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