Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r77009 - trunk/tools/build/v2/engine
From: kbelco_at_[hidden]
Date: 2012-02-13 15:08:21


Author: noel_belcourt
Date: 2012-02-13 15:08:20 EST (Mon, 13 Feb 2012)
New Revision: 77009
URL: http://svn.boost.org/trac/boost/changeset/77009

Log:
Revert 77005, biffed the revert of 76862.

Text files modified:
   trunk/tools/build/v2/engine/execunix.c | 208 +++++++++++++++++++++++----------------
   trunk/tools/build/v2/engine/jam.c | 56 ++++++++++
   trunk/tools/build/v2/engine/jam.h | 18 +++
   3 files changed, 194 insertions(+), 88 deletions(-)

Modified: trunk/tools/build/v2/engine/execunix.c
==============================================================================
--- trunk/tools/build/v2/engine/execunix.c (original)
+++ trunk/tools/build/v2/engine/execunix.c 2012-02-13 15:08:20 EST (Mon, 13 Feb 2012)
@@ -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 @@
     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 @@
 
 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 @@
 
     close(cmdtab[ i ].fd[ s ]);
     cmdtab[ i ].fd[ s ] = 0;
+
+ cmdtab[i].msgsize[s] = 0;
 }
 
 
@@ -423,6 +434,61 @@
     *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 @@
 
 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 @@
             /* 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<MAXJOBS; ++i) {
+ if (0 < terminated_children[i].pid) {
+ pid_t pid = terminated_children[i].pid;
+ /* get index of terminated pid */
+ for (j=0; j<globs.jobs; ++j) {
+ if (pid == cmdtab[j].pid) {
+ /* cleanup loose ends for terminated process */
+ close_streams(j, OUT);
+ if ( globs.pipe_action != 0 ) close_streams(j, ERR);
+ cleanup_child(j, terminated_children[i].status);
+ --cmdsrunning;
+ finished = 1;
+ break;
+ }
+ }
+ /* clear entry from list */
+ terminated_children[i].status = 0;
+ terminated_children[i].pid = 0;
+ --child_events;
+ }
+ }
         }
 
         if ( 0 < ret )
@@ -496,62 +589,10 @@
 
                     if ( pid == cmdtab[ i ].pid )
                     {
+ /* move into function so signal handler can also use */
                         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. */
+ cleanup_child(i, status);
                         --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
                     {
@@ -562,7 +603,6 @@
             }
         }
     }
-
     return 1;
 }
 

Modified: trunk/tools/build/v2/engine/jam.c
==============================================================================
--- trunk/tools/build/v2/engine/jam.c (original)
+++ trunk/tools/build/v2/engine/jam.c 2012-02-13 15:08:20 EST (Mon, 13 Feb 2012)
@@ -102,6 +102,8 @@
  */
 
 
+#include "limits.h"
+
 #include "jam.h"
 #include "option.h"
 #include "patchlevel.h"
@@ -134,9 +136,36 @@
 #endif
 
 /* And UNIX for this. */
-#ifdef unix
+#if defined(unix) || defined(__unix)
     #include <sys/utsname.h>
+ #include <sys/wait.h>
     #include <signal.h>
+
+ #include <sys/utsname.h>
+ #include <signal.h>
+
+ 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<MAXJOBS; ++i) {
+ /* find first available slot */
+ if (terminated_children[i].pid == 0) {
+ terminated_children[i].pid = pid;
+ terminated_children[i].status = status;
+ break;
+ }
+ }
+ }
+ ++child_events;
+ signal(SIGCHLD, child_sig_handler);
+ }
 #endif
 
 struct globs globs =
@@ -152,7 +181,9 @@
     { 0, 1 }, /* debug ... */
 #endif
     0, /* output commands, not run them */
- 0 /* action timeout */
+ 0, /* action timeout */
+ 0,
+ INT_MAX /* default is to accept all action output */
 };
 
 /* Symbols to be defined as true for use in Jambase. */
@@ -230,6 +261,19 @@
     char const * progname = argv[0];
     module_t * environ_module;
 
+#if defined(unix) || defined(__unix)
+ sigset_t sigmask;
+ struct sigaction sa;
+
+ sigemptyset(&sigmask);
+ sigaddset(&sigmask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &sigmask, NULL);
+ sa.sa_flags = 0;
+ sa.sa_handler = child_sig_handler;
+ sigaction(SIGCHLD, &sa, NULL);
+ sigemptyset(&empty_sigmask);
+#endif
+
     saved_argv0 = argv[0];
 
     BJAM_MEM_INIT();
@@ -241,7 +285,7 @@
     --argc;
     ++argv;
 
- if ( getoptions( argc, argv, "-:l:d:j:p:f:gs:t:ano:qv", optv ) < 0 )
+ if ( getoptions( argc, argv, "-:l:m:d:j:p:f:gs:t:ano:qv", optv ) < 0 )
     {
         printf( "\nusage: %s [ options ] targets...\n\n", progname );
 
@@ -251,6 +295,7 @@
         /* printf( "-g Build from newest sources first.\n" ); */
         printf( "-jx Run up to x shell commands concurrently.\n" );
         printf( "-lx Limit actions to x number of seconds after which they are stopped.\n" );
+ printf( "-mx Limit action output buffer to x kb's of data, after which action output is read and ignored.\n" );
         printf( "-n Don't actually execute the updating actions.\n" );
         printf( "-ox Write the updating actions to file x.\n" );
         printf( "-px x=0, pipes action stdout and stderr merged into action output.\n" );
@@ -318,6 +363,9 @@
     if ( ( s = getoptval( optv, 'l', 0 ) ) )
         globs.timeout = atoi( s );
 
+ if ( ( s = getoptval( optv, 'm', 0 ) ) )
+ globs.maxbuf = atoi( s ) * 1024;
+
     /* Turn on/off debugging */
     for ( n = 0; ( s = getoptval( optv, 'd', n ) ); ++n )
     {
@@ -396,7 +444,7 @@
                    VAR_SET );
 
         /* Set JAMUNAME. */
-#ifdef unix
+#if defined(unix) || defined(__unix)
         {
             struct utsname u;
 

Modified: trunk/tools/build/v2/engine/jam.h
==============================================================================
--- trunk/tools/build/v2/engine/jam.h (original)
+++ trunk/tools/build/v2/engine/jam.h 2012-02-13 15:08:20 EST (Mon, 13 Feb 2012)
@@ -456,10 +456,20 @@
                                  * default 0 for no limit.
                                  */
     int dart; /* output build and test results formatted for Dart */
+ int maxbuf; /* limit action output buffer to maxbuf kb's of data */
 };
 
 extern struct globs globs;
 
+struct terminated_child
+{
+ pid_t pid;
+ int status;
+};
+
+extern struct terminated_child terminated_children[MAXJOBS];
+
+
 #define DEBUG_MAKE ( globs.debug[ 1 ] ) /* show actions when executed */
 #define DEBUG_MAKEQ ( globs.debug[ 2 ] ) /* show even quiet actions */
 #define DEBUG_EXEC ( globs.debug[ 2 ] ) /* show text of actons */
@@ -493,4 +503,12 @@
 /* They also get the profile functions. */
 #include "debug.h"
 
+/* Handle child process termination */
+#if defined(unix) || defined(__unix)
+#include <signal.h>
+extern sigset_t empty_sigmask;
+extern volatile sig_atomic_t child_events;
+void child_sig_handler(int x);
+#endif
+
 #endif


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk