Update of /cvsroot/boost/boost/tools/jam/src
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv19864/tools/jam_994/src

Modified Files:
      Tag: Boost_Jam_994
        execunix.c jam.c jam.h 
Log Message:
Patch from Noel Belcourt, with some minor changes for portability. Implements 
action output deferral to sync the output regardless of -jn.

Index: execunix.c
===================================================================
RCS file: /cvsroot/boost/boost/tools/jam/src/execunix.c,v
retrieving revision 1.10
retrieving revision 1.10.2.1
diff -u -d -r1.10 -r1.10.2.1
--- execunix.c  7 Sep 2006 03:57:02 -0000       1.10
+++ execunix.c  30 May 2007 16:39:25 -0000      1.10.2.1
@@ -8,6 +8,8 @@
 # include "lists.h"
 # include "execcmd.h"
 # include <errno.h>
+# include <signal.h>
+# include <stdio.h>
 # include <time.h>
 # include <unistd.h> /* needed for vfork(), _exit() prototypes */
 
@@ -55,15 +57,44 @@
 
 static int intr = 0;
 static int cmdsrunning = 0;
+static int fd_max = 0;
 static void (*istat)( int );
 
 static struct
 {
-       int     pid; /* on win32, a real process handle */
-       void    (*func)( void *closure, int status, timing_info* );
-       void    *closure;
+    int            pid;        /* on win32, a real process handle */
+    int     finished;   /* 1 if child process has signaled, 0 otherwise */
+    int     fd;         /* file descriptors for stdout and stderr */
+    FILE   *stream;     /* child's stderr file stream */
+    char   *buffer;     /* buffer to hold stderr output, if any */
+    void    (*func)( void *closure, int status, timing_info* );
+    void   *closure;
 } cmdtab[ MAXJOBS ] = {{0}};
 
+/* file descriptor set used by unix select */
+fd_set readfds;
+
+/* handle child termination signals */
+void sig_chld_handler(int signo, siginfo_t* info, void* uap)
+{
+    int i, status;
+
+    /* Find cmdtab entry that matches the pid of this
+     * terminating child process.  Set cmdtab[i].finished 
+     * to one to indicate this child process has terminated 
+     * and is ready to have it's output read.
+     */
+    for( i=0 ; i < MAXJOBS; ++i ) {
+        if( info->si_pid == cmdtab[ i ].pid ) {
+            cmdtab[ i ].finished = 1;
+            return;
+        }
+    }
+
+    /* if here, a process terminated that execunix didn't spawn, wait for it */
+    wait(&status);
+}
+
 /*
  * onintr() - bump intr to note command interruption
  */
@@ -86,9 +117,11 @@
        void *closure,
        LIST *shell )
 {
-       int pid;
+        int p[2];
+        int pid;
        int slot;
        char *argv[ MAXARGC + 1 ];      /* +1 for NULL */
+        FILE *stream;
 
        /* Find a slot in the running commands table for this one. */
 
@@ -140,37 +173,86 @@
            argv[3] = 0;
        }
 
-       /* Catch interrupts whenever commands are running. */
+       /* increment jobs running */
+       ++cmdsrunning;
 
-       if( !cmdsrunning++ )
-           istat = signal( SIGINT, onintr );
+        /* create pipe from child to parent */
+
+        if (pipe(p) < 0)
+            exit(EXITBAD);
 
        /* Start the command */
 
        if ((pid = vfork()) == 0) 
        {
-               execvp( argv[0], argv );
-               _exit(127);
-       }
+            dup2(p[1], STDERR_FILENO);
+            close(p[0]);
+            close(p[1]);
 
-       if( pid == -1 )
+           execvp( argv[0], argv );
+           _exit(127);
+       }
+        else if( pid == -1 )
        {
            perror( "vfork" );
            exit( EXITBAD );
        }
 
+        /* close write end of pipe, open read end of pipe */
+
+        close(p[1]); 
+        stream = fdopen(p[0], "r");
+        if (stream == NULL) {
+            perror( "fdopen" );
+            exit( EXITBAD );
+        }
+
        /* Save the operation for execwait() to find. */
 
        cmdtab[ slot ].pid = pid;
+       cmdtab[ slot ].fd = p[0];
+       cmdtab[ slot ].stream = stream;
        cmdtab[ slot ].func = func;
        cmdtab[ slot ].closure = closure;
 
