I have a little test program here which opens two named pipes and
selects on them for read ready. If the pipes are opened read-write,
the select status means "read ready". If the pipes are opened
read-only, the status means "read ready" only until the first byte has
been read; from then on, the status means "won't block", and results
in no wait at all, and zillions of empty reads.
All the documentation I can find either states or implies that the
status should only be "read ready". Why does a read-only open change
this? What am I misunderstanding?
As a side question, this test program opens non-blocking because
opening a named pipe read-only does not return until there is a
writer. What is the reasoning behind this? If this is why select
returns "won't block" status, then why does it return "read ready"
status before the first byte has been read?
It's the difference in behavior before and after the first byte has
been read that puzzles me. I can understand either status, I'd just
be happier if it were consistent.
This is Linux kernel 2.0.33 / glibc 2.1 (mongrel 4 year old
Slackware), and 2.0.35 (Red Hat 5.1) (both stock 2.0.7 and 2.1).
--------------------------------
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <time.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
/* Select anomaly. Select on a named pipe opened read-only returns
"read ready" status until the first byte has been read. Afterwards
it returns "won't block" status. Select always returns "read
ready" status if opened for read-write. This opens two pipes and
shows the behavior as bytes are read. It terminates when a \n is
read on either pipe. */
char *(pipename [2]) = { "/tmp/tstpipe1", "/tmp/tstpipe2" };
int pipefd [2] = { -1, -1 };
fd_set pipefds;
int fdmax = 0;
int emptyReads [2] = { 0, 0 };
int lastEmpty = -1;
void
errexit (int pnum)
{
perror (pipename [pnum]);
exit (1);
voidQuote:}
openPipe (int ro) {
int pnum;
int flg = (ro ? O_RDONLY : O_RDWR) | O_NONBLOCK;
FD_ZERO (&pipefds);
for (pnum = 0; pnum < 2; pnum++) {
if ((mkfifo (pipename [pnum], 0622) < 0) ||
(pipefd [pnum] = open (pipename [pnum], flg)) < 0)
errexit (pnum);
FD_SET (pipefd [pnum], &pipefds);
if (pipefd [pnum] + 1 > fdmax)
fdmax = pipefd [pnum] + 1;
}
voidQuote:}
closePipe (void)
{
int pnum;
for (pnum = 0; pnum < 2; pnum++) {
if ((close (pipefd [pnum]) < 0) || (unlink (pipename [pnum]) < 0))
errexit (pnum);
FD_CLR (pipefd [pnum], &pipefds);
pipefd [pnum] = -1;
}
intQuote:}
readPipe (int pnum)
{
char c;
int i;
if ((i = read (pipefd [pnum], &c, 1)) == 1) {
if (c == '\n')
return (1); /* Watch for eol */
if (emptyReads [0] || emptyReads [1]) {
emptyReads [0] = emptyReads [1] = 0;
printf ("\n"); /* Preserve the count display */
}
printf ("%s: %c\n", pipename [pnum], c);
return (0);
}
if ((i < 0) && ((errno != EAGAIN) && (errno != EWOULDBLOCK)))
errexit (pnum);
emptyReads [pnum]++;
printf ("Empty = %d %d\r", emptyReads [0], emptyReads [1]);
return (0);
voidQuote:}
sleepy (void)
{
while (1) {
fd_set fds;
int i;
fds = pipefds;
if ((i = select (fdmax, &fds, NULL, NULL, NULL)) <= 0) {
perror ("Select");
exit (1);
}
for (i = 0; i < 2; i++)
if (FD_ISSET (pipefd [i], &fds) && readPipe (i))
return; /* EOL received */
}
intQuote:}
main (int argc, char *argv[])
{
int ro = -1;
if (argc == 2) {
if (argv [1] [0] == 'r')
ro = 1;
else if (argv [1] [0] == 'w')
ro = 0;
}
if (ro < 0) {
fprintf (stderr, "Usage:\n%s [r | w]\n o = open read-only\n n = open read-write\n", argv [0]);
exit (1);
}
openPipe (ro);
printf ("Open for %s\n", ro ? "read-only" : "read-write");
printf ("Echo -n to %s or %s to terminate\n", pipename [0], pipename [1]);
printf ("Echo a new line to terminate\n");
sleepy ();
closePipe ();
if (emptyReads [0] || emptyReads [1])
printf ("\n"); /* Preserve the last count */
exit (0);
--------------------------------Quote:}
--
... _._. ._ ._. . _._. ._. ___ .__ ._. . .__. ._ .. ._.
PGP = 91 B3 94 7C E9 E8 76 2D E1 63 51 AA A0 48 89 2F ITAR license #4933
I've found a solution to Fermat's Last Theorem but I see I've run out of room o