diff options
author | Chris Dyer <cdyer@cab.ark.cs.cmu.edu> | 2012-10-02 00:19:43 -0400 |
---|---|---|
committer | Chris Dyer <cdyer@cab.ark.cs.cmu.edu> | 2012-10-02 00:19:43 -0400 |
commit | e26434979adc33bd949566ba7bf02dff64e80a3e (patch) | |
tree | d1c72495e3af6301bd28e7e66c42de0c7a944d1f /jam-files/engine/execunix.c | |
parent | 0870d4a1f5e14cc7daf553b180d599f09f6614a2 (diff) |
cdec cleanup, remove bayesian stuff, parsing stuff
Diffstat (limited to 'jam-files/engine/execunix.c')
-rw-r--r-- | jam-files/engine/execunix.c | 569 |
1 files changed, 0 insertions, 569 deletions
diff --git a/jam-files/engine/execunix.c b/jam-files/engine/execunix.c deleted file mode 100644 index ef9dba00..00000000 --- a/jam-files/engine/execunix.c +++ /dev/null @@ -1,569 +0,0 @@ -/* - * Copyright 1993, 1995 Christopher Seiwald. - * Copyright 2007 Noel Belcourt. - * - * This file is part of Jam - see jam.c for Copyright information. - */ - -#include "jam.h" -#include "lists.h" -#include "execcmd.h" -#include "output.h" -#include <errno.h> -#include <signal.h> -#include <stdio.h> -#include <time.h> -#include <unistd.h> /* needed for vfork(), _exit() prototypes */ -#include <sys/resource.h> -#include <sys/times.h> -#include <sys/wait.h> - -#if defined(sun) || defined(__sun) || defined(linux) - #include <wait.h> -#endif - -#ifdef USE_EXECUNIX - -#include <sys/times.h> - -#if defined(__APPLE__) - #define NO_VFORK -#endif - -#ifdef NO_VFORK - #define vfork() fork() -#endif - - -/* - * execunix.c - execute a shell script on UNIX/WinNT/OS2/AmigaOS - * - * If $(JAMSHELL) is defined, uses that to formulate execvp()/spawnvp(). - * The default is: - * - * /bin/sh -c % [ on UNIX/AmigaOS ] - * cmd.exe /c % [ on OS2/WinNT ] - * - * Each word must be an individual element in a jam variable value. - * - * In $(JAMSHELL), % expands to the command string and ! expands to the slot - * number (starting at 1) for multiprocess (-j) invocations. If $(JAMSHELL) does - * not include a %, it is tacked on as the last argument. - * - * Do not just set JAMSHELL to /bin/sh or cmd.exe - it will not work! - * - * External routines: - * exec_cmd() - launch an async command execution. - * exec_wait() - wait and drive at most one execution completion. - * - * Internal routines: - * onintr() - bump intr to note command interruption. - * - * 04/08/94 (seiwald) - Coherent/386 support added. - * 05/04/94 (seiwald) - async multiprocess interface - * 01/22/95 (seiwald) - $(JAMSHELL) support - * 06/02/97 (gsar) - full async multiprocess support for Win32 - */ - -static clock_t tps = 0; -static struct timeval tv; -static int select_timeout = 0; -static int intr = 0; -static int cmdsrunning = 0; -static struct tms old_time; - -#define OUT 0 -#define ERR 1 - -static struct -{ - int pid; /* on win32, a real process handle */ - int fd[2]; /* file descriptors for stdout and stderr */ - FILE *stream[2]; /* child's stdout (0) and stderr (1) file stream */ - clock_t start_time; /* start time of child process */ - int exit_reason; /* termination status */ - int action_length; /* length of action string */ - int target_length; /* length of target string */ - char *action; /* buffer to hold action and target invoked */ - char *target; /* buffer to hold action and target invoked */ - char *command; /* buffer to hold command being invoked */ - char *buffer[2]; /* buffer to hold stdout and stderr, if any */ - void (*func)( void *closure, int status, timing_info*, char *, char * ); - void *closure; - time_t start_dt; /* start of command timestamp */ -} cmdtab[ MAXJOBS ] = {{0}}; - -/* - * onintr() - bump intr to note command interruption - */ - -void onintr( int disp ) -{ - ++intr; - printf( "...interrupted\n" ); -} - - -/* - * exec_cmd() - launch an async command execution. - */ - -void exec_cmd -( - char * string, - void (*func)( void *closure, int status, timing_info*, char *, char * ), - void * closure, - LIST * shell, - char * action, - char * target -) -{ - static int initialized = 0; - int out[2]; - int err[2]; - int slot; - int len; - char * argv[ MAXARGC + 1 ]; /* +1 for NULL */ - - /* Find a slot in the running commands table for this one. */ - for ( slot = 0; slot < MAXJOBS; ++slot ) - if ( !cmdtab[ slot ].pid ) - break; - - if ( slot == MAXJOBS ) - { - printf( "no slots for child!\n" ); - exit( EXITBAD ); - } - - /* Forumulate argv. If shell was defined, be prepared for % and ! subs. - * Otherwise, use stock /bin/sh on unix or cmd.exe on NT. - */ - if ( shell ) - { - int i; - char jobno[4]; - int gotpercent = 0; - - sprintf( jobno, "%d", slot + 1 ); - - for ( i = 0; shell && i < MAXARGC; ++i, shell = list_next( shell ) ) - { - switch ( shell->string[0] ) - { - case '%': argv[ i ] = string; ++gotpercent; break; - case '!': argv[ i ] = jobno; break; - default : argv[ i ] = shell->string; - } - if ( DEBUG_EXECCMD ) - printf( "argv[%d] = '%s'\n", i, argv[ i ] ); - } - - if ( !gotpercent ) - argv[ i++ ] = string; - - argv[ i ] = 0; - } - else - { - argv[ 0 ] = "/bin/sh"; - argv[ 1 ] = "-c"; - argv[ 2 ] = string; - argv[ 3 ] = 0; - } - - /* Increment jobs running. */ - ++cmdsrunning; - - /* Save off actual command string. */ - cmdtab[ slot ].command = BJAM_MALLOC_ATOMIC( strlen( string ) + 1 ); - strcpy( cmdtab[ slot ].command, string ); - - /* Initialize only once. */ - if ( !initialized ) - { - times( &old_time ); - initialized = 1; - } - - /* Create pipes from child to parent. */ - { - if ( pipe( out ) < 0 ) - exit( EXITBAD ); - - if ( pipe( err ) < 0 ) - exit( EXITBAD ); - } - - /* Start the command */ - - cmdtab[ slot ].start_dt = time(0); - - if ( 0 < globs.timeout ) - { - /* - * Handle hung processes by manually tracking elapsed time and signal - * process when time limit expires. - */ - struct tms buf; - cmdtab[ slot ].start_time = times( &buf ); - - /* Make a global, only do this once. */ - if ( tps == 0 ) tps = sysconf( _SC_CLK_TCK ); - } - - if ( ( cmdtab[ slot ].pid = vfork() ) == 0 ) - { - int pid = getpid(); - - close( out[0] ); - close( err[0] ); - - dup2( out[1], STDOUT_FILENO ); - - if ( globs.pipe_action == 0 ) - dup2( out[1], STDERR_FILENO ); - else - dup2( err[1], STDERR_FILENO ); - - close( out[1] ); - close( err[1] ); - - /* Make this process a process group leader so that when we kill it, all - * child processes of this process are terminated as well. We use - * killpg(pid, SIGKILL) to kill the process group leader and all its - * children. - */ - if ( 0 < globs.timeout ) - { - struct rlimit r_limit; - r_limit.rlim_cur = globs.timeout; - r_limit.rlim_max = globs.timeout; - setrlimit( RLIMIT_CPU, &r_limit ); - } - setpgid( pid,pid ); - execvp( argv[0], argv ); - perror( "execvp" ); - _exit( 127 ); - } - else if ( cmdtab[ slot ].pid == -1 ) - { - perror( "vfork" ); - exit( EXITBAD ); - } - - setpgid( cmdtab[ slot ].pid, cmdtab[ slot ].pid ); - - /* close write end of pipes */ - close( out[1] ); - close( err[1] ); - - /* set both file descriptors to non-blocking */ - fcntl(out[0], F_SETFL, O_NONBLOCK); - fcntl(err[0], F_SETFL, O_NONBLOCK); - - /* child writes stdout to out[1], parent reads from out[0] */ - cmdtab[ slot ].fd[ OUT ] = out[0]; - cmdtab[ slot ].stream[ OUT ] = fdopen( cmdtab[ slot ].fd[ OUT ], "rb" ); - if ( cmdtab[ slot ].stream[ OUT ] == NULL ) - { - perror( "fdopen" ); - exit( EXITBAD ); - } - - /* child writes stderr to err[1], parent reads from err[0] */ - if (globs.pipe_action == 0) - { - close(err[0]); - } - else - { - cmdtab[ slot ].fd[ ERR ] = err[0]; - cmdtab[ slot ].stream[ ERR ] = fdopen( cmdtab[ slot ].fd[ ERR ], "rb" ); - if ( cmdtab[ slot ].stream[ ERR ] == NULL ) - { - perror( "fdopen" ); - exit( EXITBAD ); - } - } - - /* Ensure enough room for rule and target name. */ - if ( action && target ) - { - len = strlen( action ) + 1; - if ( cmdtab[ slot ].action_length < len ) - { - BJAM_FREE( cmdtab[ slot ].action ); - cmdtab[ slot ].action = BJAM_MALLOC_ATOMIC( len ); - cmdtab[ slot ].action_length = len; - } - strcpy( cmdtab[ slot ].action, action ); - len = strlen( target ) + 1; - if ( cmdtab[ slot ].target_length < len ) - { - BJAM_FREE( cmdtab[ slot ].target ); - cmdtab[ slot ].target = BJAM_MALLOC_ATOMIC( len ); - cmdtab[ slot ].target_length = len; - } - strcpy( cmdtab[ slot ].target, target ); - } - else - { - BJAM_FREE( cmdtab[ slot ].action ); - BJAM_FREE( cmdtab[ slot ].target ); - cmdtab[ slot ].action = 0; - cmdtab[ slot ].target = 0; - cmdtab[ slot ].action_length = 0; - cmdtab[ slot ].target_length = 0; - } - - /* Save the operation for exec_wait() to find. */ - cmdtab[ slot ].func = func; - cmdtab[ slot ].closure = closure; - - /* Wait until we are under the limit of concurrent commands. Do not trust - * globs.jobs alone. - */ - while ( ( cmdsrunning >= MAXJOBS ) || ( cmdsrunning >= globs.jobs ) ) - if ( !exec_wait() ) - break; -} - - -/* Returns 1 if file is closed, 0 if descriptor is still live. - * - * i is index into cmdtab - * - * s (stream) indexes: - * - cmdtab[ i ].stream[ s ] - * - cmdtab[ i ].buffer[ s ] - * - cmdtab[ i ].fd [ s ] - */ - -int read_descriptor( int i, int s ) -{ - int ret; - int len; - 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 ); - } - } - - return feof(cmdtab[ i ].stream[ s ]); -} - - -void close_streams( int i, int s ) -{ - /* Close the stream and pipe descriptor. */ - fclose(cmdtab[ i ].stream[ s ]); - cmdtab[ i ].stream[ s ] = 0; - - close(cmdtab[ i ].fd[ s ]); - cmdtab[ i ].fd[ s ] = 0; -} - - -void populate_file_descriptors( int * fmax, fd_set * fds) -{ - int i, fd_max = 0; - struct tms buf; - clock_t current = times( &buf ); - select_timeout = globs.timeout; - - /* Compute max read file descriptor for use in select. */ - FD_ZERO(fds); - for ( i = 0; i < globs.jobs; ++i ) - { - if ( 0 < cmdtab[ i ].fd[ OUT ] ) - { - fd_max = fd_max < cmdtab[ i ].fd[ OUT ] ? cmdtab[ i ].fd[ OUT ] : fd_max; - FD_SET(cmdtab[ i ].fd[ OUT ], fds); - } - if ( globs.pipe_action != 0 ) - { - if (0 < cmdtab[ i ].fd[ ERR ]) - { - fd_max = fd_max < cmdtab[ i ].fd[ ERR ] ? cmdtab[ i ].fd[ ERR ] : fd_max; - FD_SET(cmdtab[ i ].fd[ ERR ], fds); - } - } - - if (globs.timeout && cmdtab[ i ].pid) { - clock_t consumed = (current - cmdtab[ i ].start_time) / tps; - clock_t process_timesout = globs.timeout - consumed; - if (0 < process_timesout && process_timesout < select_timeout) { - select_timeout = process_timesout; - } - if ( globs.timeout <= consumed ) - { - killpg( cmdtab[ i ].pid, SIGKILL ); - cmdtab[ i ].exit_reason = EXIT_TIMEOUT; - } - } - } - *fmax = fd_max; -} - - -/* - * exec_wait() - wait and drive at most one execution completion. - */ - -int exec_wait() -{ - int i; - 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 ) - return 0; - - /* Process children that signaled. */ - finished = 0; - while ( !finished && cmdsrunning ) - { - /* Compute max read file descriptor for use in select(). */ - populate_file_descriptors( &fd_max, &fds ); - - if ( 0 < globs.timeout ) - { - /* Force select() to timeout so we can terminate expired processes. - */ - tv.tv_sec = select_timeout; - tv.tv_usec = 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 ); - } - else - { - /* select() will wait until i/o on a descriptor or a signal. */ - ret = select( fd_max + 1, &fds, 0, 0, 0 ); - } - - if ( 0 < ret ) - { - for ( i = 0; i < globs.jobs; ++i ) - { - int out = 0; - int err = 0; - if ( FD_ISSET( cmdtab[ i ].fd[ OUT ], &fds ) ) - out = read_descriptor( i, OUT ); - - if ( ( globs.pipe_action != 0 ) && - ( FD_ISSET( cmdtab[ i ].fd[ ERR ], &fds ) ) ) - err = read_descriptor( i, ERR ); - - /* If feof on either descriptor, then we are done. */ - if ( out || err ) - { - /* Close the stream and pipe descriptors. */ - close_streams( i, OUT ); - if ( globs.pipe_action != 0 ) - close_streams( i, ERR ); - - /* Reap the child and release resources. */ - pid = waitpid( cmdtab[ i ].pid, &status, 0 ); - - if ( pid == cmdtab[ i ].pid ) - { - finished = 1; - pid = 0; - 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; - - /* Drive the completion. */ - --cmdsrunning; - - 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; - } - else - { - printf( "unknown pid %d with errno = %d\n", pid, errno ); - exit( EXITBAD ); - } - } - } - } - } - - return 1; -} - -# endif /* USE_EXECUNIX */ |