X-Recipient: archive-cygwin AT delorie DOT com X-SWARE-Spam-Status: No, hits=-0.7 required=5.0 tests=AWL,BAYES_00,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org From: bob 295 To: cygwin AT cygwin DOT com Subject: needed feature in Cygwin fifos Date: Tue, 26 Apr 2011 13:34:16 -0400 User-Agent: KMail/1.8.3 MIME-Version: 1.0 Content-Disposition: inline Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Message-Id: <201104261334.17982.icanprogram@295.ca> Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Mail-Followup-To: cygwin AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com I recognize that Cygwin fifos are "buggy and not suitable for anything but simplest of applications", however in the spirit of seeing if things can be improved here is some more test code which illustrates one of the "bugs". It seems that on Linux if you open a fifo for RDWR it will "trick" the system into supressing the EOF when a writer closes the other end of the fifo. On the Cygwin system this EOF get generated regardless. The Linux behavior is a desired feature for many fifo applications, including the one I'm trying to port to Cygwin, because many writers to a single fifo is a common configuration. These writers can come and go (ie. close the fifo) at any time. Generating an EOF in these conditions each time a writer closes its file descriptor is not logical. It would appear that the Cygwin fifo gets knocked out of commission the first time an EOF gets generated. ie. the first time a writer closes the other end of the pipe. This strikes me as a bug rather than a feature. ========== begin sender code ========= #include #include #include #include #include #include #include #include int blocked_read(int, char *, int); int main(int argc, char *argv[]) { char command[80]; char fifoname[80]; int fd=-1; int rfd; int i; int j; int *r; int bytesToGo; int numBytes; char buf[5]; char *p; int rc; printf("fifo sender starting\n"); sprintf(fifoname,"/tmp/fsender"); mkfifo(fifoname, 0666); chmod(fifoname, 0666); printf("starting receiver\n"); sprintf(command,"./receiver&"); rc=system(command); printf("receiver started\n"); sleep(2); fd=open(fifoname, O_RDWR|O_NONBLOCK); //fd=open(fifoname, O_RDONLY|O_NONBLOCK); rfd=open("/tmp/freceiver", O_WRONLY); for(j=1; j<10; j++) { printf("j=%d\n",j); write(rfd,&j,sizeof(int)); numBytes=0; memset(buf,0,4); p=buf; for(i=0; i< 10; i++) { bytesToGo=sizeof(int) - numBytes; printf("bytesToGo=%d numBytes=%d\n",bytesToGo,numBytes); if(bytesToGo <= 0) break; rc=blocked_read(fd,p,bytesToGo); printf("sender rc[%d]=%d\n",i,rc); if(rc == 0) { printf("got eof\n"); // close(fd); // fd=open(fifoname, O_RDONLY); } else if(rc == -1) { printf("%s\n",strerror(errno)); } else { numBytes+=rc; p+=rc; } } printf("buf: 0x%X-%X-%X-%X\n",buf[0],buf[1],buf[2],buf[3]); r=(int *)buf; printf("reply[%d]=%d\n",j,*r); } sleep(1); unlink(fifoname); unlink("/tmp/freceiver"); exit(0); } int blocked_read(int fd, char *buff, int size) { int rc; fd_set inset; FD_ZERO(&inset); FD_SET(fd, &inset); printf("send: before select\n"); select(fd+1, &inset, NULL, NULL, NULL); printf("send: before read\n"); rc=read(fd,buff,size); printf("send: read rc=%d\n",rc); return(rc); } ========== end sender code ========== ========== begin receiver code ========= #include #include #include #include #include #include #include #include int blocked_read(int, char *, int); int main(int argc, char *argv[]) { char command[80]; char fifoname[80]; int fd; int rfd; int dummy; int i; int j; int k; int *r; int bytesToGo; int numBytes; char buf[4]; char *p; int rc; printf("fifo receiver starting\n"); sprintf(fifoname,"/tmp/freceiver"); mkfifo(fifoname, 0666); chmod(fifoname, 0666); fd=open(fifoname, O_RDWR | O_NONBLOCK); //fd=open(fifoname, O_RDONLY | O_NONBLOCK); for(k=0; k<10; k++) { numBytes=0; p=buf; for(i=0; i< 10; i++) { bytesToGo=sizeof(int) - numBytes; if(bytesToGo <= 0) break; // rc=read(fd,p,bytesToGo); rc=blocked_read(fd,p,bytesToGo); printf("recv rc[%d]=%d\n",i,rc); if(rc == 0) { printf("recv eof\n"); } else if(rc == -1) { printf("%s\n",strerror(errno)); } else { numBytes+=rc; p+=rc; } } r=(int *)buf; j=*r; printf("received[%d]=%d\n",k,j); j++; sleep(1); rfd=open("/tmp/fsender", O_WRONLY); write(rfd,&j,sizeof(int)); close(rfd); } unlink(fifoname); exit(0); } int blocked_read(int fd, char *buff, int size) { int rc; fd_set inset; FD_ZERO(&inset); FD_SET(fd, &inset); printf("recv: before select\n"); select(fd+1, &inset, NULL, NULL, NULL); printf("recv: before read\n"); rc=read(fd,buff,size); printf("recv: read rc=%d\n",rc); return(rc); } ========== end receiver code ========== To run this test compile both sender.c and receiver.c and then run as ./sender On my Linux system this is the result: ========== begin Linux result ============ fifo sender starting starting receiver fifo receiver starting recv: before select receiver started j=1 bytesToGo=4 numBytes=0 send: before select recv: before read recv: read rc=4 recv rc[0]=4 received[0]=1 recv: before select send: before read send: read rc=4 sender rc[0]=4 bytesToGo=0 numBytes=4 buf: 0x2-0-0-0 reply[1]=2 j=2 bytesToGo=4 numBytes=0 send: before select recv: before read recv: read rc=4 recv rc[0]=4 received[1]=2 recv: before select send: before read send: read rc=4 sender rc[0]=4 bytesToGo=0 numBytes=4 buf: 0x3-0-0-0 reply[2]=3 j=3 bytesToGo=4 numBytes=0 send: before select recv: before read recv: read rc=4 recv rc[0]=4 received[2]=3 recv: before select send: before read send: read rc=4 sender rc[0]=4 bytesToGo=0 numBytes=4 buf: 0x4-0-0-0 reply[3]=4 j=4 bytesToGo=4 numBytes=0 send: before select recv: before read recv: read rc=4 recv rc[0]=4 received[3]=4 recv: before select send: before read send: read rc=4 sender rc[0]=4 bytesToGo=0 numBytes=4 buf: 0x5-0-0-0 reply[4]=5 j=5 bytesToGo=4 numBytes=0 send: before select recv: before read recv: read rc=4 recv rc[0]=4 received[4]=5 recv: before select send: before read send: read rc=4 sender rc[0]=4 bytesToGo=0 numBytes=4 buf: 0x6-0-0-0 reply[5]=6 j=6 bytesToGo=4 numBytes=0 send: before select recv: before read recv: read rc=4 recv rc[0]=4 received[5]=6 recv: before select send: before read send: read rc=4 sender rc[0]=4 bytesToGo=0 numBytes=4 buf: 0x7-0-0-0 reply[6]=7 j=7 bytesToGo=4 numBytes=0 send: before select recv: before read recv: read rc=4 recv rc[0]=4 received[6]=7 recv: before select send: before read send: read rc=4 sender rc[0]=4 bytesToGo=0 numBytes=4 buf: 0x8-0-0-0 reply[7]=8 j=8 bytesToGo=4 numBytes=0 send: before select recv: before read recv: read rc=4 recv rc[0]=4 received[7]=8 recv: before select send: before read send: read rc=4 sender rc[0]=4 bytesToGo=0 numBytes=4 buf: 0x9-0-0-0 reply[8]=9 j=9 bytesToGo=4 numBytes=0 send: before select recv: before read recv: read rc=4 recv rc[0]=4 received[8]=9 recv: before select send: before read send: read rc=4 sender rc[0]=4 bytesToGo=0 numBytes=4 buf: 0xA-0-0-0 reply[9]=10 ========== end Linux result ============= On Cygwin the same code gives: ========== begin Cygwin result ============ fifo sender starting starting receiver receiver started fifo receiver starting recv: before select j=1 bytesToGo=4 numBytes=0 recv: before read send: before select recv: read rc=4 recv rc[0]=4 received[0]=1 recv: before select send: before read send: read rc=4 sender rc[0]=4 bytesToGo=0 numBytes=4 buf: 0x2-0-0-0 reply[1]=2 j=2 bytesToGo=4 numBytes=0 recv: before read send: before select send: before read send: read rc=0recv rc[0]=4 received[1]=20 got eof bytesToGo=0 numBytes=4 send: before select ========== end Cygwin result ============= Other than the differences in sequencing of the printf's due to timing differences between the two environments, the most obvious deviations between the Cygwin run and the Linux run are: a) Cygwin run generates an EOF on the sender's fifo presumably because the receiver (the fifo writer) closes this fifo after writing a single integer response b) the receiver gets a 20 instead of a 2 on second write sender -> receiver c) the select call on the fifo hangs after the EOF is received Interestingly on Linux if you switch the RDWR open for a RDONLY open in the sender code, you generate the EOF but unlike Cygwin the select doesn't block and the EOF loops endlessly. The only way you get the "desired" behavior on the Linux is to open the fifo RDWR. Are there any plans in the Cygwin developer community to address this fifo issue in coming releases? A quick Google reveals that similar fifo issues have persisted in Cygwin for at least a couple of years. Thanks in advance for your responses. bob -- Problem reports: http://cygwin.com/problems.html FAQ: http://cygwin.com/faq/ Documentation: http://cygwin.com/docs.html Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple