1 /* $RCSfile: runargv.c,v $
3 -- last change: $Author: kz $ $Date: 2008-03-05 18:39:41 $
6 -- Invoke a sub process.
9 -- Use the standard methods of executing a sub process.
12 -- Dennis Vadura, dvadura@dmake.wticorp.com
15 -- http://dmake.wticorp.com/
18 -- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
20 -- This program is NOT free software; you can redistribute it and/or
21 -- modify it under the terms of the Software License Agreement Provided
22 -- in the file <distribution-root>/readme/license.txt.
25 -- Use cvs log to obtain detailed change logs.
28 This file (runargv.c) provides all the parallel process handling routines
29 for dmake on unix like operating systems. The following text briefly
30 describes the process flow.
32 Exec_commands() [make.c] builds the recipes associated to the given target.
33 They are build sequentially in a loop that calls Do_cmnd() for each of them.
35 Do_cmnd() [sysintf.c] feeds the given command or command group to runargv().
37 The following flowchart decripes the process flow starting with runargv,
38 descriptions for each of the functions are following.
40 +--------------------------------+
42 +--------------------------------+ |
45 | calls | wfc is false |
47 +--------------------------------+ |
49 +--------------------------------+ |
51 | calls if | | if another process
52 | wfc is true | returns | is queued:
54 +--------------------------------+ |
56 +--------------------------------+ |
61 +--------------------------------+ |
62 | _finished_child | -+
63 +--------------------------------+
67 runargv() [unix/runargv] The runargv function manages up to MAXPROCESS
68 process queues (_procs[i]) for parallel process execution and hands
69 the actual commands down to the operating system.
70 Each of the process queues handles the sequential execution of commands
71 that belong to that process queue. Usually this means the sequential
72 execution of the recipe lines that belong to one target.
73 Even in non parallel builds (MAXPROCESS==1) child processes are
75 If recipes for a target are currently running attach them to the
76 corresponding process queue (_procs[i]) of that target and return.
77 If the maximum number (MAXPROCESS) of concurrently running queues is
78 reached use Wait_for_child(?, -1) to wait for a process queue to become
80 New child processes are started using:
81 spawn: posix_spawnp (POSIX) or spawnvp (cygwin).
82 fork/execvp: Create a client process with fork and run the command
84 The parent calls _add_child() to track the child.
86 _add_child(..., wfc) [unix/runargv] creates (or reuses) a process queue
87 and enters the child's parameters.
88 If wfc (wait for completion) is TRUE the function calls
89 Wait_for_child to wait for the whole process queue to be finished.
91 Wait_for_child(abort_flg, pqid) [unix/runargv] waits either for the current
92 process from process queue pqid to finish or if the W_WFC attribute is
93 set for all entries of that process queue (recursively) to finish.
94 All finished processes are handled by calling _finished_child() for each
96 If pqid == -1 wait for the next process to finish but honor the A_WFC
97 attribute of that process (queue) and wait for the whole queue if needed.
98 If abort_flg is TRUE no further processes will be added to any process
100 If a pqid is given but a process from another process queue finishes
101 first that process is handled and A_WFC is also honored.
102 All finished processes are processed until the process from the given pqid
103 is reached or gone (might have been handled while finishing another process
106 _finished_child(pid, status) [unix/runargv] handles the finished child. If
107 there are more commands in the corresponding process queue start the next
118 # ifdef HAVE_SYS_WAIT_H
119 # include <sys/wait.h>
123 #if HAVE_SPAWN_H && ENABLE_SPAWN
127 #if __CYGWIN__ && ENABLE_SPAWN
128 # include <process.h>
132 # include <process.h>
133 #define _P_NOWAIT P_NOWAIT
148 struct prp
*prp_next
;
151 #if defined(USE_CREATEPROCESS)
152 /* MS's HANDLE is basically a (void *) (winnt.h). */
153 typedef HANDLE DMHANDLE
;
155 typedef int DMHANDLE
;
167 RCPPTR pr_recipe_end
;
171 typedef struct tpid
{
176 const TPID DMNOPID
= { (DMHANDLE
)-1, (DMHANDLE
)0 };
178 static PR
*_procs
= NIL(PR
); /* Array to hold concurrent processes. */
179 static int _procs_size
= 0; /* Savegard to find MAXPROCESS changes. */
180 static int _proc_cnt
= 0; /* Number of running processes. */
181 static int _abort_flg
= FALSE
;
182 static int _use_i
= -1;
183 #if defined(USE_CREATEPROCESS)
184 static HANDLE
*_wpList
= NIL(HANDLE
); /* Array to hold pids to wait for. */
187 static int _add_child
ANSI((TPID
, CELLPTR
, int, int, int));
188 static void _attach_cmd
ANSI((char *, int, CELLPTR
, t_attr
, int));
189 static void _finished_child
ANSI((DMHANDLE
, int));
190 static int _running
ANSI((CELLPTR
));
192 /* Machine/OS dependent helpers. */
193 static int dmwaitnext
ANSI((DMHANDLE
*, int *));
194 static int dmwaitpid
ANSI((int, DMHANDLE
*, int *));
196 #if defined( USE_SPAWN )
198 int terrno
; /* Temporarily store errno. */
200 static TPID dmspawn
ANSI((char **));
208 /* No error output is done here as stdout/stderr might be redirected. */
209 #if defined( __CYGWIN__) || defined( __EMX__)
210 pid
.pid
= spawnvp(_P_NOWAIT
, argv
[0], (const char**) argv
);
212 #elif defined(USE_CREATEPROCESS)
213 static STARTUPINFO si
;
214 static int initSTARTUPINFO
= FALSE
;
215 PROCESS_INFORMATION pi
;
217 /* si can be reused. */
218 if( initSTARTUPINFO
== FALSE
) {
219 initSTARTUPINFO
= TRUE
;
220 ZeroMemory( &si
, sizeof(si
) );
223 ZeroMemory( &pi
, sizeof(pi
) );
225 /* Start the child process. CreateProcess() parameters:
226 * No module name (use command line).
227 * Command line. This fails if the path to the program contains spaces.
228 * Process handle not inheritable.
229 * Thread handle not inheritable.
230 * Set handle inheritance (stdout, stderr, etc.) to TRUE.
232 * Use parent's environment block.
233 * Use parent's starting directory.
234 * Pointer to STARTUPINFO structure.
235 * Pointer to PROCESS_INFORMATION structure. */
236 if( CreateProcess(NULL
, argv
[0], NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &si
, &pi
) ) {
237 pid
.pid
= pi
.hProcess
;
238 pid
.tid
= pi
.hThread
;
240 fprintf(stderr
, "CreateProcess failed (%d).\n", GetLastError() );
241 pid
.pid
= (DMHANDLE
)-1;
243 #else /* Non cygwin, OS/2, MinGW and MSC */
245 if (posix_spawnp (&tpid
, argv
[0], NULL
, NULL
, argv
, (char *)NULL
))
246 tpid
= -1; /* posix_spawn failed */
250 #endif /* __CYGWIN__ */
254 #endif /* USE_SPAWN */
257 dmwaitnext( wid
, status
)
258 DMHANDLE
*wid
; /* Id we waited for. */
259 int *status
; /* status of the finished process. */
260 /* return 1 if a process finished, -1 if there
261 * was nothing to wait for (ECHILD) and -2 for other errors. */
264 #if !defined(USE_CREATEPROCESS)
265 /* Here might be the culprit for the famous OOo build hang. If
266 * cygwin manages to "loose" a process and none else is left the
267 * wait() will wait forever. */
270 /* If ECHILD is set from waitpid/wait then no child was left. */
272 int realErr
= errno
; // fprintf can pollute errno
273 fprintf(stderr
, "%s: Internal Error: wait() failed: %d - %s\n",
274 Pname
, errno
, strerror(errno
) );
275 if( realErr
!= ECHILD
) {
276 /* Wait was interrupted or a child was terminated (SIGCHLD) */
290 /* Create a list of possible objects to wait for. */
291 for( i
=0; i
<Max_proc
; i
++ ) {
292 if(_procs
[i
].pr_valid
) {
293 _wpList
[numProc
++] = _procs
[i
].pr_pid
;
297 fprintf(stderr
, "%s: Internal Error: dmwaitnext() failed: "
298 "Nothing to wait for.\n", Pname
);
303 /* number of objects in array, array of objects,
304 * wait for any object, wait for the next child to finish */
305 pEvent
= WaitForMultipleObjects( numProc
, _wpList
, FALSE
, INFINITE
);
307 if( pEvent
>= 0 && pEvent
< WAIT_OBJECT_0
+ numProc
) {
308 *wid
= _wpList
[pEvent
- WAIT_OBJECT_0
];
309 for( i
=0; i
<Max_proc
&& _procs
[i
].pr_pid
!= *wid
; i
++ )
312 Fatal("Internal Error: Process not in pq !");
314 GetExitCodeProcess(*wid
, &dwExitCode
);
315 if(dwExitCode
== STILL_ACTIVE
) {
316 /* Process did not terminate -> force it, with exit code 1. */
317 TerminateProcess(*wid
, 1);
319 fprintf(stderr
, "%s: Internal Error: Process still running - "
320 "terminate it!\n", Pname
);
323 /* Close process and thread handles. */
325 CloseHandle( _procs
[i
].pr_tid
);
326 *status
= dwExitCode
;
329 int err
= GetLastError();
332 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
|
333 FORMAT_MESSAGE_FROM_SYSTEM
|
334 FORMAT_MESSAGE_IGNORE_INSERTS
,
337 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
341 fprintf(stderr
, "%s: Internal Error: WaitForMultipleObjects() (%d) failed:"
342 " %d - %s\n", Pname
, numProc
, err
, lpMsgBuf
);
345 /* No way to identify something comparable to ECHILD, always return -2.*/
355 dmwaitpid( pqid
, wid
, status
)
356 int pqid
; /* Process queue to wait for. */
357 DMHANDLE
*wid
; /* Id we waited for. */
358 int *status
; /* status of the finished process. */
359 /* return 1 if the process finished, 0 if it didn't finish yet, -1 if there
360 * was nothing to wait for (ECHILD) and -2 for other errors. */
363 #if !defined(USE_CREATEPROCESS)
364 *wid
= waitpid(_procs
[pqid
].pr_pid
, status
, WNOHANG
);
366 /* Process still running. */
371 /* If ECHILD is set from waitpid/wait then no child was left. */
373 int realErr
= errno
; // fprintf can pollute errno
374 fprintf(stderr
, "%s: Internal Error: waitpid() failed: %d - %s\n",
375 Pname
, errno
, strerror(errno
) );
376 if(realErr
!= ECHILD
) {
377 /* Wait was interrupted or a child was terminated (SIGCHLD) */
387 *wid
= _procs
[pqid
].pr_pid
;
390 /* Wait ... (Check status and return) */
391 pEvent
= WaitForSingleObject(*wid
, 0);
393 if( pEvent
== WAIT_OBJECT_0
) {
394 GetExitCodeProcess(*wid
, &dwExitCode
);
395 if(dwExitCode
== STILL_ACTIVE
) {
396 /* Process did not terminate -> force it, with exit code 1. */
397 TerminateProcess(*wid
, 1);
399 fprintf(stderr
, "%s: Internal Error: Process still running - "
400 "terminate it!\n", Pname
);
403 /* Close process and thread handles. */
405 CloseHandle( _procs
[pqid
].pr_tid
);
406 *status
= dwExitCode
;
408 else if( pEvent
== WAIT_TIMEOUT
) {
412 int err
= GetLastError();
415 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
|
416 FORMAT_MESSAGE_FROM_SYSTEM
|
417 FORMAT_MESSAGE_IGNORE_INSERTS
,
420 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
424 fprintf(stderr
, "%s: Internal Error: WaitForSingleObject() failed:"
425 " %d - %s\n", Pname
, err
, lpMsgBuf
);
428 /* No way to identify something comparable to ECHILD, always return -2.*/
439 private_strerror (errnum
)
443 # if defined(arm32) || defined(linux) || defined(__FreeBSD__) || \
444 defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
445 extern const char * const sys_errlist
[];
447 extern char *sys_errlist
[];
452 if (errnum
> 0 && errnum
<= sys_nerr
)
453 return sys_errlist
[errnum
];
454 return "Unknown system error";
456 #define strerror private_strerror
457 #endif /* HAVE_STRERROR */
460 runargv(target
, group
, last
, cmnd_attr
, cmd
)/*
461 ==============================================
462 Execute the command given by cmd.
464 Return 0 if the command executed and finished or
465 1 if the command started and is running.
470 t_attr cmnd_attr
; /* Attributes for current cmnd. */
471 char **cmd
; /* Simulate a reference to *cmd. */
473 int ignore
= (cmnd_attr
& A_IGNORE
)!= 0; /* Ignore errors ('-'). */
474 int shell
= (cmnd_attr
& A_SHELL
) != 0; /* Use shell ('+'). */
475 int mute
= (cmnd_attr
& A_MUTE
) != 0; /* Mute output ('@@'). */
476 int wfc
= (cmnd_attr
& A_WFC
) != 0; /* Wait for completion. */
479 int st_pq
= 0; /* Current _exec_shell target process index */
480 char *tcmd
= *cmd
; /* For saver/easier string arithmetic on *cmd. */
483 int old_stdout
= -1; /* For shell escapes and */
484 int old_stderr
= -1; /* @@-recipe silencing. */
485 int internal
= 0; /* Used to indicate internal command. */
487 DB_ENTER( "runargv" );
489 /* Special handling for the shell function macro is required. If the
490 * currend command is called as part of a shell escape in a recipe make
491 * sure that all previous recipe lines of this target have finished. */
492 if( Is_exec_shell
) {
493 if( (st_pq
= _running(Shell_exec_target
)) != -1 ) {
495 /* Add WFC to _procs[st_pq]. */
496 _procs
[st_pq
].pr_wfc
= TRUE
;
497 /* Set also the A_WFC flag in the recipe attributes. */
498 for( rp
= _procs
[st_pq
].pr_recipe
; rp
!= NIL(RCP
); rp
= rp
->prp_next
)
499 rp
->prp_attr
|= A_WFC
;
501 Wait_for_child(FALSE
, st_pq
);
504 if( _running(target
) != -1 /*&& Max_proc != 1*/ ) {
505 /* The command will be executed when the previous recipe
507 _attach_cmd( *cmd
, group
, target
, cmnd_attr
, last
);
512 /* If all process array entries are used wait until we get a free
513 * slot. For Max_proc == 1 this forces sequential execution. */
514 while( _proc_cnt
== Max_proc
) {
515 Wait_for_child(FALSE
, -1);
518 /* Return immediately for empty line or noop command. */
519 if ( !*tcmd
|| /* empty line */
520 ( strncmp(tcmd
, "noop", 4) == 0 && /* noop command */
521 (iswhite(tcmd
[4]) || tcmd
[4] == '\0')) ) {
524 else if( !shell
&& /* internal echo only if not in shell */
525 strncmp(tcmd
, "echo", 4) == 0 &&
526 (iswhite(tcmd
[4]) || tcmd
[4] == '\0') ) {
530 while( iswhite(*tcmd
) ) ++tcmd
;
531 if ( strncmp(tcmd
,"-n",2 ) == 0) {
534 while( iswhite(*tcmd
) ) ++tcmd
;
537 /* redirect output for _exec_shell / @@-recipes. */
538 if( Is_exec_shell
) {
539 /* Add error checking? */
541 dup2( fileno(stdout_redir
), 1 );
547 if( !Is_exec_shell
) {
553 printf("%s%s", tcmd
, nl
? "\n" : "");
556 /* Restore stdout/stderr if needed. */
557 if( old_stdout
!= -1 ) {
560 if( old_stderr
!= -1 ) {
569 /* Use _add_child() / _finished_child() with internal command. */
570 int cur_proc
= _add_child(DMNOPID
, target
, ignore
, last
, FALSE
);
571 _finished_child( (DMHANDLE
)-cur_proc
, 0 );
575 /* Pack cmd in argument vector. */
576 argv
= Pack_argv( group
, shell
, cmd
);
578 /* Really spawn or fork a child. */
579 #if defined( USE_SPAWN )
580 /* As no other childs are started while the output is redirected this
582 if( Is_exec_shell
) {
583 /* Add error checking? */
585 dup2( fileno(stdout_redir
), 1 );
591 if( !Is_exec_shell
) {
597 pid
= dmspawn( argv
);
600 if( old_stdout
!= -1 ) {
603 if( old_stderr
!= -1 ) {
608 if(pid
.pid
== (DMHANDLE
)-1) {
612 fprintf(stderr
, "%s: Error executing '%s': %s",
613 Pname
, argv
[0], strerror(terrno
) );
614 if( ignore
||Continue
) {
615 fprintf(stderr
, " (Ignored)" );
617 fprintf(stderr
, "\n");
619 /* Use _add_child() / _finished_child() to treat the failure
620 * gracefully, if so requested. */
621 cur_proc
= _add_child(DMNOPID
, target
, ignore
, last
, FALSE
);
622 _finished_child((DMHANDLE
)cur_proc
, SIGTERM
);
624 /* _finished_child() aborts dmake if we are not told to
625 * ignore errors. If we reach the this point return 0 as
626 * errors are obviously ignored and indicate that the process
630 _add_child(pid
, target
, ignore
, last
, wfc
);
632 #else /* USE_SPAWN */
635 switch( pid
.pid
= fork() ){
637 case -1: /* fork failed */
638 Fatal("fork failed: %s: %s", argv
[0], strerror( errno
));
641 /* redirect output for _exec_shell / @@-recipes. */
642 if( Is_exec_shell
) {
643 /* Add error checking? */
645 dup2( fileno(stdout_redir
), 1 );
651 if( !Is_exec_shell
) {
656 execvp(argv
[0], argv
);
657 /* restoring output to catch potential error output if execvp()
659 if( old_stdout
!= -1 ) {
662 if( old_stderr
!= -1 ) {
667 fprintf(stderr
, "%s: Error executing '%s': %s",
668 Pname
, argv
[0], strerror(errno
) );
669 if( ignore
||Continue
) {
670 fprintf(stderr
, " (Ignored)" );
672 fprintf(stderr
, "\n");
674 kill(getpid(), SIGTERM
);
676 Fatal("\nInternal Error - kill could't kill child %d.\n", getpid());
678 default: /* parent */
679 _add_child(pid
, target
, ignore
, last
, wfc
);
682 #endif /* USE_SPAWN */
684 /* If wfc is set this command must have been finished. */
694 Wait_for_child( abort_flg
, pqid
)/*
695 ===================================
696 Wait for the next processes from process queue pqid to finish. All finished
697 processes are handled by calling _finished_child() for each of them.
698 If pqid == -1 wait for the next process to finish.
699 If abort_flg is TRUE no further processes will be added to any process
700 queue. The A_WFC attribute is honored, see the documentation at the top
702 Return 0 if we successfully waited for a process and -1 if there was nothing
711 int waitret
; /* return value of the dmwait functions. */
712 /* Never wait for internal commands. */
714 int is_exec_shell_status
= Is_exec_shell
;
717 /* No process was ever created, i.e. _procs is not yet initialized.
718 * Nothing to wait for. */
722 if( pqid
> Max_proc
) Fatal("Internal Error: pqid > Max_proc !");
725 /* Check if there is something to wait for. */
727 for( i
=0; i
<Max_proc
&& !_procs
[i
].pr_valid
; i
++ )
736 /* Check if pqid is active. */
737 if( !_procs
[pqid
].pr_valid
) {
738 /* Make this an error? */
739 Warning("Internal Warning: pqid is not active!?");
743 pid
= _procs
[pqid
].pr_pid
;
744 waitchild
= _procs
[pqid
].pr_wfc
;
748 /* It is impossible that processes that were started from _exec_shell
749 * have follow-up commands in its process entry. Unset Is_exec_shell
750 * to prevent piping of child processes that are started from the
751 * _finished_child subroutine and reset to its original value when
752 * leaving this function. */
753 Is_exec_shell
= FALSE
;
756 /* Wait for the next process to finish. */
757 if( (pid
!= (DMHANDLE
)-1) && (waitret
= dmwaitpid(pqid
, &wid
, &status
)) != 0 ) {
758 /* if dmwaitpid returns 0 this means that pid didn't finish yet.
759 * In this case just handle the next finished process in the
760 * following "else". If an error is returned (waitret < 0) the else
761 * clause is not evaluated and the error is handled in the following
762 * lines. If a process was waited for (waitret == 0) also proceed to
763 * the following lines. */
767 waitret
= dmwaitnext(&wid
, &status
);
768 /* If we get an error tell the error handling routine below that we
769 * were not waiting for a specific pid. */
775 /* If ECHILD is set from waitpid/wait then no child was left. */
778 /* Wait was interrupted or a child was terminated (SIGCHLD) */
780 /* We're already terminating, just continue. */
783 Fatal( "dmake was interrupted or a child terminated. "
784 "Stopping all childs ..." );
787 /* The child we were waiting for is missing or no child is
788 * left to wait for. */
789 if( pid
!= (DMHANDLE
)-1 ) {
790 /* If we know the pid disable the pq entry. */
791 if( _procs
[pqid
].pr_valid
) {
792 _procs
[pqid
].pr_valid
= 0;
793 _procs
[pqid
].pr_recipe
= NIL(RCP
);
797 /* otherwise disable all remaining pq's. As we don't know
798 * which pid failed there is no gracefull way to terminate. */
800 for( i
=0; i
<Max_proc
; i
++ ) {
801 _procs
[i
].pr_valid
= 0;
802 _procs
[i
].pr_recipe
= NIL(RCP
);
806 /* The pid we were waiting for or any of the remaining childs
807 * (pid == -1) is missing. This should not happen and means
808 * that the process got lost or was treated elsewhere. */
809 Fatal( "Internal Error: Child is missing but still listed in _procs[x] %d: %s\n"
810 "\nTemporary or .ERRREMOVE targets might not have been removed!\n",
811 errno
, strerror( errno
) );
815 _abort_flg
= abort_flg
;
816 _finished_child(wid
, status
);
819 /* If pid != wid the process we're waiting for might have been
820 * finished from a "Wait_for_child(FALSE, -1)" call from
821 * _finished_child() -> runargv(). */
823 if( !_procs
[pqid
].pr_valid
|| _procs
[pqid
].pr_pid
!= pid
) {
824 /* Someone finished pid, no need to wait further. */
829 /* We finished pid, no need to wait further. */
835 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)
852 if( (ret
= kill(_procs
[i
].pr_pid
, SIGTERM
)) )
854 fprintf(stderr
, "Killing of pid %d from pq[%d] failed with: %s - %d ret: %d\n",
855 _procs
[i
].pr_pid
, i
, strerror(errno
), SIGTERM
, ret
);
858 TerminateProcess(_procs
[i
].pr_pid
, 1);
866 _add_child( pid
, target
, ignore
, last
, wfc
)/*
867 ==============================================
868 Creates/amend a process queue entry and enters the child parameters.
869 The pid == -1 represents an internal command and the function returns
870 the used process array index. For non-internal commands the function
872 If wfc (wait for completion) is TRUE the function calls
873 Wait_for_child to wait for the whole process queue to be finished.
884 /* Never change MAXPROCESS after _procs is allocated. */
885 if( _procs_size
!= Max_proc
) {
886 /* If procs was never initialize this is OK, do it now. */
887 if( _procs
== NIL(PR
) ) {
888 _procs_size
= Max_proc
;
889 TALLOC( _procs
, Max_proc
, PR
);
890 #if defined(USE_CREATEPROCESS)
891 TALLOC( _wpList
, Max_proc
, HANDLE
);
893 /* Signed int values are cast to DMHANDLE in various places, use this
894 * sanity check to verify that DMHANDLE is large enough. */
895 if( sizeof(int) > sizeof(DMHANDLE
) )
896 Fatal( "Internal Error: Check type of DMHANDLE!" );
900 Fatal( "MAXPROCESS changed from `%d' to `%d' after a command was executed!", _procs_size
, Max_proc
);
904 if( Measure
& M_RECIPE
)
905 Do_profile_output( "s", M_RECIPE
, target
);
907 /* If _use_i ! =-1 then this function is called by _finished_child() ( through runargv() ),
908 and we re-use the process queue number given by _use_i. */
909 if( (i
= _use_i
) == -1 ) {
910 for( i
=0; i
<Max_proc
; i
++ )
911 if( !_procs
[i
].pr_valid
)
918 pp
->pr_pid
= pid
.pid
;
919 pp
->pr_tid
= pid
.tid
;
920 pp
->pr_target
= target
;
921 pp
->pr_ignore
= ignore
;
925 if( pp
->pr_dir
!= NIL(char) )
927 pp
->pr_dir
= DmStrDup(Get_current_dir());
929 Current_target
= NIL(CELL
);
933 if( pid
.pid
!= (DMHANDLE
)-1 ) {
934 /* Wait for each recipe to finish if wfc is TRUE. This
935 * basically forces sequential execution. */
937 Wait_for_child( FALSE
, i
);
947 _finished_child(cid
, status
)/*
948 ==============================
949 Handle process array entry for finished child. This can be a finished
950 process or a finished internal command depending on the content of cid.
951 For cid >= 1 the value of cid is used as the pid to of the finished
952 process and for cid < 1 -cid is used as the process array index of the
961 if((int)cid
< 1) { /* Force int. */
962 /* internal command */
966 for( i
=0; i
<Max_proc
; i
++ )
967 if( _procs
[i
].pr_valid
&& _procs
[i
].pr_pid
== cid
)
970 /* Some children we didn't make esp true if using /bin/sh to execute a
971 * a pipe and feed the output as a makefile into dmake. */
972 if( i
== Max_proc
) {
973 Warning("Internal Warning: finished pid %d is not in pq!?", cid
);
978 /* Not a running process anymore, the next runargv() will not use
980 _procs
[i
].pr_valid
= 0;
982 if( Measure
& M_RECIPE
)
983 Do_profile_output( "e", M_RECIPE
, _procs
[i
].pr_target
);
986 dir
= DmStrDup(Get_current_dir());
987 Set_dir( _procs
[i
].pr_dir
);
989 if( _procs
[i
].pr_recipe
!= NIL(RCP
) && !_abort_flg
) {
990 RCPPTR rp
= _procs
[i
].pr_recipe
;
993 Current_target
= _procs
[i
].pr_target
;
994 Handle_result( status
, _procs
[i
].pr_ignore
, FALSE
, _procs
[i
].pr_target
);
995 Current_target
= NIL(CELL
);
997 if ( _procs
[i
].pr_target
->ce_attr
& A_ERROR
) {
998 _procs
[i
].pr_last
= TRUE
;
999 goto ABORT_REMAINDER_OF_RECIPE
;
1002 _procs
[i
].pr_recipe
= rp
->prp_next
;
1005 /* Run next recipe line. The rp->prp_attr propagates a possible
1007 runargv( _procs
[i
].pr_target
, rp
->prp_group
,
1008 rp
->prp_last
, rp
->prp_attr
, &rp
->prp_cmd
);
1011 FREE( rp
->prp_cmd
);
1014 /* If all process queues are used wait for the next process to
1015 * finish. Is this really needed here? */
1016 if( _proc_cnt
== Max_proc
) {
1017 Wait_for_child( FALSE
, -1 );
1021 /* empty the queue on abort. */
1023 _procs
[i
].pr_recipe
= NIL(RCP
);
1025 Handle_result(status
,_procs
[i
].pr_ignore
,_abort_flg
,_procs
[i
].pr_target
);
1027 ABORT_REMAINDER_OF_RECIPE
:
1028 if( _procs
[i
].pr_last
) {
1029 FREE(_procs
[i
].pr_dir
); _procs
[i
].pr_dir
= NIL(char); /* Set in _add_child() */
1032 /* Update_time_stamp() triggers the deletion of intermediate
1033 * targets. This starts a new process queue, so we have to
1034 * clear the _use_i variable. */
1035 int my_use_i
= _use_i
;
1038 Update_time_stamp( _procs
[i
].pr_target
);
1052 Check if target exists in process array AND is running. Return its
1053 process array index if it is running, return -1 otherwise.
1059 if( !_procs
) return( -1 );
1061 for( i
=0; i
<Max_proc
; i
++ )
1062 if( _procs
[i
].pr_valid
&&
1063 _procs
[i
].pr_target
== cp
)
1066 return( i
== Max_proc
? -1 : i
);
1071 _attach_cmd( cmd
, group
, cp
, cmnd_attr
, last
)/*
1072 ================================================
1073 Attach to an active process queue. Inherit wfc setting. */
1083 for( i
=0; i
<Max_proc
; i
++ )
1084 if( _procs
[i
].pr_valid
&&
1085 _procs
[i
].pr_target
== cp
)
1088 TALLOC( rp
, 1, RCP
);
1089 rp
->prp_cmd
= DmStrDup(cmd
);
1090 rp
->prp_attr
= cmnd_attr
;
1091 /* Inherit wfc from process queue. */
1092 if( _procs
[i
].pr_wfc
)
1093 rp
->prp_attr
|= A_WFC
;
1094 rp
->prp_group
= group
;
1095 rp
->prp_last
= last
;
1097 if( _procs
[i
].pr_recipe
== NIL(RCP
) )
1098 _procs
[i
].pr_recipe
= _procs
[i
].pr_recipe_end
= rp
;
1100 _procs
[i
].pr_recipe_end
->prp_next
= rp
;
1101 _procs
[i
].pr_recipe_end
= rp
;