+        /* save off max read file descriptor for use in select */
+
+        fd_max = fd_max < p[0] ? p[0] : fd_max;
+        FD_SET(p[0], &readfds);
+
        /* Wait until we're under the limit of concurrent commands. */
        /* Don't trust globs.jobs alone. */
 
-       while( cmdsrunning >= MAXJOBS || cmdsrunning >= globs.jobs )
-           if( !execwait() )
-               break;
+        while( cmdsrunning >= MAXJOBS || cmdsrunning >= globs.jobs )
+            if( !execwait() )
+                break;
+}
+
+void read_descriptor(int i)
+{
+    int ret, len;
+    char *tmp;
+    char buffer[BUFSIZ];
+    while ((ret = fread(buffer, sizeof(char), BUFSIZ-1, cmdtab[i].stream)) > 
0) 
+    {
+        buffer[ret] = 0;
+        if (!cmdtab[i].buffer)
+        {
+            /* never been allocated */
+            cmdtab[i].buffer = (char*)malloc(ret+1);
+            memcpy(cmdtab[i].buffer, buffer, ret+1);
+        }
+        else
+        {
+            /* previously allocated */
+            tmp = cmdtab[i].buffer;
+            len = strlen(tmp);
+            cmdtab[i].buffer = (char*)malloc(len+ret+1);
+            memcpy(cmdtab[i].buffer, tmp, len);
+            memcpy(cmdtab[i].buffer+len, buffer, ret+1);
+            free(tmp);
+        }
+    }
 }
 
 /*
@@ -180,65 +262,116 @@
 int
 execwait()
 {
-       int i;
-       int status, w;
-       int rstat;
+    int i, j, ret;
+    int status, w, finished;
+    int rstat;
     timing_info time;
+    fd_set fds;
     struct tms old_time, new_time;
     
-       /* Handle naive make1() which doesn't know if cmds are running. */
+    /* Handle naive make1() which doesn't know if cmds are running. */
 
-       if( !cmdsrunning )
-           return 0;
+    if( !cmdsrunning )
+        return 0;
+
+    finished = 0;
+    while (!finished)
+    {
+        /* find first job that finished */
+        for (i=0; i<MAXJOBS; ++i)
+        {
+            if ( cmdtab[i].finished )
+            {
+                finished = 1;
+                read_descriptor(i);
+                break;
+            }
+        }
+
+        if (!finished) 
+        {
+            fds = readfds;
+
+            /* wait for io on a descriptor or a signal */
+            ret = select(fd_max+1, &fds, NULL, NULL, NULL);
+
+            /* check for data on a descriptor */
+            if (0 < ret)
+            {
+                for (i=0; i<MAXJOBS; ++i)
+                {
+                    if ( FD_ISSET(cmdtab[i].fd, &fds) )
+                    {
+                        read_descriptor(i);
+                    }
+                }
+            }
+        }
+    }
+
+    /* find first job that finished */
+    for (i=0; i<MAXJOBS; ++i)
+        if ( cmdtab[i].finished )
+            break;
+
+    /* ensure a job terminated */
+    if (i == MAXJOBS)
+        exit(EXITBAD);
 
     times(&old_time);
     
-       /* Pick up process pid and status */
-       while( ( w = wait( &status ) ) == -1 && errno == EINTR )
-               ;
+    /* print out the buffer */
+    if (cmdtab[i].buffer)
+        printf("%s", cmdtab[i].buffer);
 
-       if( w == -1 )
-       {
-           printf( "child process(es) lost!\n" );
-           perror("wait");
-           exit( EXITBAD );
-       }
+    /* close stderr file */
+    ret = fclose(cmdtab[i].stream);
 
-    times(&new_time);
+    /* wait for the child */
+    w = waitpid(cmdtab[i].pid, &status, 0);
 
-    time.system = (double)(new_time.tms_cstime - old_time.tms_cstime) / 
CLOCKS_PER_SEC;
-    time.user = (double)(new_time.tms_cutime - old_time.tms_cutime) / 
CLOCKS_PER_SEC;
-    
-       /* Find the process in the cmdtab. */
+    if( w == -1 )
+    {
+        printf( "child process(es) lost!\n" );
+        perror("waitpid");
+        exit( EXITBAD );
+    }
 
-       for( i = 0; i < MAXJOBS; i++ )
-           if( w == cmdtab[ i ].pid )
-               break;
+    /* clear this file descriptor from pselect */ 
+    FD_CLR(cmdtab[i].fd, &readfds);
 
