From ino-e31cbe40@spotteswoode.dnsalias.org  Fri Jan 18 01:42:47 2002
Return-Path: <ino-e31cbe40@spotteswoode.dnsalias.org>
Received: from mailout01.sul.t-online.com (mailout01.sul.t-online.com [194.25.134.80])
	by hub.freebsd.org (Postfix) with ESMTP id 1C05937B402
	for <FreeBSD-gnats-submit@freebsd.org>; Fri, 18 Jan 2002 01:42:46 -0800 (PST)
Received: from fwd06.sul.t-online.de 
	by mailout01.sul.t-online.com with smtp 
	id 16RVXp-0003qq-03; Fri, 18 Jan 2002 10:42:45 +0100
Received: from spotteswoode.dnsalias.org (520082050842-0001@[217.80.22.15]) by fmrl06.sul.t-online.com
	with smtp id 16RVXa-15RejYC; Fri, 18 Jan 2002 10:42:30 +0100
Received: (qmail 1721 invoked by uid 0); 18 Jan 2002 09:42:30 -0000
Message-Id: <20020118094230.GA968@spotteswoode.dnsalias.org>
Date: Fri, 18 Jan 2002 10:42:30 +0100
From: clemensF <ino-e31cbe40@spotteswoode.dnsalias.org>
To: FreeBSD-gnats-submit@freebsd.org
Subject: poll(2) on fifos is broken

>Number:         34020
>Category:       kern
>Synopsis:       programs fail that poll(2) on fifos
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    maxim
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Jan 18 01:50:00 PST 2002
>Closed-Date:    Thu Dec 02 14:08:03 GMT 2004
>Last-Modified:  Thu Dec 02 14:08:03 GMT 2004
>Originator:     Tip Chap
>Release:        FreeBSD 4.3-RELEASE i386
>Organization:
no
>Environment:
>Description:

the programs below are meant to communicate a state change to multiple
processes.  the original idea is from paul jarc.  several variants of the
waiters were tested (selecting, blocking, polling).

what's needed is this:  readers on a fifo are supposed to wait until some
writer opens it.  this could be a portable, light-weight way of event-
notification, where an unspecified number of readers can be realiably
signalled, not loosing any signals even when they are not yet ready to
receive them.

it works in linux and openbsd.  POSIX doesn't specify the situation (nobody
does).  the only alternative would be heavy machinery using SYSV-IPC or
unix- signals, that would also put unbearable load on the system.

>How-To-Repeat:

0 p1 root #./pipe-wait pipe & ./pipe-wait pipe & ./pipe-wait pipe &
[1] 16768
[2] 16769
[3] 16770
[1]  16768 Running                 ./pipe-wait pipe &
[2]- 16769 Running                 ./pipe-wait pipe &
[3]+ 16770 Running                 ./pipe-wait pipe &

0 p1 root #
[1]  16768 Done                    ./pipe-wait pipe
[2]- 16769 Done                    ./pipe-wait pipe
[3]+ 16770 Done                    ./pipe-wait pipe

this behaviour is wrong, no matter which of the pipe-wait* programs is
used.  what i want to achieve is having any number of poll's wait until
pipe-signal is invoked.  this doesn't happen, as the waiters exit
immediately with no error, as if data was immediately available, which is
obviously wrong.

0 p1 root #ls -F pipe*
pipe|              pipe-wait*         pipe-wait-poll*
pipe-signal*       pipe-wait-block*   pipe-wait-poll.c*
pipe-signal.c*     pipe-wait-block.c* pipe-wait.c*

0 p1 root #ll pipe
29165 prw-r--r--  1 root  wheel  - 0 13 Jan 18:32 pipe|

0 p1 root #./pipe-signal

1 p1 root #./pipe-signal pipe

>Fix:

the kernel for version 4.3 needs fixing.  i am not sure if this issue has
been resolved in -current.

clemens fischer

-------------------- 8< -----------------------

/* pipe-wait.c */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char* argv[]) {
  int fd;
  fd_set set, empty;
  if (argc<2) return 1;
  fd=open(argv[1], O_RDONLY|O_NDELAY);
  if (fd<0) return 2;
  FD_ZERO(&empty);
  FD_ZERO(&set);
  FD_SET(fd, &set);
  if (select(fd+1, &set, &empty, &empty, NULL)!=1) return 3;
  return 0;
}

-------------------- 8< -----------------------
/* pipe-wait-block.c */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char* argv[]) {
  int fd;
  fd_set set, empty;
  if (argc<2) return 1;
  fd=open(argv[1], O_RDONLY|O_NDELAY);
  if (fd<0) return 2;
  if (fcntl(fd, F_SETFL, O_RDONLY)!=0) return 3;
  FD_ZERO(&empty);
  FD_ZERO(&set);
  FD_SET(fd, &set);
  if (select(fd+1, &set, &empty, &empty, NULL)!=1) return 4;
  return 0;
}

-------------------- 8< -----------------------
/* pipe-wait-poll.c */
#include <sys/types.h>
#include <poll.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char* argv[]) {
  int fd;
  struct pollfd x;
  if (argc<2) return 1;
  fd=open(argv[1], O_RDONLY|O_NDELAY);
  if (fd<0) return 2;
  if (fcntl(fd, F_SETFL, O_RDONLY)!=0) return 3;
  x.fd=fd;
  x.events=POLLIN;
  if (poll(&x, 1, -1)!=1) return 4;
  if (x.revents&POLLIN==0) return 5;
  return 0;
}

-------------------- 8< -----------------------
/* pipe-signal.c */
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

int main(int argc, char* argv[]) {
  if (argc<2) return 1;
  if (open(argv[1], O_WRONLY|O_NDELAY)<0 && errno!=ENXIO) return 2;
  return 0;
}
>Release-Note:
>Audit-Trail:

