The following program demonstrates what appears to
be a bug in the implementation of select() (or the
select handler) within the terminal driver(s).
I have tested this both in a pterm window and without
photon on 6.2.0.
The program is supposed to read a character at a time
from STDIN_FILENO while using select with a timeout
value. (There is probably a better way to do this,
but the code is taken from someone else’s software
(sudo) and appears to be legal.)
When you execute the program, it displays a prompt.
If you take no action for 5 seconds, it times out,
which is good.
If you type a single character other than ‘Enter’,
then wait, it will not timeout, which is bad.
If you type a few characters followed by ‘Enter’,
it will read one character, then block. select()
is apparently not returning even though there are
more characters available for reading. If you hit
‘Enter’ again, all of the characters are read -
select() has now recognizes that there are more
characters available. [This behaviour is independent
of the use of a timeout value.]
[Because the console is in edited mode, it is
reasonable to expect select() to wait until the
newline is entered before returning.]
-Norton Allen
#include <stdio.h>
#include <unistd.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <stdlib.h>
#include <errno.h>
int main( int argc, char **argv ) {
int c, n;
fd_set *readfds = NULL;
struct timeval tv;
int fd = STDIN_FILENO;
int timeout = 5;
printf( "Enter Text: " );
fflush(stdout);
readfds = (fd_set *) malloc(sizeof(fd_set));
FD_ZERO(readfds);
for (; {
FD_SET(fd, readfds);
/* Set timeout for select /
tv.tv_sec = timeout;
tv.tv_usec = 0;
/ Make sure there is something to read (or timeout) /
while ((n = select(fd + 1, readfds, 0, 0, &tv)) == -1 &&
errno == EAGAIN) {
tv.tv_sec = timeout;
tv.tv_usec = 0;
}
if (n <= 0) {
free(readfds);
printf( “select returned %d (timeout or interrupt)\n”, n );
return(0); / timeout or interrupt */
}
n = read( fd, &c, 1 );
if ( n != 1 || c == ‘\n’ || c == ‘\r’ )
break;
printf(“read c=%d\n”, c );
}
free(readfds);
if ( n != 1 ) printf(“read n=%d\n”, n );
else printf(“read c=%d\n”, c );
return 0;
}