-       if( i == MAXJOBS )
-       {
-           printf( "waif child found!\n" );
-           exit( EXITBAD );
-       }
+    /* initialize back to zero */
+    cmdtab[i].pid = 0;
+    cmdtab[i].finished = 0;
+    cmdtab[i].fd = 0;
+    cmdtab[i].stream = 0;
+    free(cmdtab[i].buffer);
+    cmdtab[i].buffer = 0;
 
-    
-       /* Drive the completion */
+    /* compute fd_max */
+    fd_max = 0;
+    for (j=0; j<MAXJOBS; ++j)
+        fd_max = fd_max < cmdtab[j].fd ? cmdtab[j].fd : fd_max;
 
-       if( !--cmdsrunning )
-           signal( SIGINT, istat );
+    times(&new_time);
 
-       if( intr )
-           rstat = EXEC_CMD_INTR;
-       else if( w == -1 || status != 0 )
-           rstat = EXEC_CMD_FAIL;
-       else
-           rstat = EXEC_CMD_OK;
+    time.system = (double)(new_time.tms_cstime - old_time.tms_cstime) / 
CLOCKS_PER_SEC;
+    time.user = (double)(new_time.tms_cutime - old_time.tms_cutime) / 
CLOCKS_PER_SEC;
+    
+    /* Drive the completion */
 
-       cmdtab[ i ].pid = 0;
+    --cmdsrunning;
 
-       (*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat, &time );
+    if( intr )
+        rstat = EXEC_CMD_INTR;
+    else if( w == -1 || status != 0 )
+        rstat = EXEC_CMD_FAIL;
+    else
+        rstat = EXEC_CMD_OK;
 
-       return 1;
+    (*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat, &time );
+
+    return 1;
 }
 
 # if defined( OS_NT ) && !defined( __BORLANDC__ )

Index: jam.c
===================================================================
RCS file: /cvsroot/boost/boost/tools/jam/src/jam.c,v
retrieving revision 1.41
retrieving revision 1.41.2.1
diff -u -d -r1.41 -r1.41.2.1
--- jam.c       7 Sep 2006 03:57:02 -0000       1.41
+++ jam.c       30 May 2007 16:39:25 -0000      1.41.2.1
@@ -133,6 +133,7 @@
 
 # ifdef unix
 # include <sys/utsname.h>
+# include <signal.h>
 # endif
 
 struct globs globs = {
@@ -217,9 +218,35 @@
     int arg_c = argc;
     char ** arg_v = argv;
     const char *progname = argv[0];
-    
+
     BJAM_MEM_INIT();
 
+    #ifdef unix
+    {
+        /* handle child termination signals (in execunix.c) */
+        extern void sig_chld_handler(int signo, siginfo_t* info, void* uap);
+        extern fd_set readfds;
+        
+        struct sigaction act, oact;
+        
+        /* install child termination signal handler */
+
+        act.sa_sigaction = sig_chld_handler;
+        sigemptyset(&act.sa_mask);
+        act.sa_flags = 0;
+        act.sa_flags |= SA_NOCLDSTOP;
+        act.sa_flags |= SA_RESTART;
+        act.sa_flags |= SA_SIGINFO;
+        if (sigaction(SIGCHLD, &act, &oact) < 0)
+        {
+            perror("sigaction SIGCHLD error");
+        }
+
+        /* initialize file descriptor set used in select */
+        FD_ZERO(&readfds);
+    }
+    #endif
+    
 # ifdef OS_MAC
     InitGraf(&qd.thePort);
 # endif

Index: jam.h
===================================================================
RCS file: /cvsroot/boost/boost/tools/jam/src/jam.h,v
retrieving revision 1.21
retrieving revision 1.21.2.1
diff -u -d -r1.21 -r1.21.2.1
--- jam.h       7 Sep 2006 03:57:02 -0000       1.21
+++ jam.h       30 May 2007 16:39:25 -0000      1.21.2.1
@@ -524,7 +524,8 @@
        int     newestfirst;            /* build newest sources first */
        char    debug[DEBUG_MAX];
        FILE    *cmdout;                /* print cmds, not run them */
-    long timeout; /* number of seconds to limit actions to, default 0 for no 
limit. */
+    long timeout;           /* number of seconds to limit actions to, default 
0 for no limit. */
+    int dart;               /* output build and test results formatted for 
Dart */
 } ;
 
 extern struct globs globs;


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Boost-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/boost-cvs

Reply via email to