public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
From: Enrico Forestieri <forenr@lyx.org>
To: cygwin@cygwin.com
Subject: Re: FIFO issues
Date: Tue, 20 Sep 2022 19:20:08 +0200	[thread overview]
Message-ID: <Yyn2SEWN3R80ItR8@GIOVE> (raw)
In-Reply-To: <58359837-fd07-50a0-d5f8-b07bf425b7df@cornell.edu>

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

On Tue, Sep 20, 2022 at 06:18:54PM -0700, Ken Brown wrote:
> 
> On 9/20/2022 2:54 AM, Enrico Forestieri wrote:
> > 
> >  I compared the behavior of read() and select() on 3 different platforms.
> >  My conclusion is that, actually, read() behaves the same on all of them,
> >  whereas cygwin differs in the way select() works.
> 
> Then I'm even more confused than I was before. Are you saying that
> there are situations in which read() reports EOF but select() does not
> report read ready? Could you post the code you used for testing?

I simply introduced a timeout for select() such that it returns on any
platform. On cygwin, when using "O_RDONLY | O_NONBLOCK" for the input
pipe, select() always returns 1, while on all other platforms it returns 0
unless a client actually opens it for writing.

As the "if (FD_ISSET(infd, &readfds))" block would not be entered on the
other platforms, I replaced it with "if (TRUE)" so that the read() is
always executed. In this conditions, the output is the same on all
platforms, meaning that the issue is the select() and not the read() call.

This is the attached fifocomm-test.c file.

-- 
Enrico

[-- Attachment #2: fifocomm-test.c --]
[-- Type: text/plain, Size: 3661 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);
	struct timeval wait_tm = { 0l, 200000l }; /* 200 millisecs */
	do {
	    nsel = select(infd + 1, &readfds, 0, 0, &wait_tm);
	} while (nsel == -1 && (errno == EINTR || errno == EAGAIN));

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

	if (TRUE) {
	    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 */
		fprintf(stderr, "Removing stale pipe %s\n", name);
		stalepipe = TRUE;
		endpipe(name, -1);
	    }
	} else if (stalepipe) {
	    fprintf(stderr, "Removing stale pipe %s\n", name);
	    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));
}

  reply	other threads:[~2022-09-20 17:20 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-18 21:45 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 [this message]
2022-09-23 15:36                   ` Ken Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Yyn2SEWN3R80ItR8@GIOVE \
    --to=forenr@lyx.org \
    --cc=cygwin@cygwin.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).