Discussion:
named pipe (fifo) question
bob 295
2011-04-19 15:01:55 UTC
Permalink
I'm porting a library from Linux to Cygwin and I've encountered a problem with
the behavior of named pipes (fifo's).

In my sequence a pair of fifos are opened by each end of the conversation.
One is opened as WRONLY, the other as RDWR. Some documentation seems to
frown on RDWR pipes. We found that this allows us to trap certain errors
when processes on other ends of the pipe vanish.

The message exchange sequence is then:

For the sender
i) open the WRONLY pipe to receiver
ii) write an integer on the WRONLY pipe
iii) drop into a read on the RDWR pipe (which blocks in Linux)

For the receiver
i) drop into read on the RDWR pipe (which blocks in Linux)
ii) process the message
iii) open the WRONLY end of pipe for response
iv) write an integer onto the WRONLY pipe back to sender
v) close the WRONLY end of pipe

The sender leaves the WRONLY pipe open in case another message will be sent.
It only closes the file descriptor upon process exit. The receiver opens,
writes and closes its WRONLY end on each pass. In Linux this sequence works
just fine and has been working in all versions for at least 10 years now.

However, on Cygwin it would appear that after the first time the receiver
closes the WRONLY end of the sender's pipe, the sender's next read comes
back with a 0 (eof) repeatedly without ever blocking.

Is this the intended POSIX behavior? Is the problem the RDWR open?

Thanks in advance for your help.

bob
Christopher Faylor
2011-04-19 15:23:21 UTC
Permalink
Post by bob 295
I'm porting a library from Linux to Cygwin and I've encountered a problem with
the behavior of named pipes (fifo's).
...
Is this the intended POSIX behavior? Is the problem the RDWR open?
The problem is that Cygwin's implementation of fifos is very buggy. I wouldn't
recommend using them for anything but the simplest of applications.

cgf
bob 295
2011-04-20 13:48:09 UTC
Permalink
(I'm on the list in digest mode so things can't thread easily)
Post by Christopher Faylor
Post by bob 295
I'm porting a library from Linux to Cygwin and I've encountered a problem
with
Post by Christopher Faylor
Post by bob 295
the behavior of named pipes (fifo's).
...
Is this the intended POSIX behavior? Is the problem the RDWR open?
The problem is that Cygwin's implementation of fifos is very buggy. I
wouldn't
Post by Christopher Faylor
recommend using them for anything but the simplest of applications.
cgf
Here is some sample code I've been playing with which produces clean results
on Linux but totally wonky results on Cygwin.

======= begin sender.c code ==========
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>

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);

rfd=open("/tmp/freceiver", O_WRONLY);

for(j=1; j<10; j++)
{
printf("j=%d\n",j);

write(rfd,&j,sizeof(int));

if(fd == -1)
{
// fd=open(fifoname, O_RDONLY);
fd=open(fifoname, O_RDWR);
}

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=read(fd,p,bytesToGo);
printf("rc[%d]=%d\n",i,rc);
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);
}

remove(fifoname);
remove("/tmp/freceiver");

exit(0);
}

======= end sender.c code ===========

======= begin receiver.c code ==========
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>

int main(int argc, char *argv[])
{
char command[80];
char fifoname[80];
int fd;
int rfd;
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);
//fd=open(fifoname, O_RDONLY);

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);
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);
}

remove(fifoname);

exit(0);
}

======= end receiver.c code ===========

Compile both sender and receiver and run as

./sender

Here are the results:
========== begin results Linux =========
fifo sender starting
starting receiver
receiver started
j=1
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0x2-0-0-0
reply[1]=2
j=2
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0x3-0-0-0
reply[2]=3
j=3
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0x4-0-0-0
reply[3]=4
j=4
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0x5-0-0-0
reply[4]=5
j=5
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0x6-0-0-0
reply[5]=6
j=6
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0x7-0-0-0
reply[6]=7
j=7
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0x8-0-0-0
reply[7]=8
j=8
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0x9-0-0-0
reply[8]=9
j=9
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0xA-0-0-0
reply[9]=10

========== end results Linux ==========

========== begin results Cygwin ========
fifo sender starting
starting receiver
receiver started
j=1
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0x2-0-0-0
reply[1]=2
j=2
bytesToGo=4 numBytes=0
rc[0]=0
bytesToGo=4 numBytes=0
rc[1]=4
bytesToGo=0 numBytes=4
buf: 0x0-0-0-0
reply[2]=0
j=3
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0x0-0-0-0
reply[3]=0
j=4
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0x0-0-0-0
reply[4]=0
j=5
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0x0-0-0-0
reply[5]=0
j=6
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0x0-0-0-0
reply[6]=0
j=7
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0x0-0-0-0
reply[7]=0
j=8
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0x0-0-0-0
reply[8]=0
j=9
bytesToGo=4 numBytes=0
rc[0]=4
bytesToGo=0 numBytes=4
buf: 0x0-0-0-0
reply[9]=0
fifo receiver starting
received[0]=1
received[1]=2
received[2]=3
received[3]=4
received[4]=5
received[5]=6
received[6]=7
received[7]=8
received[8]=9
received[9]=9

========== end results Cygwin =========

In this run the Cygwin fifo /tmp/sender appears to get stuffed with 4 bytes of
all zeros ... or at least that is what the sender read thinks it sees each
time it loops back to that read.

Thanks in advance for any help with this.

bob
Christopher Faylor
2011-04-20 15:23:07 UTC
Permalink
Post by bob 295
(I'm on the list in digest mode so things can't thread easily)
Post by Christopher Faylor
Post by bob 295
I'm porting a library from Linux to Cygwin and I've encountered a problem
with
Post by Christopher Faylor
Post by bob 295
the behavior of named pipes (fifo's).
...
Is this the intended POSIX behavior? Is the problem the RDWR open?
The problem is that Cygwin's implementation of fifos is very buggy. I
wouldn't
Post by Christopher Faylor
recommend using them for anything but the simplest of applications.
Here is some sample code I've been playing with which produces clean results
on Linux but totally wonky results on Cygwin.
The problem is that Cygwin's implementation of fifos is very buggy. I
wouldn't recommend using fifos for anything but the simplest of
applications.

cgf

Continue reading on narkive:
Loading...