Index: dmake/dmake.c =================================================================== RCS file: /cvs/tools/dmake/dmake.c,v retrieving revision 1.5.2.4 diff -u -r1.5.2.4 dmake.c --- dmake/dmake.c 5 May 2005 21:45:39 -0000 1.5.2.4 +++ dmake/dmake.c 4 Sep 2005 19:18:21 -0000 @@ -169,6 +169,7 @@ m_export = FALSE; cmdmacs = NIL(char); targets = NIL(char); + Is_shell_exec = FALSE; Verbose = V_NOFLAG; Transitive = TRUE; Index: dmake/function.c =================================================================== RCS file: /cvs/tools/dmake/function.c,v retrieving revision 1.7.6.3 diff -u -r1.7.6.3 function.c --- dmake/function.c 1 Jun 2005 23:48:57 -0000 1.7.6.3 +++ dmake/function.c 4 Sep 2005 19:18:21 -0000 @@ -507,7 +507,9 @@ static char * -_exec_shell( data, mod1 ) +_exec_shell( data, mod1 )/* +=========================== + Capture the stdout of an execuded command. */ char *data; char *mod1; { @@ -520,6 +522,7 @@ static FILE *tmp; int wait = Wait_for_completion; + int old_is_shell_exec = Is_shell_exec; uint16 vflag = Verbose; int tflag = Trace; char *res = NIL(char); @@ -556,6 +559,9 @@ fflush(stdout); } + /* FIXME: This doesn't look right. Instead of using nestlevel and + * org_out as static variables this should be done as normal function + * calls that save and restore stdout. */ if( nestlevel == 0 ) { org_out = dup(1); @@ -569,7 +575,13 @@ buffer = MALLOC(bsize,char); } + /* As this function redirects the output of stdout we have to make sure + * that only this single command is executed. With Is_shell_exec and + * Wait_for_completion set this is realized. This is obviously a design + * weakness, if the client process would do the redirection the additional + * global variable would not be needed. */ Wait_for_completion = TRUE; + Is_shell_exec = TRUE; Verbose &= V_LEAVE_TMP; Trace = FALSE; nestlevel++; @@ -579,6 +591,7 @@ Trace = tflag; Verbose = vflag; Wait_for_completion = wait; + Is_shell_exec = old_is_shell_exec; /* Now we have to read the temporary file, get the tokens and return them * as a string. */ @@ -590,6 +603,9 @@ res = DmStrJoin(res,buffer,-1,TRUE); else { *p = '\0'; + /* You might encounter '\r\n' on windows, handle it. */ + if( p > buffer && *(p-1) == '\r') + *(p-1) = '\0'; res = DmStrApp(res,buffer); } } Index: dmake/sysintf.c =================================================================== RCS file: /cvs/tools/dmake/sysintf.c,v retrieving revision 1.6.2.3 diff -u -r1.6.2.3 sysintf.c --- dmake/sysintf.c 5 May 2005 21:27:21 -0000 1.6.2.3 +++ dmake/sysintf.c 4 Sep 2005 19:18:21 -0000 @@ -214,6 +214,7 @@ if( Max_proc == 1 ) Wait_for_completion = TRUE; if( (i = runargv(target, ignore, group, last, shell, cmd)) == -1 ) + /* Only fails for failed spawn. (Spawn is disabled ATM.) */ Quit(); /* NOTE: runargv must return either 0 or 1, 0 ==> command executed, and Index: dmake/vextern.h =================================================================== RCS file: /cvs/tools/dmake/vextern.h,v retrieving revision 1.1.1.1.132.2 diff -u -r1.1.1.1.132.2 vextern.h --- dmake/vextern.h 11 Apr 2005 03:28:54 -0000 1.1.1.1.132.2 +++ dmake/vextern.h 4 Sep 2005 19:18:21 -0000 @@ -74,7 +74,8 @@ EXTERN CELLPTR Targets; /* Targets in makefile */ EXTERN CELLPTR Current_target; /* cell of current target being made */ -EXTERN int Wait_for_completion; +EXTERN int Wait_for_completion; /* Wait for subprocess to finish */ +EXTERN int Is_shell_exec; /* Enable special child process handling */ EXTERN int Doing_bang; EXTERN int Packed_shell; /* TRUE if packed args to use a shell */ EXTERN int Swap_on_exec; /* TRUE if going to swap on exec call */ Index: dmake/unix/runargv.c =================================================================== RCS file: /cvs/tools/dmake/unix/runargv.c,v retrieving revision 1.8 diff -u -r1.8 runargv.c --- dmake/unix/runargv.c 8 Sep 2004 16:09:39 -0000 1.8 +++ dmake/unix/runargv.c 4 Sep 2005 19:18:22 -0000 @@ -24,6 +24,47 @@ -- LOG -- Use cvs log to obtain detailed change logs. */ +/* +This file (runargv.c) provides all the parallel process handling routines +for dmake on unix like operating systems. The following text briefly +describes the process flow. + +Exec_commands() [make.c] builds the recipes associated to the given target. + They are build sequentially in a loop that calls Do_cmnd() for each of them. + +Do_cmnd() [sysintf.c] feeds the given command or command group to runargv(). + +runargv() [unix/runargv] The actual child processes are started in this + function, even in non parallel builds (MAXPROCESS==1) child processes are + created. + If recipes for a target are currently running attach them to the process + queue (_procs[i]) of that target and return. + If the maximum number of running process queues is reached + Wait_for_child(?, -1) is used to wait for one to be available. + New child processes are started using: + spawn: currently disabled, see line 40. + fork/execvp: Create a client process with fork and run the command with + execvp. + The parent calls _add_child() to track the child. + +_add_child() [unix/runargv] creates a new process queue and enters the child + parameters. + If Wait_for_completion (global variable) is set the function calls + Wait_for_child to waits for the new process queue to be finished. + +Wait_for_child(?, pid) [unix/runargv] waits for process queues to finish. + All finished processes are handled by calling _finished_child() for each + of them. + If pid = -1 wait for the next child process to finish. + If Wait_for_completion is set handle all finished processes until the + process with the given pid is reached. + If Is_shell_exec (global variable) is set wait and handle only the given + pid. + +_finished_child(pid, ?) [unix/runargv] removes the finished child from its + process queue. If there are more commands in this queue start the next + with runargv(). +*/ #include #ifdef HAVE_WAIT_H @@ -185,7 +226,11 @@ waitchild = (pid == -1)? FALSE : Wait_for_completion; do { - wid = wait(&status); + if( Is_shell_exec ) /* For pid == -1 waitpid behaves like wait. */ + wid = waitpid(pid, &status, 0); + else + wid = wait(&status); + if( wid == -1 ) return(-1);