diff --git a/src/engine/execunix.c b/src/engine/execunix.c index 1ef15a34e..9709d89cb 100644 --- a/src/engine/execunix.c +++ b/src/engine/execunix.c @@ -66,7 +66,7 @@ */ static clock_t tps = 0; -static struct timeval tv; +static struct timespec tv; static int select_timeout = 0; static int intr = 0; static int cmdsrunning = 0; @@ -91,6 +91,7 @@ static struct void (*func)( void *closure, int status, timing_info*, const char *, const char * ); void *closure; time_t start_dt; /* start of command timestamp */ + long msgsize[2]; } cmdtab[ MAXJOBS ] = {{0}}; /* @@ -342,28 +343,36 @@ void exec_cmd int read_descriptor( int i, int s ) { - int ret; - int len; + int ret = 1, len, err; char buffer[BUFSIZ]; - while ( 0 < ( ret = fread( buffer, sizeof(char), BUFSIZ-1, cmdtab[ i ].stream[ s ] ) ) ) - { - buffer[ret] = 0; - if ( !cmdtab[ i ].buffer[ s ] ) - { - /* Never been allocated. */ - cmdtab[ i ].buffer[ s ] = (char*)BJAM_MALLOC_ATOMIC( ret + 1 ); - memcpy( cmdtab[ i ].buffer[ s ], buffer, ret + 1 ); - } - else - { - /* Previously allocated. */ - char * tmp = cmdtab[ i ].buffer[ s ]; - len = strlen( tmp ); - cmdtab[ i ].buffer[ s ] = (char*)BJAM_MALLOC_ATOMIC( len + ret + 1 ); - memcpy( cmdtab[ i ].buffer[ s ], tmp, len ); - memcpy( cmdtab[ i ].buffer[ s ] + len, buffer, ret + 1 ); - BJAM_FREE( tmp ); + while ( 0 < ( ret = fread( buffer, sizeof(char), BUFSIZ-1, cmdtab[ i ].stream[ s ] ) ) ) { + + /* only copy action data until hit buffer limit, then ignore rest of data */ + if (cmdtab[i].msgsize[s] < globs.maxbuf) { + cmdtab[i].msgsize[s] += ret; + buffer[ret] = 0; + if ( !cmdtab[ i ].buffer[ s ] ) + { + /* Never been allocated. */ + cmdtab[ i ].buffer[ s ] = (char*)BJAM_MALLOC_ATOMIC( ret + 1 ); + memcpy( cmdtab[ i ].buffer[ s ], buffer, ret + 1 ); + } + else + { + /* Previously allocated. */ + char * tmp = cmdtab[ i ].buffer[ s ]; + len = strlen( tmp ); + cmdtab[ i ].buffer[ s ] = (char*)BJAM_MALLOC_ATOMIC( len + ret + 1 ); + memcpy( cmdtab[ i ].buffer[ s ], tmp, len ); + memcpy( cmdtab[ i ].buffer[ s ] + len, buffer, ret + 1 ); + BJAM_FREE( tmp ); + } + + /* buffer was truncated, append newline to ensure pjl can find line end */ + if (globs.maxbuf <= cmdtab[i].msgsize[s]) { + cmdtab[i].buffer[s][cmdtab[i].msgsize[s]-1] = '\n'; + } } } @@ -379,6 +388,8 @@ void close_streams( int i, int s ) close(cmdtab[ i ].fd[ s ]); cmdtab[ i ].fd[ s ] = 0; + + cmdtab[i].msgsize[s] = 0; } @@ -423,6 +434,61 @@ void populate_file_descriptors( int * fmax, fd_set * fds) *fmax = fd_max; } +void cleanup_child(int i, int status) +{ + int rstat; + struct tms new_time; + timing_info time_info; + + cmdtab[ i ].pid = 0; + + /* Set reason for exit if not timed out. */ + if ( WIFEXITED( status ) ) { + cmdtab[ i ].exit_reason = 0 == WEXITSTATUS( status ) + ? EXIT_OK : EXIT_FAIL; + } + + /* Print out the rule and target name. */ + out_action( cmdtab[ i ].action, cmdtab[ i ].target, + cmdtab[ i ].command, cmdtab[ i ].buffer[ OUT ], + cmdtab[ i ].buffer[ ERR ], cmdtab[ i ].exit_reason + ); + + times( &new_time ); + + time_info.system = (double)( new_time.tms_cstime - old_time.tms_cstime ) / CLOCKS_PER_SEC; + time_info.user = (double)( new_time.tms_cutime - old_time.tms_cutime ) / CLOCKS_PER_SEC; + time_info.start = cmdtab[ i ].start_dt; + time_info.end = time( 0 ); + + old_time = new_time; + + if ( intr ) + rstat = EXEC_CMD_INTR; + else if ( status != 0 ) + rstat = EXEC_CMD_FAIL; + else + rstat = EXEC_CMD_OK; + + /* Assume -p0 in effect so only pass buffer[ 0 ] + * containing merged output. + */ + (*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat, &time_info, cmdtab[ i ].command, cmdtab[ i ].buffer[ 0 ] ); + + BJAM_FREE( cmdtab[ i ].buffer[ OUT ] ); + cmdtab[ i ].buffer[ OUT ] = 0; + + BJAM_FREE( cmdtab[ i ].buffer[ ERR ] ); + cmdtab[ i ].buffer[ ERR ] = 0; + + BJAM_FREE( cmdtab[ i ].command ); + cmdtab[ i ].command = 0; + + cmdtab[ i ].func = 0; + cmdtab[ i ].closure = 0; + cmdtab[ i ].start_time = 0; +} + /* * exec_wait() - wait and drive at most one execution completion. @@ -430,16 +496,13 @@ void populate_file_descriptors( int * fmax, fd_set * fds) int exec_wait() { - int i; + int i, j; int ret; int fd_max; int pid; int status; int finished; - int rstat; - timing_info time_info; fd_set fds; - struct tms new_time; /* Handle naive make1() which does not know if commands are running. */ if ( !cmdsrunning ) @@ -457,17 +520,47 @@ int exec_wait() /* Force select() to timeout so we can terminate expired processes. */ tv.tv_sec = select_timeout; - tv.tv_usec = 0; + tv.tv_nsec = 0; /* select() will wait until: i/o on a descriptor, a signal, or we * time out. */ - ret = select( fd_max + 1, &fds, 0, 0, &tv ); + ret = pselect( fd_max + 1, &fds, 0, 0, &tv, &empty_sigmask ); } else { - /* select() will wait until i/o on a descriptor or a signal. */ - ret = select( fd_max + 1, &fds, 0, 0, 0 ); + /* pselect() will wait until i/o on a descriptor or a signal. */ + ret = pselect( fd_max + 1, &fds, 0, 0, 0, &empty_sigmask ); + } + + if (-1 == ret && errno != EINTR) { + perror("pselect()"); + exit(-1); + } + + if (0 < child_events) { + /* child terminated via SIGCHLD */ + for (i=0; i + #include #include + + #include + #include + + sigset_t empty_sigmask; + volatile sig_atomic_t child_events = 0; + struct terminated_child terminated_children[MAXJOBS] = {{ 0 }}; + + void child_sig_handler(int x) { + pid_t pid; + int i, status; + pid = waitpid(-1, &status, WNOHANG); + if (0 < pid) { + /* save terminated child pid and status */ + for (i=0; i +extern sigset_t empty_sigmask; +extern volatile sig_atomic_t child_events; +void child_sig_handler(int x); +#endif + #endif