public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
* FIFO issues
@ 2022-09-18 21:45 Enrico Forestieri
  2022-09-19 19:15 ` Ken Brown
  0 siblings, 1 reply; 13+ messages in thread
From: Enrico Forestieri @ 2022-09-18 21:45 UTC (permalink / raw)
  To: cygwin

[-- Attachment #1: Type: text/plain, Size: 1469 bytes --]

Hi,

I think I am experiencing a problem with fifos on cygwin. The attached
C source (fifocomm.c) creates two pipes (/tmp/pipe.{in,out}), expecting
to receive inputs from /tmp/pipe.in and replying to /tmp/pipe.out.

Compiling this source on linux and launching it produces on the terminal

1) Opening pipes

and then the program waits for someone to write to /tmp/pipe.in.
Opening another terminal and launching the fifotest.sh script (also
attached) produces on the first terminal

1) Closing pipes
2) Opening pipes

and the program continues waiting for another input, while the other
terminal shows "You sent: foo"

Instead, on cygwin, after launching the program one gets:

1) Opening pipes
1) Closing pipes
2) Opening pipes
2) Closing pipes
3) Opening pipes
3) Closing pipes
4) Opening pipes
....
....

meaning that the pipes are continually closed and reopened even if
nobody is writing to /tmp/pipe.in.

Seemingly, the problem is the return value of read() on line 55.
As O_NONBLOCK is set, until no data is available for reading,
read() shouldn't block but should return -1 and set errno to EAGAIN.
After a client that opened the pipe for writing, closes it
(and no other client is using the pipe), read() should return 0 and
only at this point the pipes have to be closed and reopened.

However, on cygwin, read() returns 0 also when nobody is writing to the
input pipe causing the above ping pong. As already said, it works as it
should on linux.

-- 
Enrico

[-- Attachment #2: fifocomm.c --]
[-- Type: text/plain, Size: 3502 bytes --]

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define FIFO_IN  "/tmp/pipe.in"
#define FIFO_OUT "/tmp/pipe.out"

#define FALSE 0
#define TRUE  1

typedef int bool;

void openpipes(void);
void closepipes(void);
int startpipe(char *name, bool inputpipe);
void endpipe(char *name, int fd);

int infd;
int outfd;
int count = 0;

int main(void)
{
    int nsel;
    bool done = FALSE;
    char const *msg = "You sent: ";
    int mlen = strlen(msg);
    fd_set readfds;
    FD_ZERO(&readfds);

    openpipes();

    do {
	FD_SET(infd, &readfds);
	do {
	    nsel = select(infd + 1, &readfds, 0, 0, 0);
	} while (nsel == -1 && (errno == EINTR || errno == EAGAIN));

	if (nsel == -1) {
	    perror("select");
	    exit(4);
	}

	if (FD_ISSET(infd, &readfds)) {
	    char buf[100] = "You sent: ";
	    int status;
	    int count = 0;
	    strcpy(buf, msg);
	    while ((status = read(infd, buf + mlen, sizeof(buf) - mlen - 1))) {
		if (status > 0) {
		    buf[mlen + status] = '\0';
		    if (write(outfd, buf, strlen(buf)) < 0) {
			if (buf[mlen + status - 1] == '\n')
			    buf[mlen + status - 1] = '\0';
			fprintf(stderr, "Error sending message: '%s': %s\n",
				buf, strerror(errno));
		    }
		    if (strncasecmp(buf + mlen, "quit", 4) == 0)
			done = TRUE;
		} else if (errno == EAGAIN) {
		    /* Nothing to read, continue */
		    break;
		} else {
		    /* An error occurred, bail out */
		    perror("read");
		    done = TRUE;
		    break;
		}
	    }
	    if (!done) {
		sleep(3);
		closepipes();
		openpipes();
		errno = 0;
	    }
	}
    } while (!done);

    closepipes();
    return 0;
}


void openpipes(void)
{
    fprintf(stderr, "%d) Opening pipes\n", ++count);

    infd = startpipe(FIFO_IN, TRUE);
    if (infd == -1)
	exit(1);

    outfd = startpipe(FIFO_OUT, FALSE);
    if (outfd == -1)
	exit(2);

    if (fcntl(outfd, F_SETFL, O_NONBLOCK) < 0) {
	fprintf(stderr, "Could not set flags on pipe %s: %s\n",
		FIFO_OUT, strerror(errno));
	exit(3);
    }
}


void closepipes()
{
    fprintf(stderr, "%d) Closing pipes\n", count);

    endpipe(FIFO_IN, infd);
    endpipe(FIFO_OUT, outfd);
}


int startpipe(char *name, bool inputpipe)
{
    static bool stalepipe = FALSE;
    int fd;

    if (access(name, F_OK) == 0) {
	if (inputpipe) {
	    /* Let's see whether we have a stale pipe */
	    fd = open(name, O_WRONLY | O_NONBLOCK);
	    if (fd >= 0) {
		/* pipe exists and is used by another process */
		close(fd);
	    } else if (errno == ENXIO) {
		/* No process is reading from the other end */
		stalepipe = TRUE;
		endpipe(name, -1);
	    }
	} else if (stalepipe) {
	    endpipe(name, -1);
	    stalepipe = FALSE;
	}
	if (access(name, F_OK) == 0) {
	    fprintf(stderr, "Pipe %s already exists and is in use.\n", name);
	    return -1;
	}
    }

    if (mkfifo(name, 0600) < 0) {
	fprintf(stderr, "Could not create pipe %s: %s\n",
		name, strerror(errno));
	return -1;
    }

    fd = open(name, inputpipe ? (O_RDONLY | O_NONBLOCK) : O_RDWR);

    if (fd < 0) {
	fprintf(stderr, "Could not open pipe %s: %s\n",
		name, strerror(errno));
	endpipe(name, -1);
	return -1;
    }

    return fd;
}


void endpipe(char *name, int fd)
{
    if (fd >= 0 && close(fd) < 0)
	fprintf(stderr, "Could not close pipe %s: %s\n",
		name, strerror(errno));

    if (remove(name) < 0)
	fprintf(stderr, "Could not remove pipe %s: %s\n",
		name, strerror(errno));
}

[-- Attachment #3: fifotest.sh --]
[-- Type: application/x-sh, Size: 59 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2022-09-23 15:37 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-18 21:45 FIFO issues Enrico Forestieri
2022-09-19 19:15 ` Ken Brown
2022-09-19 19:50   ` Norton Allen
2022-09-19 19:53     ` Norton Allen
2022-09-19 21:25       ` Ken Brown
2022-09-19 21:28         ` Norton Allen
2022-09-19 22:05         ` Enrico Forestieri
2022-09-19 23:54           ` Ken Brown
2022-09-20  3:51             ` [EXTERNAL] " Lavrentiev, Anton (NIH/NLM/NCBI) [C]
2022-09-20  6:54             ` Enrico Forestieri
2022-09-20 13:18               ` Ken Brown
2022-09-20 17:20                 ` Enrico Forestieri
2022-09-23 15:36                   ` Ken Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).