Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 30 Sep 2007 22:55:24 +0200 (CEST)
From:      Bo Lindbergh <blgl@stacken.kth.se>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   kern/116770: Unfortunate fifo/O_NONBLOCK/kevent interaction
Message-ID:  <200709302055.l8UKtOUQ071624@igloo.stacken.kth.se>
Resent-Message-ID: <200709302120.l8ULK38f009694@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         116770
>Category:       kern
>Synopsis:       Unfortunate fifo/O_NONBLOCK/kevent interaction
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun Sep 30 21:20:03 GMT 2007
>Closed-Date:
>Last-Modified:
>Originator:     Bo Lindbergh <blgl@stacken.kth.se>
>Release:        FreeBSD 5.4-RELEASE-p6 i386
>Organization:
>Environment:
System: FreeBSD igloo.stacken.kth.se 5.4-RELEASE-p6 FreeBSD 5.4-RELEASE-p6 #1: Thu Jul 28 19:42:42 CEST 2005 root@igloo.stacken.kth.se:/usr/obj/usr/src/sys/IGLOO i386


>Description:
When a fifo with no writers is opened nonblockingly for reading and
the resulting file descriptor is added to a kqueue, kevent will
immediately report an EOF condition.  This is less than useful.

The useful behaviour would be for kevent not to report EOF until at
least one writer has come and gone.  This matches how similar
mechanisms in other operating systems work (e.g. epoll in Linux,
/dev/poll in Solaris).

>How-To-Repeat:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/event.h>
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>

int main(void)
{
    int rfd,wfd,qfd,n;
    static struct timespec zero;
    struct kevent kev;
    char fifopath[64];

    sprintf(fifopath,"/tmp/less-than-useful.%ld",(long)getpid());
    if (mkfifo(fifopath,S_IRUSR|S_IWUSR)==-1) {
        perror("mkfifo");
        return 1;
    }
    rfd=open(fifopath,O_RDONLY|O_NONBLOCK);
    if (rfd==-1) {
        perror("open 1");
        goto cleanup;
    }
    qfd=kqueue();
    if (qfd==-1) {
        perror("kqueue");
        goto cleanup;
    }
    EV_SET(&kev,rfd,EVFILT_READ,EV_ADD,0,0,NULL);
    n=kevent(qfd,&kev,1,NULL,0,&zero);
    if (n==-1) {
        perror("kevent 1");
        goto cleanup;
    }
    n=kevent(qfd,NULL,0,&kev,1,&zero);
    if (n==-1) {
        perror("kevent 2");
        goto cleanup;
    }
    if (n==1 && (kev.flags & EV_EOF)) {
        fputs("Immediate EOF (not useful)\n",stderr);
    }
    wfd=open(fifopath,O_WRONLY);
    if (wfd==-1) {
        perror("open 2");
        goto cleanup;
    }
    n=kevent(qfd,NULL,0,&kev,1,&zero);
    if (n==-1) {
        perror("kevent 3");
        goto cleanup;
    }
    if (n==1 && (kev.flags & EV_EOF)) {
        fputs("EOF while there's still a writer (BUG!)\n",stderr);
    }
    close(wfd);
    n=kevent(qfd,NULL,0,&kev,1,&zero);
    if (n==-1) {
        perror("kevent 4");
        goto cleanup;
    }
    if (n==1 && (kev.flags & EV_EOF)) {
        fputs("EOF after the last writer went away (useful)\n",stderr);
    }
    close(qfd);
    close(rfd);
    unlink(fifopath);
    return 0;

 cleanup:
    unlink(fifopath);
    return 1;
}

>Fix:
Don't CANTRCVMORE the socketpair immediately after creating it.  Add
code to fifo_read_f to avoid calling soreceive blockingly when there
are zero writers.

Or just add a fi_seen_at_least_one_writer flag to struct fifoinfo...

>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200709302055.l8UKtOUQ071624>