I believe, this code is better. The attached patch should be applied over previously attached open_init_pty.c source. Changes: * BUFSIZE changed to 2KiB (from 16KiB), it seems to me sufficient. * When no file-descriptor is available to monitor by select(), waitpid() in blocking mode is called. * An empty signal handler for SIGCHLD is installed, because ignored signal (default) does not interrupts I/O calls. Best Regards -- Zito
--- open_init_pty.c~v1 2008-04-23 13:13:03.000000000 +0200 +++ open_init_pty.c 2008-04-23 14:52:02.000000000 +0200 @@ -29,6 +29,7 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <signal.h> #include <errno.h> #include <sysexits.h> @@ -43,7 +44,7 @@ #define MAXRETR 3 /* The max number of IO retries on a fd */ -#define BUFSIZE 16384 /* The ring buffer size */ +#define BUFSIZE 2048 /* The ring buffer size */ static struct termios saved_termios; static int saved_fd = -1; @@ -165,13 +166,9 @@ return n; } - -#define FD_SET_VALUE(fd, fdset, value) \ - if (value) \ - FD_SET(fd, fdset); \ - else \ - FD_CLR(fd, fdset); - +void sigchld_handler(int asig __attribute__ ((unused))) +{ +} int main(int argc, char *argv[]) { @@ -194,6 +191,12 @@ exit(1); } + /* Wee need I/O calls to fail with EINTR on SIGCHLD... */ + if ( signal(SIGCHLD, sigchld_handler) == SIG_ERR ) { + perror("signal(SIGCHLD,...)"); + exit(EX_OSERR); + } + if (isatty(STDIN_FILENO)) { /* get terminal parameters associated with stdout */ if (tcgetattr(STDOUT_FILENO, &tty_attr) < 0) { @@ -281,14 +284,41 @@ do { /* Accept events only on fds, that we can handle now. */ - FD_SET_VALUE(pty_master, &readfds, - ringbuf_space(&outbuf) > 0 && err_n_rpty < MAXRETR); - FD_SET_VALUE(pty_master, &writefds, - ! ringbuf_isempty(&inbuf) && err_n_wpty < MAXRETR); - FD_SET_VALUE(STDIN_FILENO, &readfds, - ringbuf_space(&inbuf) > 0 && err_n_stdin < MAXRETR); - FD_SET_VALUE(STDOUT_FILENO, &writefds, - ! ringbuf_isempty(&outbuf) && err_n_stdout < MAXRETR); + int do_select = 0; + + if ( ringbuf_space(&outbuf) > 0 && err_n_rpty < MAXRETR ) { + FD_SET(pty_master, &readfds); + do_select = 1; + } else + FD_CLR(pty_master, &readfds); + + if ( ! ringbuf_isempty(&inbuf) && err_n_wpty < MAXRETR ) { + FD_SET(pty_master, &writefds); + do_select = 1; + } else + FD_CLR(pty_master, &writefds); + + if ( ringbuf_space(&inbuf) > 0 && err_n_stdin < MAXRETR ) { + FD_SET(STDIN_FILENO, &readfds); + do_select = 1; + } else + FD_CLR(STDIN_FILENO, &readfds); + + if ( ! ringbuf_isempty(&outbuf) && err_n_stdout < MAXRETR ) { + FD_SET(STDOUT_FILENO, &writefds); + do_select = 1; + } else + FD_CLR(STDOUT_FILENO, &writefds); + + if ( ! do_select ) + { +#ifdef DEBUG + fprintf(stderr, "No I/O job for us, calling waitpid()...\n"); +#endif + while ( waitpid(child_pid, &child_exit_status, 0) < 0 ) + ; + break; + } int select_rc = select(pty_master + 1, &readfds, &writefds, &exceptfds, NULL);