X-Recipient: archive-cygwin AT delorie DOT com X-Original-To: cygwin AT cygwin DOT com Delivered-To: cygwin AT cygwin DOT com DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org AD0713858C74 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=lyx.org Authentication-Results: sourceware.org; spf=none smtp.mailfrom=lyx.org Date: Tue, 20 Sep 2022 19:20:08 +0200 From: Enrico Forestieri To: cygwin AT cygwin DOT com Subject: Re: FIFO issues Message-ID: Mail-Followup-To: cygwin AT cygwin DOT com MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="rtiBEQW2d4pROHZG" Content-Disposition: inline In-Reply-To: <58359837-fd07-50a0-d5f8-b07bf425b7df@cornell.edu> X-Spam-Status: No, score=1.1 required=5.0 tests=BAYES_00, KAM_DMARC_STATUS, KAM_LAZY_DOMAIN_SECURITY, RCVD_IN_BARRACUDACENTRAL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=no autolearn_force=no version=3.4.6 X-Spam-Level: * X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: cygwin AT cygwin DOT com X-Mailman-Version: 2.1.29 Precedence: list List-Id: General Cygwin discussions and problem reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: cygwin-bounces+archive-cygwin=delorie DOT com AT cygwin DOT com Sender: "Cygwin" --rtiBEQW2d4pROHZG Content-Type: text/plain; charset=us-ascii Content-Disposition: inline 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 --rtiBEQW2d4pROHZG Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="fifocomm-test.c" #include #include #include #include #include #include #include #include #include #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)); } --rtiBEQW2d4pROHZG Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline -- Problem reports: https://cygwin.com/problems.html FAQ: https://cygwin.com/faq/ Documentation: https://cygwin.com/docs.html Unsubscribe info: https://cygwin.com/ml/#unsubscribe-simple --rtiBEQW2d4pROHZG--