kern/94772: FIFOs (named pipes) + select() == broken

Oliver Fromme olli at lurza.secnetix.de
Thu Mar 23 22:10:31 UTC 2006


The following reply was made to PR kern/94772; it has been noted by GNATS.

From: Oliver Fromme <olli at lurza.secnetix.de>
To: bde at zeta.org.au (Bruce Evans)
Cc: bug-followup at freebsd.org
Subject: Re: kern/94772: FIFOs (named pipes) + select() == broken
Date: Thu, 23 Mar 2006 23:05:17 +0100 (CET)

 OK, here are new patches.  I wrote and tested them on
 RELENG_6, but they should apply to HEAD as well, AFAICT.
 
 With these patches, all of the test programs pass with
 success (no output), i.e. the select test and the poll
 test.  My own test program from the beginning of this
 PR passes without problems, too.
 
 Best regards
    Oliver
 
 
 --- ./fs/fifofs/fifo_vnops.c.orig	Tue Mar 21 09:42:32 2006
 +++ ./fs/fifofs/fifo_vnops.c	Thu Mar 23 19:57:21 2006
 @@ -231,6 +231,12 @@
  				wakeup(&fip->fi_writers);
  				sowwakeup(fip->fi_writesock);
  			}
 +			else if (ap->a_mode & O_NONBLOCK) {
 +				SOCKBUF_LOCK(&fip->fi_readsock->so_rcv);
 +				fip->fi_readsock->so_rcv.sb_state |=
 +				    SBS_EOFNOHUP;
 +				SOCKBUF_UNLOCK(&fip->fi_readsock->so_rcv);
 +			}
  		}
  	}
  	if (ap->a_mode & FWRITE) {
 @@ -241,7 +247,8 @@
  		fip->fi_writers++;
  		if (fip->fi_writers == 1) {
  			SOCKBUF_LOCK(&fip->fi_readsock->so_rcv);
 -			fip->fi_readsock->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
 +			fip->fi_readsock->so_rcv.sb_state &=
 +			    ~(SBS_CANTRCVMORE | SBS_EOFNOHUP);
  			SOCKBUF_UNLOCK(&fip->fi_readsock->so_rcv);
  			if (fip->fi_readers > 0) {
  				wakeup(&fip->fi_readers);
 @@ -661,37 +668,23 @@
  	int levents, revents = 0;
  
  	fip = fp->f_data;
 -	levents = events &
 -	    (POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM | POLLRDBAND);
 +	levents = events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND);
  	if ((fp->f_flag & FREAD) && levents) {
 -		/*
 -		 * If POLLIN or POLLRDNORM is requested and POLLINIGNEOF is
 -		 * not, then convert the first two to the last one.  This
 -		 * tells the socket poll function to ignore EOF so that we
 -		 * block if there is no writer (and no data).  Callers can
 -		 * set POLLINIGNEOF to get non-blocking behavior.
 -		 */
 -		if (levents & (POLLIN | POLLRDNORM) &&
 -		    !(levents & POLLINIGNEOF)) {
 -			levents &= ~(POLLIN | POLLRDNORM);
 -			levents |= POLLINIGNEOF;
 -		}
 -
  		filetmp.f_data = fip->fi_readsock;
  		filetmp.f_cred = cred;
  		revents |= soo_poll(&filetmp, levents, cred, td);
 -
 -		/* Reverse the above conversion. */
 -		if ((revents & POLLINIGNEOF) && !(events & POLLINIGNEOF)) {
 -			revents |= (events & (POLLIN | POLLRDNORM));
 -			revents &= ~POLLINIGNEOF;
 -		}
  	}
  	levents = events & (POLLOUT | POLLWRNORM | POLLWRBAND);
  	if ((fp->f_flag & FWRITE) && levents) {
  		filetmp.f_data = fip->fi_writesock;
  		filetmp.f_cred = cred;
  		revents |= soo_poll(&filetmp, levents, cred, td);
 +	}
 +	if (revents & POLLHUP) {
 +		SOCKBUF_LOCK(&fip->fi_readsock->so_rcv);
 +		if (fip->fi_readsock->so_rcv.sb_state & SBS_EOFNOHUP)
 +			revents = (revents & ~POLLHUP) | POLLHUPIGNEOF;
 +		SOCKBUF_UNLOCK(&fip->fi_readsock->so_rcv);
  	}
  	return (revents);
  }
 --- ./kern/uipc_socket.c.orig	Wed Dec 28 19:05:13 2005
 +++ ./kern/uipc_socket.c	Thu Mar 23 22:50:33 2006
 @@ -2033,16 +2033,15 @@
  	SOCKBUF_LOCK(&so->so_snd);
  	SOCKBUF_LOCK(&so->so_rcv);
  	if (events & (POLLIN | POLLRDNORM))
 -		if (soreadable(so))
 -			revents |= events & (POLLIN | POLLRDNORM);
 -
 -	if (events & POLLINIGNEOF)
  		if (so->so_rcv.sb_cc >= so->so_rcv.sb_lowat ||
  		    !TAILQ_EMPTY(&so->so_comp) || so->so_error)
 -			revents |= POLLINIGNEOF;
 +			revents |= events & (POLLIN | POLLRDNORM);
  
 -	if (events & (POLLOUT | POLLWRNORM))
 -		if (sowriteable(so))
 +	if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) ||
 +	    (so->so_snd.sb_state & SBS_CANTSENDMORE))
 +		revents |= POLLHUP;
 +	else
 +		if (events & (POLLOUT | POLLWRNORM) && sowriteable(so))
  			revents |= events & (POLLOUT | POLLWRNORM);
  
  	if (events & (POLLPRI | POLLRDBAND))
 @@ -2050,9 +2049,7 @@
  			revents |= events & (POLLPRI | POLLRDBAND);
  
  	if (revents == 0) {
 -		if (events &
 -		    (POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM |
 -		     POLLRDBAND)) {
 +		if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
  			selrecord(td, &so->so_rcv.sb_sel);
  			so->so_rcv.sb_flags |= SB_SEL;
  		}
 --- ./kern/sys_generic.c.orig	Thu Jul  7 20:17:55 2005
 +++ ./kern/sys_generic.c	Thu Mar 23 19:58:03 2006
 @@ -1027,7 +1027,7 @@
  				 * POLLERR if appropriate.
  				 */
  				fds->revents = fo_poll(fp, fds->events,
 -				    td->td_ucred, td);
 +				    td->td_ucred, td) & ~POLLHUPIGNEOF;
  				if (fds->revents != 0)
  					n++;
  			}
 --- ./sys/poll.h.orig	Wed Jul 10 06:47:25 2002
 +++ ./sys/poll.h	Thu Mar 23 19:56:58 2006
 @@ -66,9 +66,8 @@
  #define	POLLRDBAND	0x0080		/* OOB/Urgent readable data */
  #define	POLLWRBAND	0x0100		/* OOB/Urgent data can be written */
  
 -#if __BSD_VISIBLE
 -/* General FreeBSD extension (currently only supported for sockets): */
 -#define	POLLINIGNEOF	0x2000		/* like POLLIN, except ignore EOF */
 +#ifdef _KERNEL
 +#define	POLLHUPIGNEOF	0x2000
  #endif
  
  /*
 --- ./sys/socketvar.h.orig	Sat Jul  9 14:24:40 2005
 +++ ./sys/socketvar.h	Thu Mar 23 19:20:25 2006
 @@ -215,6 +215,7 @@
  #define	SBS_CANTSENDMORE	0x0010	/* can't send more data to peer */
  #define	SBS_CANTRCVMORE		0x0020	/* can't receive more data from peer */
  #define	SBS_RCVATMARK		0x0040	/* at mark on input */
 +#define	SBS_EOFNOHUP		0x0080	/* no initial writer */
  
  /*
   * Socket state bits stored in so_qstate.
 
 
 
 -- 
 Oliver Fromme,  secnetix GmbH & Co. KG, Marktplatz 29, 85567 Grafing
 Dienstleistungen mit Schwerpunkt FreeBSD: http://www.secnetix.de/bsd
 Any opinions expressed in this message may be personal to the author
 and may not necessarily reflect the opinions of secnetix in any way.


More information about the freebsd-bugs mailing list