From: Maxim Konovalov <maxim@macomnet.ru>
To: clemensF <ino-e31cbe40@spotteswoode.dnsalias.org>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: kern/34020: poll(2) on fifos is broken
Date: Mon, 21 Jan 2002 19:44:26 +0300 (MSK)

 Alfred has fixed in -current:
 
 http://www.FreeBSD.org/cgi/getmsg.cgi?fetch=395052+397069+/usr/local/www/db/text/2002/cvs-all/20020120.cvs-all
 
 Here is the patch for -stable:
 
 --- poll.h.orig	Mon Jan 21 19:00:01 2002
 +++ poll.h	Mon Jan 21 19:00:46 2002
 @@ -70,6 +70,8 @@
  #define	POLLATTRIB	0x0400		/* file attributes may have changed */
  #define	POLLNLINK	0x0800		/* (un)link/rename may have happened */
  #define	POLLWRITE	0x1000		/* file's contents may have changed */
 +/* General FreeBSD extensions (currently only supported for sockets): */
 +#define	POLLINIGNEOF	0x2000		/* POLLIN, except ignore EOF */
 
  /*
   * These events are set if they occur regardless of whether they were
 --- fifo_vnops.c.orig	Mon Jan 21 18:40:56 2002
 +++ fifo_vnops.c	Mon Jan 21 18:46:47 2002
 @@ -446,18 +446,41 @@
  	} */ *ap;
  {
  	struct file filetmp;
 -	int revents = 0;
 +	int events, revents = 0;
 
 -	if (ap->a_events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
 +	events = ap->a_events &
 +	    (POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM | POLLRDBAND);
 +	if (events) {
 +		/*
 +		 * Tell socket poll to ignore EOF so that we block if
 +		 * there is no writer (and no data).
 +		 */
 +		if (events & (POLLIN | POLLRDNORM)) {
 +			events &= ~(POLLIN | POLLRDNORM);
 +			events |= POLLINIGNEOF;
 +		}
  		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
  		if (filetmp.f_data)
 -			revents |= soo_poll(&filetmp, ap->a_events, ap->a_cred,
 +			revents |= soo_poll(&filetmp, events, ap->a_cred,
  			    ap->a_p);
 +
 +		/*
 +		 * If POLLIN or POLLRDNORM was requested and POLLINIGNEOF was
 +		 * not then convert POLLINIGNEOF back to POLLIN.
 +		 */
 +		events = ap->a_events & (POLLIN | POLLRDNORM | POLLINIGNEOF);
 +		if ((events & (POLLIN | POLLRDNORM)) &&
 +		    !(events & POLLINIGNEOF) &&
 +		    (revents & POLLINIGNEOF)) {
 +			revents &= ~POLLINIGNEOF;
 +			revents |= (events & (POLLIN | POLLRDNORM));
 +		}
  	}
 -	if (ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
 +	events = ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND);
 +	if (events) {
  		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
  		if (filetmp.f_data)
 -			revents |= soo_poll(&filetmp, ap->a_events, ap->a_cred,
 +			revents |= soo_poll(&filetmp, events, ap->a_cred,
  			    ap->a_p);
  	}
  	return (revents);
 --- uipc_socket.c.orig	Mon Jan 21 19:21:00 2002
 +++ uipc_socket.c	Mon Jan 21 19:23:00 2002
 @@ -1510,6 +1510,11 @@
  		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;
 +
  	if (events & (POLLOUT | POLLWRNORM))
  		if (sowriteable(so))
  			revents |= events & (POLLOUT | POLLWRNORM);
 @@ -1519,7 +1524,9 @@
  			revents |= events & (POLLPRI | POLLRDBAND);
 
  	if (revents == 0) {
 -		if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
 +		if (events &
 +		    (POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM |
 +		     POLLRDBAND)) {
  			selrecord(p, &so->so_rcv.sb_sel);
  			so->so_rcv.sb_flags |= SB_SEL;
  		}
 
 -- 
 Maxim Konovalov, MAcomnet, Internet-Intranet Dept., system engineer
 phone: +7 (095) 796-9079, mailto: maxim@macomnet.ru
 

From: "clemensF" <ino-e31cbe40@spotteswoode.dnsalias.org>
To: "Maxim Konovalov" <maxim@macomnet.ru>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: kern/34020: poll(2) on fifos is broken
Date: 21 Jan 2002 18:13:14 +0100

 > Maxim Konovalov:
 
 > Alfred has fixed in -current:
 > 
 > http://www.FreeBSD.org/cgi/getmsg.cgi?fetch=395052+397069+/usr/local/www/db/text/2002/cvs-all/20020120.cvs-all
 > 
 > Here is the patch for -stable:
 
 thank you very much.  has this patch received testing?
 
 clemens fischer

From: Maxim Konovalov <maxim@macomnet.ru>
To: clemensF <ino-e31cbe40@spotteswoode.dnsalias.org>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: kern/34020: poll(2) on fifos is broken
Date: Tue, 22 Jan 2002 10:46:27 +0300 (MSK)

 >  > Maxim Konovalov:
 >
 >  > Alfred has fixed in -current:
 >  >
 >  > http://www.FreeBSD.org/cgi/getmsg.cgi?fetch=395052+397069+/usr/local/www/db/text/2002/cvs-all/20020120.cvs-all
 >  >
 >  > Here is the patch for -stable:
 >
 >  thank you very much.  has this patch received testing?
 
 Certainly it has.
 
 -- 
 Maxim Konovalov, MAcomnet, Internet-Intranet Dept., system engineer
 phone: +7 (095) 796-9079, mailto: maxim@macomnet.ru
 

From: "clemensF" <ino-e31cbe40@spotteswoode.dnsalias.org>
To: "Maxim Konovalov" <maxim@macomnet.ru>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: kern/34020: poll(2) on fifos is broken
Date: 22 Jan 2002 10:18:19 +0100

 > Maxim Konovalov:
 
 > >  > Here is the patch for -stable:
 > >
 > >  thank you very much.  has this patch received testing?
 > 
 > Certainly it has.
 
 great.  i was so anxious to apply the patches that i overlooked "the other"
 poll.h, the one in sys/sys/poll.h, so i had a patched
 /usr/include/sys/poll.h only.
 
 could you please provide more of the actual path in patch files, so this
 doesn't cause headaches in the future?
 
 clemens fischer

From: Maxim Konovalov <maxim@macomnet.ru>
To: clemensF <ino-e31cbe40@spotteswoode.dnsalias.org>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: kern/34020: poll(2) on fifos is broken
Date: Tue, 22 Jan 2002 12:42:01 +0300 (MSK)

 Here you are.
 
 Index: poll.h
 ===================================================================
 RCS file: /home/ncvs/src/sys/sys/poll.h,v
 retrieving revision 1.6.2.1
 diff -u -r1.6.2.1 poll.h
 --- poll.h	2000/08/21 12:25:58	1.6.2.1
 +++ poll.h	2002/01/22 09:37:31
 @@ -70,6 +70,8 @@
  #define	POLLATTRIB	0x0400		/* file attributes may have changed */
  #define	POLLNLINK	0x0800		/* (un)link/rename may have happened */
  #define	POLLWRITE	0x1000		/* file's contents may have changed */
 +/* General FreeBSD extensions (currently only supported for sockets): */
 +#define	POLLINIGNEOF	0x2000		/* POLLIN, except ignore EOF */
 
  /*
   * These events are set if they occur regardless of whether they were
 Index: fifo_vnops.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/fs/fifofs/fifo_vnops.c,v
 retrieving revision 1.45.2.2
 diff -u -r1.45.2.2 fifo_vnops.c
 --- fifo_vnops.c	2001/02/26 04:23:20	1.45.2.2
 +++ fifo_vnops.c	2002/01/22 09:37:42
 @@ -446,18 +446,41 @@
  	} */ *ap;
  {
  	struct file filetmp;
 -	int revents = 0;
 +	int events, revents = 0;
 
 -	if (ap->a_events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
 +	events = ap->a_events &
 +	    (POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM | POLLRDBAND);
 +	if (events) {
 +		/*
 +		 * Tell socket poll to ignore EOF so that we block if
 +		 * there is no writer (and no data).
 +		 */
 +		if (events & (POLLIN | POLLRDNORM)) {
 +			events &= ~(POLLIN | POLLRDNORM);
 +			events |= POLLINIGNEOF;
 +		}
  		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
  		if (filetmp.f_data)
 -			revents |= soo_poll(&filetmp, ap->a_events, ap->a_cred,
 +			revents |= soo_poll(&filetmp, events, ap->a_cred,
  			    ap->a_p);
 +
 +		/*
 +		 * If POLLIN or POLLRDNORM was requested and POLLINIGNEOF was
 +		 * not then convert POLLINIGNEOF back to POLLIN.
 +		 */
 +		events = ap->a_events & (POLLIN | POLLRDNORM | POLLINIGNEOF);
 +		if ((events & (POLLIN | POLLRDNORM)) &&
 +		    !(events & POLLINIGNEOF) &&
 +		    (revents & POLLINIGNEOF)) {
 +			revents &= ~POLLINIGNEOF;
 +			revents |= (events & (POLLIN | POLLRDNORM));
 +		}
  	}
 -	if (ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
 +	events = ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND);
 +	if (events) {
  		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
  		if (filetmp.f_data)
 -			revents |= soo_poll(&filetmp, ap->a_events, ap->a_cred,
 +			revents |= soo_poll(&filetmp, events, ap->a_cred,
  			    ap->a_p);
  	}
  	return (revents);
 Index: uipc_socket.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/kern/uipc_socket.c,v
 retrieving revision 1.68.2.17
 diff -u -r1.68.2.17 uipc_socket.c
 --- uipc_socket.c	2001/12/01 21:32:42	1.68.2.17
 +++ uipc_socket.c	2002/01/22 09:37:54
 @@ -1518,6 +1518,11 @@
  		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;
 +
  	if (events & (POLLOUT | POLLWRNORM))
  		if (sowriteable(so))
  			revents |= events & (POLLOUT | POLLWRNORM);
 @@ -1527,7 +1532,9 @@
  			revents |= events & (POLLPRI | POLLRDBAND);
 
  	if (revents == 0) {
 -		if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
 +		if (events &
 +		    (POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM |
 +		     POLLRDBAND)) {
  			selrecord(p, &so->so_rcv.sb_sel);
  			so->so_rcv.sb_flags |= SB_SEL;
  		}
 
 -- 
 Maxim Konovalov, MAcomnet, Internet-Intranet Dept., system engineer
 phone: +7 (095) 796-9079, mailto: maxim@macomnet.ru
 
State-Changed-From-To: open->patched 
State-Changed-By: arved 
State-Changed-When: Thu Aug 26 13:13:55 GMT 2004 
State-Changed-Why:  
Correct state: maxim pointed out that this is fixed in CURRENT. 
Maybe someone still wants to commit the patch to RELENG_4. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=34020 
Responsible-Changed-From-To: freebsd-bugs->maxim 
Responsible-Changed-By: arved 
Responsible-Changed-When: Thu Aug 26 13:26:34 GMT 2004 
Responsible-Changed-Why:  
Submitters email bounces, so the only one left, who is interested in this is  
maxim who provided the patch against RELENG_4. 
He can commit his own patches now, if he wants to. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=34020 
State-Changed-From-To: patched->closed 
State-Changed-By: maxim 
State-Changed-When: Thu Dec 2 14:06:27 GMT 2004 
State-Changed-Why:  
I do not think it is wise to bring these changes to RELENG_4 
on its current stage of the lifecycle. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=34020 
>Unformatted:
 >System: FreeBSD spotteswoode.dnsalias.org 4.3-RELEASE FreeBSD 4.3-RELEASE #13: Sun Jan 13 11:53:26 CET 2002 root@spotteswoode.dnsalias.org:/usr/src/sys/compile/n1 i386
 
 
