4 -- Invoke a sub process.
7 -- Use the standard methods of executing a sub process.
10 -- Dennis Vadura, dvadura@dmake.wticorp.com
13 -- http://dmake.wticorp.com/
16 -- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
18 -- This program is NOT free software; you can redistribute it and/or
19 -- modify it under the terms of the Software License Agreement Provided
20 -- in the file <distribution-root>/readme/license.txt.
23 -- Use cvs log to obtain detailed change logs.
26 This file (runargv.c) provides all the parallel process handling routines
27 for dmake on unix like operating systems. The following text briefly
28 describes the process flow.
30 Exec_commands() [make.c] builds the recipes associated to the given target.
31 They are build sequentially in a loop that calls Do_cmnd() for each of them.
33 Do_cmnd() [sysintf.c] feeds the given command or command group to runargv().
35 The following flowchart decripes the process flow starting with runargv,
36 descriptions for each of the functions are following.
38 +--------------------------------+
40 +--------------------------------+ |
43 | calls | wfc is false |
45 +--------------------------------+ |
47 +--------------------------------+ |
49 | calls if | | if another process
50 | wfc is true | returns | is queued:
52 +--------------------------------+ |
54 +--------------------------------+ |
59 +--------------------------------+ |
60 | _finished_child | -+
61 +--------------------------------+
65 runargv() [unix/runargv] The runargv function manages up to MAXPROCESS
66 process queues (_procs[i]) for parallel process execution and hands
67 the actual commands down to the operating system.
68 Each of the process queues handles the sequential execution of commands
69 that belong to that process queue. Usually this means the sequential
70 execution of the recipe lines that belong to one target.
71 Even in non parallel builds (MAXPROCESS==1) child processes are
73 If recipes for a target are currently running attach them to the
74 corresponding process queue (_procs[i]) of that target and return.
75 If the maximum number (MAXPROCESS) of concurrently running queues is
76 reached use Wait_for_child(?, -1) to wait for a process queue to become
78 New child processes are started using:
79 spawn: posix_spawnp (POSIX) or spawnvp (cygwin).
80 fork/execvp: Create a client process with fork and run the command
82 The parent calls _add_child() to track the child.
84 _add_child(..., wfc) [unix/runargv] creates (or reuses) a process queue
85 and enters the child's parameters.
86 If wfc (wait for completion) is TRUE the function calls
87 Wait_for_child to wait for the whole process queue to be finished.
89 Wait_for_child(abort_flg, pqid) [unix/runargv] waits either for the current
90 process from process queue pqid to finish or if the W_WFC attribute is
91 set for all entries of that process queue (recursively) to finish.
92 All finished processes are handled by calling _finished_child() for each
94 If pqid == -1 wait for the next process to finish but honor the A_WFC
95 attribute of that process (queue) and wait for the whole queue if needed.
96 If abort_flg is TRUE no further processes will be added to any process
98 If a pqid is given but a process from another process queue finishes
99 first that process is handled and A_WFC is also honored.
100 All finished processes are processed until the process from the given pqid
101 is reached or gone (might have been handled while finishing another process
104 _finished_child(pid, status) [unix/runargv] handles the finished child. If
105 there are more commands in the corresponding process queue start the next
116 # ifdef HAVE_SYS_WAIT_H
117 # include <sys/wait.h>
121 #if HAVE_SPAWN_H && ENABLE_SPAWN
125 #if __CYGWIN__ && ENABLE_SPAWN
126 #if HAVE_CYGWIN_PROCESS_H
127 # include <cygwin/process.h>
129 # include <process.h>
134 # include <process.h>
135 #define _P_NOWAIT P_NOWAIT
150 struct prp
*prp_next
;
153 #if defined(USE_CREATEPROCESS)
154 /* MS's HANDLE is basically a (void *) (winnt.h). */
155 typedef HANDLE DMHANDLE
;
157 typedef int DMHANDLE
;
169 RCPPTR pr_recipe_end
;
173 typedef struct tpid
{
178 const TPID DMNOPID
= { (DMHANDLE
)-1, (DMHANDLE
)0 };
180 static PR
*_procs
= NIL(PR
); /* Array to hold concurrent processes. */
181 static int _procs_size
= 0; /* Savegard to find MAXPROCESS changes. */
182 static int _proc_cnt
= 0; /* Number of running processes. */
183 static int _abort_flg
= FALSE
;
184 static int _use_i
= -1;
185 #if defined(USE_CREATEPROCESS)
186 static HANDLE
*_wpList
= NIL(HANDLE
); /* Array to hold pids to wait for. */
189 static int _add_child
ANSI((TPID
, CELLPTR
, int, int, int));
190 static void _attach_cmd
ANSI((char *, int, CELLPTR
, t_attr
, int));
191 static void _finished_child
ANSI((DMHANDLE
, int));
192 static int _running
ANSI((CELLPTR
));
194 /* Machine/OS dependent helpers. */
195 static int dmwaitnext
ANSI((DMHANDLE
*, int *));
196 static int dmwaitpid
ANSI((int, DMHANDLE
*, int *));
198 #if defined( USE_SPAWN )
200 int terrno
; /* Temporarily store errno. */
202 static TPID dmspawn
ANSI((char **));
210 /* No error output is done here as stdout/stderr might be redirected. */
211 #if defined( __CYGWIN__) || defined( __EMX__)
212 pid
.pid
= spawnvp(_P_NOWAIT
, argv
[0], (const char**) argv
);
214 #elif defined(USE_CREATEPROCESS)
215 static STARTUPINFO si
;
216 static int initSTARTUPINFO
= FALSE
;
217 PROCESS_INFORMATION pi
;
219 /* si can be reused. */
220 if( initSTARTUPINFO
== FALSE
) {
221 initSTARTUPINFO
= TRUE
;
222 ZeroMemory( &si
, sizeof(si
) );
225 ZeroMemory( &pi
, sizeof(pi
) );
227 /* Start the child process. CreateProcess() parameters:
228 * No module name (use command line).
229 * Command line. This fails if the path to the program contains spaces.
230 * Process handle not inheritable.
231 * Thread handle not inheritable.
232 * Set handle inheritance (stdout, stderr, etc.) to TRUE.
234 * Use parent's environment block.
235 * Use parent's starting directory.
236 * Pointer to STARTUPINFO structure.
237 * Pointer to PROCESS_INFORMATION structure. */
238 if( CreateProcess(NULL
, argv
[0], NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &si
, &pi
) ) {
239 pid
.pid
= pi
.hProcess
;
240 pid
.tid
= pi
.hThread
;
242 fprintf(stderr
, "CreateProcess failed (%d).\n", GetLastError() );
243 pid
.pid
= (DMHANDLE
)-1;
245 #else /* Non cygwin, OS/2, MinGW and MSC */
247 if (posix_spawnp (&tpid
, argv
[0], NULL
, NULL
, argv
, (char *)NULL
))
248 tpid
= -1; /* posix_spawn failed */
252 #endif /* __CYGWIN__ */
256 #endif /* USE_SPAWN */
259 dmwaitnext( wid
, status
)
260 DMHANDLE
*wid
; /* Id we waited for. */
261 int *status
; /* status of the finished process. */
262 /* return 1 if a process finished, -1 if there
263 * was nothing to wait for (ECHILD) and -2 for other errors. */
266 #if !defined(USE_CREATEPROCESS)
267 /* Here might be the culprit for the famous OOo build hang. If
268 * cygwin manages to "loose" a process and none else is left the
269 * wait() will wait forever. */
272 /* If ECHILD is set from waitpid/wait then no child was left. */
274 int realErr
= errno
; // fprintf can pollute errno
275 fprintf(stderr
, "%s: Internal Error: wait() failed: %d - %s\n",
276 Pname
, errno
, strerror(errno
) );
277 if( realErr
!= ECHILD
) {
278 /* Wait was interrupted or a child was terminated (SIGCHLD) */
292 /* Create a list of possible objects to wait for. */
293 for( i
=0; i
<Max_proc
; i
++ ) {
294 if(_procs
[i
].pr_valid
) {
295 _wpList
[numProc
++] = _procs
[i
].pr_pid
;
299 fprintf(stderr
, "%s: Internal Error: dmwaitnext() failed: "
300 "Nothing to wait for.\n", Pname
);
305 /* number of objects in array, array of objects,
306 * wait for any object, wait for the next child to finish */
307 pEvent
= WaitForMultipleObjects( numProc
, _wpList
, FALSE
, INFINITE
);
309 if( pEvent
>= 0 && pEvent
< WAIT_OBJECT_0
+ numProc
) {
310 *wid
= _wpList
[pEvent
- WAIT_OBJECT_0
];
311 for( i
=0; i
<Max_proc
&& _procs
[i
].pr_pid
!= *wid
; i
++ )
314 Fatal("Internal Error: Process not in pq !");
316 GetExitCodeProcess(*wid
, &dwExitCode
);
317 if(dwExitCode
== STILL_ACTIVE
) {
318 /* Process did not terminate -> force it, with exit code 1. */
319 TerminateProcess(*wid
, 1);
321 fprintf(stderr
, "%s: Internal Error: Process still running - "
322 "terminate it!\n", Pname
);
325 /* Close process and thread handles. */
327 CloseHandle( _procs
[i
].pr_tid
);
328 *status
= dwExitCode
;
331 int err
= GetLastError();
334 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
|
335 FORMAT_MESSAGE_FROM_SYSTEM
|
336 FORMAT_MESSAGE_IGNORE_INSERTS
,
339 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
343 fprintf(stderr
, "%s: Internal Error: WaitForMultipleObjects() (%d) failed:"
344 " %d - %s\n", Pname
, numProc
, err
, lpMsgBuf
);
347 /* No way to identify something comparable to ECHILD, always return -2.*/
357 dmwaitpid( pqid
, wid
, status
)
358 int pqid
; /* Process queue to wait for. */
359 DMHANDLE
*wid
; /* Id we waited for. */
360 int *status
; /* status of the finished process. */
361 /* return 1 if the process finished, 0 if it didn't finish yet, -1 if there
362 * was nothing to wait for (ECHILD) and -2 for other errors. */
365 #if !defined(USE_CREATEPROCESS)
366 *wid
= waitpid(_procs
[pqid
].pr_pid
, status
, WNOHANG
);
368 /* Process still running. */
373 /* If ECHILD is set from waitpid/wait then no child was left. */
375 int realErr
= errno
; // fprintf can pollute errno
376 fprintf(stderr
, "%s: Internal Error: waitpid() failed: %d - %s\n",
377 Pname
, errno
, strerror(errno
) );
378 if(realErr
!= ECHILD
) {
379 /* Wait was interrupted or a child was terminated (SIGCHLD) */
389 *wid
= _procs
[pqid
].pr_pid
;
392 /* Wait ... (Check status and return) */
393 pEvent
= WaitForSingleObject(*wid
, 0);
395 if( pEvent
== WAIT_OBJECT_0
) {
396 GetExitCodeProcess(*wid
, &dwExitCode
);
397 if(dwExitCode
== STILL_ACTIVE
) {
398 /* Process did not terminate -> force it, with exit code 1. */
399 TerminateProcess(*wid
, 1);
401 fprintf(stderr
, "%s: Internal Error: Process still running - "
402 "terminate it!\n", Pname
);
405 /* Close process and thread handles. */
407 CloseHandle( _procs
[pqid
].pr_tid
);
408 *status
= dwExitCode
;
410 else if( pEvent
== WAIT_TIMEOUT
) {
414 int err
= GetLastError();
417 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
|
418 FORMAT_MESSAGE_FROM_SYSTEM
|
419 FORMAT_MESSAGE_IGNORE_INSERTS
,
422 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
426 fprintf(stderr
, "%s: Internal Error: WaitForSingleObject() failed:"
427 " %d - %s\n", Pname
, err
, lpMsgBuf
);
430 /* No way to identify something comparable to ECHILD, always return -2.*/
441 private_strerror (errnum
)
445 # if defined(arm32) || defined(linux) || defined(__FreeBSD__) || \
446 defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
447 extern const char * const sys_errlist
[];
449 extern char *sys_errlist
[];
454 if (errnum
> 0 && errnum
<= sys_nerr
)
455 return sys_errlist
[errnum
];
456 return "Unknown system error";
458 #define strerror private_strerror
459 #endif /* HAVE_STRERROR */
462 runargv(target
, group
, last
, cmnd_attr
, cmd
)/*
463 ==============================================
464 Execute the command given by cmd.
466 Return 0 if the command executed and finished or
467 1 if the command started and is running.
472 t_attr cmnd_attr
; /* Attributes for current cmnd. */
473 char **cmd
; /* Simulate a reference to *cmd. */
475 int ignore
= (cmnd_attr
& A_IGNORE
)!= 0; /* Ignore errors ('-'). */
476 int shell
= (cmnd_attr
& A_SHELL
) != 0; /* Use shell ('+'). */
477 int mute
= (cmnd_attr
& A_MUTE
) != 0; /* Mute output ('@@'). */
478 int wfc
= (cmnd_attr
& A_WFC
) != 0; /* Wait for completion. */
481 int st_pq
= 0; /* Current _exec_shell target process index */
482 char *tcmd
= *cmd
; /* For saver/easier string arithmetic on *cmd. */
485 int old_stdout
= -1; /* For shell escapes and */
486 int old_stderr
= -1; /* @@-recipe silencing. */
487 int internal
= 0; /* Used to indicate internal command. */
489 DB_ENTER( "runargv" );
491 /* Special handling for the shell function macro is required. If the
492 * currend command is called as part of a shell escape in a recipe make
493 * sure that all previous recipe lines of this target have finished. */
494 if( Is_exec_shell
) {
495 if( (st_pq
= _running(Shell_exec_target
)) != -1 ) {
497 /* Add WFC to _procs[st_pq]. */
498 _procs
[st_pq
].pr_wfc
= TRUE
;
499 /* Set also the A_WFC flag in the recipe attributes. */
500 for( rp
= _procs
[st_pq
].pr_recipe
; rp
!= NIL(RCP
); rp
= rp
->prp_next
)
501 rp
->prp_attr
|= A_WFC
;
503 Wait_for_child(FALSE
, st_pq
);
506 if( _running(target
) != -1 /*&& Max_proc != 1*/ ) {
507 /* The command will be executed when the previous recipe
509 _attach_cmd( *cmd
, group
, target
, cmnd_attr
, last
);
514 /* If all process array entries are used wait until we get a free
515 * slot. For Max_proc == 1 this forces sequential execution. */
516 while( _proc_cnt
== Max_proc
) {
517 Wait_for_child(FALSE
, -1);
520 /* Return immediately for empty line or noop command. */
521 if ( !*tcmd
|| /* empty line */
522 ( strncmp(tcmd
, "noop", 4) == 0 && /* noop command */
523 (iswhite(tcmd
[4]) || tcmd
[4] == '\0')) ) {
526 else if( !shell
&& /* internal echo only if not in shell */
527 strncmp(tcmd
, "echo", 4) == 0 &&
528 (iswhite(tcmd
[4]) || tcmd
[4] == '\0') ) {
532 while( iswhite(*tcmd
) ) ++tcmd
;
533 if ( strncmp(tcmd
,"-n",2 ) == 0) {
536 while( iswhite(*tcmd
) ) ++tcmd
;
539 /* redirect output for _exec_shell / @@-recipes. */
540 if( Is_exec_shell
) {
541 /* Add error checking? */
543 dup2( fileno(stdout_redir
), 1 );
549 if( !Is_exec_shell
) {
555 printf("%s%s", tcmd
, nl
? "\n" : "");
558 /* Restore stdout/stderr if needed. */
559 if( old_stdout
!= -1 ) {
562 if( old_stderr
!= -1 ) {
571 /* Use _add_child() / _finished_child() with internal command. */
572 int cur_proc
= _add_child(DMNOPID
, target
, ignore
, last
, FALSE
);
573 _finished_child( (DMHANDLE
)-cur_proc
, 0 );
577 /* Pack cmd in argument vector. */
578 argv
= Pack_argv( group
, shell
, cmd
);
580 /* Really spawn or fork a child. */
581 #if defined( USE_SPAWN )
582 /* As no other children are started while the output is redirected this
584 if( Is_exec_shell
) {
585 /* Add error checking? */
587 dup2( fileno(stdout_redir
), 1 );
593 if( !Is_exec_shell
) {
599 pid
= dmspawn( argv
);
602 if( old_stdout
!= -1 ) {
605 if( old_stderr
!= -1 ) {
610 if(pid
.pid
== (DMHANDLE
)-1) {
614 fprintf(stderr
, "%s: Error executing '%s': %s",
615 Pname
, argv
[0], strerror(terrno
) );
616 if( ignore
||Continue
) {
617 fprintf(stderr
, " (Ignored)" );
619 fprintf(stderr
, "\n");
621 /* Use _add_child() / _finished_child() to treat the failure
622 * gracefully, if so requested. */
623 cur_proc
= _add_child(DMNOPID
, target
, ignore
, last
, FALSE
);
624 _finished_child((DMHANDLE
)cur_proc
, SIGTERM
);
626 /* _finished_child() aborts dmake if we are not told to
627 * ignore errors. If we reach the this point return 0 as
628 * errors are obviously ignored and indicate that the process
632 _add_child(pid
, target
, ignore
, last
, wfc
);
634 #else /* USE_SPAWN */
637 switch( pid
.pid
= fork() ){
639 case -1: /* fork failed */
640 Fatal("fork failed: %s: %s", argv
[0], strerror( errno
));
643 /* redirect output for _exec_shell / @@-recipes. */
644 if( Is_exec_shell
) {
645 /* Add error checking? */
647 dup2( fileno(stdout_redir
), 1 );
653 if( !Is_exec_shell
) {
658 execvp(argv
[0], argv
);
659 /* restoring output to catch potential error output if execvp()
661 if( old_stdout
!= -1 ) {
664 if( old_stderr
!= -1 ) {
669 fprintf(stderr
, "%s: Error executing '%s': %s",
670 Pname
, argv
[0], strerror(errno
) );
671 if( ignore
||Continue
) {
672 fprintf(stderr
, " (Ignored)" );
674 fprintf(stderr
, "\n");
676 kill(getpid(), SIGTERM
);
678 Fatal("\nInternal Error - kill could't kill child %d.\n", getpid());
680 default: /* parent */
681 _add_child(pid
, target
, ignore
, last
, wfc
);
684 #endif /* USE_SPAWN */
686 /* If wfc is set this command must have been finished. */
696 Wait_for_child( abort_flg
, pqid
)/*
697 ===================================
698 Wait for the next processes from process queue pqid to finish. All finished
699 processes are handled by calling _finished_child() for each of them.
700 If pqid == -1 wait for the next process to finish.
701 If abort_flg is TRUE no further processes will be added to any process
702 queue. The A_WFC attribute is honored, see the documentation at the top
704 Return 0 if we successfully waited for a process and -1 if there was nothing
713 int waitret
; /* return value of the dmwait functions. */
714 /* Never wait for internal commands. */
716 int is_exec_shell_status
= Is_exec_shell
;
719 /* No process was ever created, i.e. _procs is not yet initialized.
720 * Nothing to wait for. */
724 if( pqid
> Max_proc
) Fatal("Internal Error: pqid > Max_proc !");
727 /* Check if there is something to wait for. */
729 for( i
=0; i
<Max_proc
&& !_procs
[i
].pr_valid
; i
++ )
738 /* Check if pqid is active. */
739 if( !_procs
[pqid
].pr_valid
) {
740 /* Make this an error? */
741 Warning("Internal Warning: pqid is not active!?");
745 pid
= _procs
[pqid
].pr_pid
;
746 waitchild
= _procs
[pqid
].pr_wfc
;
750 /* It is impossible that processes that were started from _exec_shell
751 * have follow-up commands in its process entry. Unset Is_exec_shell
752 * to prevent piping of child processes that are started from the
753 * _finished_child subroutine and reset to its original value when
754 * leaving this function. */
755 Is_exec_shell
= FALSE
;
758 /* Wait for the next process to finish. */
759 if( (pid
!= (DMHANDLE
)-1) && (waitret
= dmwaitpid(pqid
, &wid
, &status
)) != 0 ) {
760 /* if dmwaitpid returns 0 this means that pid didn't finish yet.
761 * In this case just handle the next finished process in the
762 * following "else". If an error is returned (waitret < 0) the else
763 * clause is not evaluated and the error is handled in the following
764 * lines. If a process was waited for (waitret == 0) also proceed to
765 * the following lines. */
769 waitret
= dmwaitnext(&wid
, &status
);
770 /* If we get an error tell the error handling routine below that we
771 * were not waiting for a specific pid. */
777 /* If ECHILD is set from waitpid/wait then no child was left. */
780 /* Wait was interrupted or a child was terminated (SIGCHLD) */
782 /* We're already terminating, just continue. */
785 Fatal( "dmake was interrupted or a child terminated. "
786 "Stopping all children ..." );
789 /* The child we were waiting for is missing or no child is
790 * left to wait for. */
791 if( pid
!= (DMHANDLE
)-1 ) {
792 /* If we know the pid disable the pq entry. */
793 if( _procs
[pqid
].pr_valid
) {
794 _procs
[pqid
].pr_valid
= 0;
795 _procs
[pqid
].pr_recipe
= NIL(RCP
);
799 /* otherwise disable all remaining pq's. As we don't know
800 * which pid failed there is no gracefull way to terminate. */
802 for( i
=0; i
<Max_proc
; i
++ ) {
803 _procs
[i
].pr_valid
= 0;
804 _procs
[i
].pr_recipe
= NIL(RCP
);
808 /* The pid we were waiting for or any of the remaining children
809 * (pid == -1) is missing. This should not happen and means
810 * that the process got lost or was treated elsewhere. */
811 Fatal( "Internal Error: Child is missing but still listed in _procs[x] %d: %s\n"
812 "\nTemporary or .ERRREMOVE targets might not have been removed!\n",
813 errno
, strerror( errno
) );
817 _abort_flg
= abort_flg
;
818 _finished_child(wid
, status
);
821 /* If pid != wid the process we're waiting for might have been
822 * finished from a "Wait_for_child(FALSE, -1)" call from
823 * _finished_child() -> runargv(). */
825 if( !_procs
[pqid
].pr_valid
|| _procs
[pqid
].pr_pid
!= pid
) {
826 /* Someone finished pid, no need to wait further. */
831 /* We finished pid, no need to wait further. */
837 Is_exec_shell
= is_exec_shell_status
;
845 if( _procs
!= NIL(PR
) )
848 for( i
=0; i
<Max_proc
; i
++ )
849 if( _procs
[i
].pr_valid
)
851 #if !defined(USE_CREATEPROCESS)
853 if( (ret
= kill(_procs
[i
].pr_pid
, SIGTERM
)) )
855 fprintf(stderr
, "Killing of pid %d from pq[%d] failed with: %s - %d ret: %d\n",
856 _procs
[i
].pr_pid
, i
, strerror(errno
), SIGTERM
, ret
);
859 TerminateProcess(_procs
[i
].pr_pid
, 1);
867 _add_child( pid
, target
, ignore
, last
, wfc
)/*
868 ==============================================
869 Creates/amend a process queue entry and enters the child parameters.
870 The pid == -1 represents an internal command and the function returns
871 the used process array index. For non-internal commands the function
873 If wfc (wait for completion) is TRUE the function calls
874 Wait_for_child to wait for the whole process queue to be finished.
885 /* Never change MAXPROCESS after _procs is allocated. */
886 if( _procs_size
!= Max_proc
) {
887 /* If procs was never initialize this is OK, do it now. */
888 if( _procs
== NIL(PR
) ) {
889 _procs_size
= Max_proc
;
890 TALLOC( _procs
, Max_proc
, PR
);
891 #if defined(USE_CREATEPROCESS)
892 TALLOC( _wpList
, Max_proc
, HANDLE
);
894 /* Signed int values are cast to DMHANDLE in various places, use this
895 * sanity check to verify that DMHANDLE is large enough. */
896 if( sizeof(int) > sizeof(DMHANDLE
) )
897 Fatal( "Internal Error: Check type of DMHANDLE!" );
901 Fatal( "MAXPROCESS changed from `%d' to `%d' after a command was executed!", _procs_size
, Max_proc
);
905 if( Measure
& M_RECIPE
)
906 Do_profile_output( "s", M_RECIPE
, target
);
908 /* If _use_i ! =-1 then this function is called by _finished_child() ( through runargv() ),
909 and we re-use the process queue number given by _use_i. */
910 if( (i
= _use_i
) == -1 ) {
911 for( i
=0; i
<Max_proc
; i
++ )
912 if( !_procs
[i
].pr_valid
)
919 pp
->pr_pid
= pid
.pid
;
920 pp
->pr_tid
= pid
.tid
;
921 pp
->pr_target
= target
;
922 pp
->pr_ignore
= ignore
;
926 if( pp
->pr_dir
!= NIL(char) )
928 pp
->pr_dir
= DmStrDup(Get_current_dir());
930 Current_target
= NIL(CELL
);
934 if( pid
.pid
!= (DMHANDLE
)-1 ) {
935 /* Wait for each recipe to finish if wfc is TRUE. This
936 * basically forces sequential execution. */
938 Wait_for_child( FALSE
, i
);
948 _finished_child(cid
, status
)/*
949 ==============================
950 Handle process array entry for finished child. This can be a finished
951 process or a finished internal command depending on the content of cid.
952 For cid >= 1 the value of cid is used as the pid to of the finished
953 process and for cid < 1 -cid is used as the process array index of the
962 if((int)cid
< 1) { /* Force int. */
963 /* internal command */
967 for( i
=0; i
<Max_proc
; i
++ )
968 if( _procs
[i
].pr_valid
&& _procs
[i
].pr_pid
== cid
)
971 /* Some children we didn't make esp true if using /bin/sh to execute a
972 * a pipe and feed the output as a makefile into dmake. */
973 if( i
== Max_proc
) {
974 Warning("Internal Warning: finished pid %d is not in pq!?", cid
);
979 /* Not a running process anymore, the next runargv() will not use
981 _procs
[i
].pr_valid
= 0;
983 if( Measure
& M_RECIPE
)
984 Do_profile_output( "e", M_RECIPE
, _procs
[i
].pr_target
);
987 dir
= DmStrDup(Get_current_dir());
988 Set_dir( _procs
[i
].pr_dir
);
990 if( _procs
[i
].pr_recipe
!= NIL(RCP
) && !_abort_flg
) {
991 RCPPTR rp
= _procs
[i
].pr_recipe
;
994 Current_target
= _procs
[i
].pr_target
;
995 Handle_result( status
, _procs
[i
].pr_ignore
, FALSE
, _procs
[i
].pr_target
);
996 Current_target
= NIL(CELL
);
998 if ( _procs
[i
].pr_target
->ce_attr
& A_ERROR
) {
999 _procs
[i
].pr_last
= TRUE
;
1000 goto ABORT_REMAINDER_OF_RECIPE
;
1003 _procs
[i
].pr_recipe
= rp
->prp_next
;
1006 /* Run next recipe line. The rp->prp_attr propagates a possible
1008 runargv( _procs
[i
].pr_target
, rp
->prp_group
,
1009 rp
->prp_last
, rp
->prp_attr
, &rp
->prp_cmd
);
1012 FREE( rp
->prp_cmd
);
1015 /* If all process queues are used wait for the next process to
1016 * finish. Is this really needed here? */
1017 if( _proc_cnt
== Max_proc
) {
1018 Wait_for_child( FALSE
, -1 );
1022 /* empty the queue on abort. */
1024 _procs
[i
].pr_recipe
= NIL(RCP
);
1026 Handle_result(status
,_procs
[i
].pr_ignore
,_abort_flg
,_procs
[i
].pr_target
);
1028 ABORT_REMAINDER_OF_RECIPE
:
1029 if( _procs
[i
].pr_last
) {
1030 FREE(_procs
[i
].pr_dir
); _procs
[i
].pr_dir
= NIL(char); /* Set in _add_child() */
1033 /* Update_time_stamp() triggers the deletion of intermediate
1034 * targets. This starts a new process queue, so we have to
1035 * clear the _use_i variable. */
1036 int my_use_i
= _use_i
;
1039 Update_time_stamp( _procs
[i
].pr_target
);
1053 Check if target exists in process array AND is running. Return its
1054 process array index if it is running, return -1 otherwise.
1060 if( !_procs
) return( -1 );
1062 for( i
=0; i
<Max_proc
; i
++ )
1063 if( _procs
[i
].pr_valid
&&
1064 _procs
[i
].pr_target
== cp
)
1067 return( i
== Max_proc
? -1 : i
);
1072 _attach_cmd( cmd
, group
, cp
, cmnd_attr
, last
)/*
1073 ================================================
1074 Attach to an active process queue. Inherit wfc setting. */
1084 for( i
=0; i
<Max_proc
; i
++ )
1085 if( _procs
[i
].pr_valid
&&
1086 _procs
[i
].pr_target
== cp
)
1089 TALLOC( rp
, 1, RCP
);
1090 rp
->prp_cmd
= DmStrDup(cmd
);
1091 rp
->prp_attr
= cmnd_attr
;
1092 /* Inherit wfc from process queue. */
1093 if( _procs
[i
].pr_wfc
)
1094 rp
->prp_attr
|= A_WFC
;
1095 rp
->prp_group
= group
;
1096 rp
->prp_last
= last
;
1098 if( _procs
[i
].pr_recipe
== NIL(RCP
) )
1099 _procs
[i
].pr_recipe
= _procs
[i
].pr_recipe_end
= rp
;
1101 _procs
[i
].pr_recipe_end
->prp_next
= rp
;
1102 _procs
[i
].pr_recipe_end
= rp
;