From: "James F.Hranicky" Date: 2002-08-22T08:54:14+09:00 Subject: Re: select on solaris On Thu, 22 Aug 2002 03:53:51 +0900 "Jeff Putsch" wrote: > It seems that select() is claiming file descriptors are ready whether or > not they are. > > The simple program I'm trying as a test is: > This does not seem right. First, there is never any data on the error > object, so why is select saying there is? Second once the end of the > file is reached, why is select continuing to claim both descriptors > have data? I'm sure I'm doing something wrong... I ran into something like the programming in C: it seemed that select simply didn't work on pipes. I was doing this: writer -> proc1 -> proc2 -> ... -> procN -> reader Basically, forking an arbitrary # of procs in a pipeline, and getting the writer on one end and the reader at the other. I found what I had to do was make the writer and reader non blocking, use read() and write() and catch EAGAIN when the operations failed. It looked like this: if (fcntl(reader, F_SETFL, O_NONBLOCK) < 0) exit(fprintf(stderr, "fcntl(reader, F_SETFL, O_NONBLOCK): %s\n", strerror(errno))); if (fcntl(writer, F_SETFL, O_NONBLOCK) < 0) exit(fprintf(stderr, "fcntl(reader, F_SETFL, O_NONBLOCK): %s\n", strerror(errno))); while (1) { if ((from_stdin_bytes = read(0, to_pipe_buf, BUFSIZE)) < 0) exit(fprintf(stderr, "read from stdin %d: (%d) %s\n", 0, errno, strerror(errno))); if (to_pipe_bytes == 0) break; while ((to_pipe_bytes = write(writer, to_pipe_buf, from_stdin_bytes)) < 0) { if (errno == EAGAIN) { if ((from_pipe_bytes = read(reader, from_pipe_buf, BUFSIZE)) < 0) { if (errno == EAGAIN) { continue; } else { exit(fprintf(stderr, "read from pipe %d: (%d) %s\n", reader, errno, strerror(errno))); } } else { if (write(1, from_pipe_buf, from_pipe_bytes) < 0) { exit(fprintf(stderr, "write to stdout: %s\n", strerror(errno))); } continue; } } else { exit(fprintf(stderr, "write to pipe: %s\n", strerror(errno))); } } } close(writer); tv.tv_sec = 0; tv.tv_usec = 10; numreads = 0; while (1) { if (numreads == MAXREADS) { char *msg = "Error: reached max # reads\n"; write(2, msg, strlen(msg)); break; } numreads++; if ((from_pipe_bytes = read(reader, from_pipe_buf, BUFSIZE)) < 0) { if (errno == EAGAIN) { select(32, NULL, NULL, NULL, &tv); /* pause for 1/100th of a sec to allow other procs to finish */ continue; } else { exit(fprintf(stderr, "read from pipe %d: (%d) %s\n", reader, errno, strerror(errno))); } } else if (from_pipe_bytes == 0) { break; } else { numreads = 0; if (write(1, from_pipe_buf, from_pipe_bytes) < 0) { exit(fprintf(stderr, "write to stdout: %s\n", strerror(errno))); } continue; } } The kicker was the select() in the read loop after the writer had been closed. I had to add a tiny bit of delay to ensure all the procs in the pipeline finished. Anyway, this worked for me -- I'm sure other Unix folks on the list can add more insight. Jim