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 fprintf(stderr
, "%s: Internal Error: wait() failed: %d - %s\n",
273 Pname
, errno
, strerror(errno
) );
274 if(errno
!= ECHILD
) {
275 /* Wait was interrupted or a child was terminated (SIGCHLD) */
289 /* Create a list of possible objects to wait for. */
290 for( i
=0; i
<Max_proc
; i
++ ) {
291 if(_procs
[i
].pr_valid
) {
292 _wpList
[numProc
++] = _procs
[i
].pr_pid
;
296 fprintf(stderr
, "%s: Internal Error: dmwaitnext() failed: "
297 "Nothing to wait for.\n", Pname
);
302 /* number of objects in array, array of objects,
303 * wait for any object, wait for the next child to finish */
304 pEvent
= WaitForMultipleObjects( numProc
, _wpList
, FALSE
, INFINITE
);
306 if( pEvent
>= 0 && pEvent
< WAIT_OBJECT_0
+ numProc
) {
307 *wid
= _wpList
[pEvent
- WAIT_OBJECT_0
];
308 for( i
=0; i
<Max_proc
&& _procs
[i
].pr_pid
!= *wid
; i
++ )
311 Fatal("Internal Error: Process not in pq !");
313 GetExitCodeProcess(*wid
, &dwExitCode
);
314 if(dwExitCode
== STILL_ACTIVE
) {
315 /* Process did not terminate -> force it, with exit code 1. */
316 TerminateProcess(*wid
, 1);
318 fprintf(stderr
, "%s: Internal Error: Process still running - "
319 "terminate it!\n", Pname
);
322 /* Close process and thread handles. */
324 CloseHandle( _procs
[i
].pr_tid
);
325 *status
= dwExitCode
;
328 int err
= GetLastError();
331 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
|
332 FORMAT_MESSAGE_FROM_SYSTEM
|
333 FORMAT_MESSAGE_IGNORE_INSERTS
,
336 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
340 fprintf(stderr
, "%s: Internal Error: WaitForMultipleObjects() (%d) failed:"
341 " %d - %s\n", Pname
, numProc
, err
, lpMsgBuf
);
344 /* No way to identify something comparable to ECHILD, always return -2.*/
354 dmwaitpid( pqid
, wid
, status
)
355 int pqid
; /* Process queue to wait for. */
356 DMHANDLE
*wid
; /* Id we waited for. */
357 int *status
; /* status of the finished process. */
358 /* return 1 if the process finished, 0 if it didn't finish yet, -1 if there
359 * was nothing to wait for (ECHILD) and -2 for other errors. */
362 #if !defined(USE_CREATEPROCESS)
363 *wid
= waitpid(_procs
[pqid
].pr_pid
, status
, WNOHANG
);
365 /* Process still running. */
370 /* If ECHILD is set from waitpid/wait then no child was left. */
372 fprintf(stderr
, "%s: Internal Error: waitpid() failed: %d - %s\n",
373 Pname
, errno
, strerror(errno
) );
374 if(errno
!= ECHILD
) {
375 /* Wait was interrupted or a child was terminated (SIGCHLD) */
385 *wid
= _procs
[pqid
].pr_pid
;
388 /* Wait ... (Check status and return) */
389 pEvent
= WaitForSingleObject(*wid
, 0);
391 if( pEvent
== WAIT_OBJECT_0
) {
392 GetExitCodeProcess(*wid
, &dwExitCode
);
393 if(dwExitCode
== STILL_ACTIVE
) {
394 /* Process did not terminate -> force it, with exit code 1. */
395 TerminateProcess(*wid
, 1);
397 fprintf(stderr
, "%s: Internal Error: Process still running - "
398 "terminate it!\n", Pname
);
401 /* Close process and thread handles. */
403 CloseHandle( _procs
[pqid
].pr_tid
);
404 *status
= dwExitCode
;
406 else if( pEvent
== WAIT_TIMEOUT
) {
410 int err
= GetLastError();
413 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
|
414 FORMAT_MESSAGE_FROM_SYSTEM
|
415 FORMAT_MESSAGE_IGNORE_INSERTS
,
418 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
422 fprintf(stderr
, "%s: Internal Error: WaitForSingleObject() failed:"
423 " %d - %s\n", Pname
, err
, lpMsgBuf
);
426 /* No way to identify something comparable to ECHILD, always return -2.*/
437 private_strerror (errnum
)
441 # if defined(arm32) || defined(linux) || defined(__FreeBSD__) || defined(__OpenBSD__)
442 extern const char * const sys_errlist
[];
444 extern char *sys_errlist
[];
449 if (errnum
> 0 && errnum
<= sys_nerr
)
450 return sys_errlist
[errnum
];
451 return "Unknown system error";
453 #define strerror private_strerror
454 #endif /* HAVE_STRERROR */
457 runargv(target
, group
, last
, cmnd_attr
, cmd
)/*
458 ==============================================
459 Execute the command given by cmd.
461 Return 0 if the command executed and finished or
462 1 if the command started and is running.
467 t_attr cmnd_attr
; /* Attributes for current cmnd. */
468 char **cmd
; /* Simulate a reference to *cmd. */
470 int ignore
= (cmnd_attr
& A_IGNORE
)!= 0; /* Ignore errors ('-'). */
471 int shell
= (cmnd_attr
& A_SHELL
) != 0; /* Use shell ('+'). */
472 int mute
= (cmnd_attr
& A_MUTE
) != 0; /* Mute output ('@@'). */
473 int wfc
= (cmnd_attr
& A_WFC
) != 0; /* Wait for completion. */
476 int st_pq
= 0; /* Current _exec_shell target process index */
477 char *tcmd
= *cmd
; /* For saver/easier string arithmetic on *cmd. */
480 int old_stdout
= -1; /* For shell escapes and */
481 int old_stderr
= -1; /* @@-recipe silencing. */
482 int internal
= 0; /* Used to indicate internal command. */
484 DB_ENTER( "runargv" );
486 /* Special handling for the shell function macro is required. If the
487 * currend command is called as part of a shell escape in a recipe make
488 * sure that all previous recipe lines of this target have finished. */
489 if( Is_exec_shell
) {
490 if( (st_pq
= _running(Shell_exec_target
)) != -1 ) {
492 /* Add WFC to _procs[st_pq]. */
493 _procs
[st_pq
].pr_wfc
= TRUE
;
494 /* Set also the A_WFC flag in the recipe attributes. */
495 for( rp
= _procs
[st_pq
].pr_recipe
; rp
!= NIL(RCP
); rp
= rp
->prp_next
)
496 rp
->prp_attr
|= A_WFC
;
498 Wait_for_child(FALSE
, st_pq
);
501 if( _running(target
) != -1 /*&& Max_proc != 1*/ ) {
502 /* The command will be executed when the previous recipe
504 _attach_cmd( *cmd
, group
, target
, cmnd_attr
, last
);
509 /* If all process array entries are used wait until we get a free
510 * slot. For Max_proc == 1 this forces sequential execution. */
511 while( _proc_cnt
== Max_proc
) {
512 Wait_for_child(FALSE
, -1);
515 /* Return immediately for empty line or noop command. */
516 if ( !*tcmd
|| /* empty line */
517 ( strncmp(tcmd
, "noop", 4) == 0 && /* noop command */
518 (iswhite(tcmd
[4]) || tcmd
[4] == '\0')) ) {
521 else if( !shell
&& /* internal echo only if not in shell */
522 strncmp(tcmd
, "echo", 4) == 0 &&
523 (iswhite(tcmd
[4]) || tcmd
[4] == '\0') ) {
527 while( iswhite(*tcmd
) ) ++tcmd
;
528 if ( strncmp(tcmd
,"-n",2 ) == 0) {
531 while( iswhite(*tcmd
) ) ++tcmd
;
534 /* redirect output for _exec_shell / @@-recipes. */
535 if( Is_exec_shell
) {
536 /* Add error checking? */
538 dup2( fileno(stdout_redir
), 1 );
544 if( !Is_exec_shell
) {
550 printf("%s%s", tcmd
, nl
? "\n" : "");
553 /* Restore stdout/stderr if needed. */
554 if( old_stdout
!= -1 ) {
557 if( old_stderr
!= -1 ) {
566 /* Use _add_child() / _finished_child() with internal command. */
567 int cur_proc
= _add_child(DMNOPID
, target
, ignore
, last
, FALSE
);
568 _finished_child( (DMHANDLE
)-cur_proc
, 0 );
572 /* Pack cmd in argument vector. */
573 argv
= Pack_argv( group
, shell
, cmd
);
575 /* Really spawn or fork a child. */
576 #if defined( USE_SPAWN )
577 /* As no other childs are started while the output is redirected this
579 if( Is_exec_shell
) {
580 /* Add error checking? */
582 dup2( fileno(stdout_redir
), 1 );
588 if( !Is_exec_shell
) {
594 pid
= dmspawn( argv
);
597 if( old_stdout
!= -1 ) {
600 if( old_stderr
!= -1 ) {
605 if(pid
.pid
== (DMHANDLE
)-1) {
609 fprintf(stderr
, "%s: Error executing '%s': %s",
610 Pname
, argv
[0], strerror(terrno
) );
611 if( ignore
||Continue
) {
612 fprintf(stderr
, " (Ignored)" );
614 fprintf(stderr
, "\n");
616 /* Use _add_child() / _finished_child() to treat the failure
617 * gracefully, if so requested. */
618 cur_proc
= _add_child(DMNOPID
, target
, ignore
, last
, FALSE
);
619 _finished_child((DMHANDLE
)cur_proc
, SIGTERM
);
621 /* _finished_child() aborts dmake if we are not told to
622 * ignore errors. If we reach the this point return 0 as
623 * errors are obviously ignored and indicate that the process
627 _add_child(pid
, target
, ignore
, last
, wfc
);
629 #else /* USE_SPAWN */
632 switch( pid
.pid
= fork() ){
634 case -1: /* fork failed */
635 Fatal("fork failed: %s: %s", argv
[0], strerror( errno
));
638 /* redirect output for _exec_shell / @@-recipes. */
639 if( Is_exec_shell
) {
640 /* Add error checking? */
642 dup2( fileno(stdout_redir
), 1 );
648 if( !Is_exec_shell
) {
653 execvp(argv
[0], argv
);
654 /* restoring output to catch potential error output if execvp()
656 if( old_stdout
!= -1 ) {
659 if( old_stderr
!= -1 ) {
664 fprintf(stderr
, "%s: Error executing '%s': %s",
665 Pname
, argv
[0], strerror(errno
) );
666 if( ignore
||Continue
) {
667 fprintf(stderr
, " (Ignored)" );
669 fprintf(stderr
, "\n");
671 kill(getpid(), SIGTERM
);
673 Fatal("\nInternal Error - kill could't kill child %d.\n", getpid());
675 default: /* parent */
676 _add_child(pid
, target
, ignore
, last
, wfc
);
679 #endif /* USE_SPAWN */
681 /* If wfc is set this command must have been finished. */
691 Wait_for_child( abort_flg
, pqid
)/*
692 ===================================
693 Wait for the next processes from process queue pqid to finish. All finished
694 processes are handled by calling _finished_child() for each of them.
695 If pqid == -1 wait for the next process to finish.
696 If abort_flg is TRUE no further processes will be added to any process
697 queue. The A_WFC attribute is honored, see the documentation at the top
699 Return 0 if we successfully waited for a process and -1 if there was nothing
708 int waitret
; /* return value of the dmwait functions. */
709 /* Never wait for internal commands. */
711 int is_exec_shell_status
= Is_exec_shell
;
714 /* No process was ever created, i.e. _procs is not yet initialized.
715 * Nothing to wait for. */
719 if( pqid
> Max_proc
) Fatal("Internal Error: pqid > Max_proc !");
722 /* Check if there is something to wait for. */
724 for( i
=0; i
<Max_proc
&& !_procs
[i
].pr_valid
; i
++ )
733 /* Check if pqid is active. */
734 if( !_procs
[pqid
].pr_valid
) {
735 /* Make this an error? */
736 Warning("Internal Warning: pqid is not active!?");
740 pid
= _procs
[pqid
].pr_pid
;
741 waitchild
= _procs
[pqid
].pr_wfc
;
745 /* It is impossible that processes that were started from _exec_shell
746 * have follow-up commands in its process entry. Unset Is_exec_shell
747 * to prevent piping of child processes that are started from the
748 * _finished_child subroutine and reset to its original value when
749 * leaving this function. */
750 Is_exec_shell
= FALSE
;
753 /* Wait for the next process to finish. */
754 if( (pid
!= (DMHANDLE
)-1) && (waitret
= dmwaitpid(pqid
, &wid
, &status
)) != 0 ) {
755 /* if dmwaitpid returns 0 this means that pid didn't finish yet.
756 * In this case just handle the next finished process in the
757 * following "else". If an error is returned (waitret < 0) the else
758 * clause is not evaluated and the error is handled in the following
759 * lines. If a process was waited for (waitret == 0) also proceed to
760 * the following lines. */
764 waitret
= dmwaitnext(&wid
, &status
);
765 /* If we get an error tell the error handling routine below that we
766 * were not waiting for a specific pid. */
772 /* If ECHILD is set from waitpid/wait then no child was left. */
775 /* Wait was interrupted or a child was terminated (SIGCHLD) */
777 /* We're already terminating, just continue. */
780 Fatal( "dmake was interrupted or a child terminated. "
781 "Stopping all childs ..." );
784 /* The child we were waiting for is missing or no child is
785 * left to wait for. */
786 if( pid
!= (DMHANDLE
)-1 ) {
787 /* If we know the pid disable the pq entry. */
788 if( _procs
[pqid
].pr_valid
) {
789 _procs
[pqid
].pr_valid
= 0;
790 _procs
[pqid
].pr_recipe
= NIL(RCP
);
794 /* otherwise disable all remaining pq's. As we don't know
795 * which pid failed there is no gracefull way to terminate. */
797 for( i
=0; i
<Max_proc
; i
++ ) {
798 _procs
[i
].pr_valid
= 0;
799 _procs
[i
].pr_recipe
= NIL(RCP
);
803 /* The pid we were waiting for or any of the remaining childs
804 * (pid == -1) is missing. This should not happen and means
805 * that the process got lost or was treated elsewhere. */
806 Fatal( "Internal Error: Child is missing but still listed in _procs[x] %d: %s\n"
807 "\nTemporary or .ERRREMOVE targets might not have been removed!\n",
808 errno
, strerror( errno
) );
812 _abort_flg
= abort_flg
;
813 _finished_child(wid
, status
);
816 /* If pid != wid the process we're waiting for might have been
817 * finished from a "Wait_for_child(FALSE, -1)" call from
818 * _finished_child() -> runargv(). */
820 if( !_procs
[pqid
].pr_valid
|| _procs
[pqid
].pr_pid
!= pid
) {
821 /* Someone finished pid, no need to wait further. */
826 /* We finished pid, no need to wait further. */
832 Is_exec_shell
= is_exec_shell_status
;
843 if( _procs
!= NIL(PR
) ) {
844 for( i
=0; i
<Max_proc
; i
++ )
845 if( _procs
[i
].pr_valid
) {
846 #if !defined(USE_CREATEPROCESS)
847 if( (ret
= kill(_procs
[i
].pr_pid
, SIGTERM
)) ) {
848 fprintf(stderr
, "Killing of pid %d from pq[%d] failed with: %s - %d ret: %d\n",
850 strerror(errno
), SIGTERM
, ret
);
853 TerminateProcess(_procs
[i
].pr_pid
, 1);
861 _add_child( pid
, target
, ignore
, last
, wfc
)/*
862 ==============================================
863 Creates/amend a process queue entry and enters the child parameters.
864 The pid == -1 represents an internal command and the function returns
865 the used process array index. For non-internal commands the function
867 If wfc (wait for completion) is TRUE the function calls
868 Wait_for_child to wait for the whole process queue to be finished.
879 /* Never change MAXPROCESS after _procs is allocated. */
880 if( _procs_size
!= Max_proc
) {
881 /* If procs was never initialize this is OK, do it now. */
882 if( _procs
== NIL(PR
) ) {
883 _procs_size
= Max_proc
;
884 TALLOC( _procs
, Max_proc
, PR
);
885 #if defined(USE_CREATEPROCESS)
886 TALLOC( _wpList
, Max_proc
, HANDLE
);
888 /* Signed int values are cast to DMHANDLE in various places, use this
889 * sanity check to verify that DMHANDLE is large enough. */
890 if( sizeof(int) > sizeof(DMHANDLE
) )
891 Fatal( "Internal Error: Check type of DMHANDLE!" );
895 Fatal( "MAXPROCESS changed from `%d' to `%d' after a command was executed!", _procs_size
, Max_proc
);
899 if( Measure
& M_RECIPE
)
900 Do_profile_output( "s", M_RECIPE
, target
);
902 /* If _use_i!=-1 then this function is called by _finished_child()
903 * ( through runargv() ). */
904 if( (i
= _use_i
) == -1 ) {
905 for( i
=0; i
<Max_proc
; i
++ )
906 if( !_procs
[i
].pr_valid
)
910 /* Re-use the process queue number given by _use_i.
911 * Free the pointer before using it again below. */
912 FREE( _procs
[i
].pr_dir
);
918 pp
->pr_pid
= pid
.pid
;
919 pp
->pr_tid
= pid
.tid
;
920 pp
->pr_target
= target
;
921 pp
->pr_ignore
= ignore
;
924 /* Freed above and after the last recipe in _finished child(). */
925 pp
->pr_dir
= DmStrDup(Get_current_dir());
927 Current_target
= NIL(CELL
);
931 if( pid
.pid
!= (DMHANDLE
)-1 ) {
932 /* Wait for each recipe to finish if wfc is TRUE. This
933 * basically forces sequential execution. */
935 Wait_for_child( FALSE
, i
);
945 _finished_child(cid
, status
)/*
946 ==============================
947 Handle process array entry for finished child. This can be a finished
948 process or a finished internal command depending on the content of cid.
949 For cid >= 1 the value of cid is used as the pid to of the finished
950 process and for cid < 1 -cid is used as the process array index of the
959 if((int)cid
< 1) { /* Force int. */
960 /* internal command */
964 for( i
=0; i
<Max_proc
; i
++ )
965 if( _procs
[i
].pr_valid
&& _procs
[i
].pr_pid
== cid
)
968 /* Some children we didn't make esp true if using /bin/sh to execute a
969 * a pipe and feed the output as a makefile into dmake. */
970 if( i
== Max_proc
) {
971 Warning("Internal Warning: finished pid %d is not in pq!?", cid
);
976 /* Not a running process anymore, the next runargv() will not use
978 _procs
[i
].pr_valid
= 0;
980 if( Measure
& M_RECIPE
)
981 Do_profile_output( "e", M_RECIPE
, _procs
[i
].pr_target
);
984 dir
= DmStrDup(Get_current_dir());
985 Set_dir( _procs
[i
].pr_dir
);
987 if( _procs
[i
].pr_recipe
!= NIL(RCP
) && !_abort_flg
) {
988 RCPPTR rp
= _procs
[i
].pr_recipe
;
991 Current_target
= _procs
[i
].pr_target
;
992 Handle_result( status
, _procs
[i
].pr_ignore
, FALSE
, _procs
[i
].pr_target
);
993 Current_target
= NIL(CELL
);
995 if ( _procs
[i
].pr_target
->ce_attr
& A_ERROR
) {
996 _procs
[i
].pr_last
= TRUE
;
997 goto ABORT_REMAINDER_OF_RECIPE
;
1000 _procs
[i
].pr_recipe
= rp
->prp_next
;
1003 /* Run next recipe line. The rp->prp_attr propagates a possible
1005 runargv( _procs
[i
].pr_target
, rp
->prp_group
,
1006 rp
->prp_last
, rp
->prp_attr
, &rp
->prp_cmd
);
1009 FREE( rp
->prp_cmd
);
1012 /* If all process queues are used wait for the next process to
1013 * finish. Is this really needed here? */
1014 if( _proc_cnt
== Max_proc
) {
1015 Wait_for_child( FALSE
, -1 );
1019 /* empty the queue on abort. */
1021 _procs
[i
].pr_recipe
= NIL(RCP
);
1023 Handle_result(status
,_procs
[i
].pr_ignore
,_abort_flg
,_procs
[i
].pr_target
);
1025 ABORT_REMAINDER_OF_RECIPE
:
1026 if( _procs
[i
].pr_last
) {
1027 FREE(_procs
[i
].pr_dir
); /* Set in _add_child() */
1030 /* Update_time_stamp() triggers the deletion of intermediate
1031 * targets. This starts a new process queue, so we have to
1032 * clear the _use_i variable. */
1033 int my_use_i
= _use_i
;
1036 Update_time_stamp( _procs
[i
].pr_target
);
1050 Check if target exists in process array AND is running. Return its
1051 process array index if it is running, return -1 otherwise.
1057 if( !_procs
) return( -1 );
1059 for( i
=0; i
<Max_proc
; i
++ )
1060 if( _procs
[i
].pr_valid
&&
1061 _procs
[i
].pr_target
== cp
)
1064 return( i
== Max_proc
? -1 : i
);
1069 _attach_cmd( cmd
, group
, cp
, cmnd_attr
, last
)/*
1070 ================================================
1071 Attach to an active process queue. Inherit wfc setting. */
1081 for( i
=0; i
<Max_proc
; i
++ )
1082 if( _procs
[i
].pr_valid
&&
1083 _procs
[i
].pr_target
== cp
)
1086 TALLOC( rp
, 1, RCP
);
1087 rp
->prp_cmd
= DmStrDup(cmd
);
1088 rp
->prp_attr
= cmnd_attr
;
1089 /* Inherit wfc from process queue. */
1090 if( _procs
[i
].pr_wfc
)
1091 rp
->prp_attr
|= A_WFC
;
1092 rp
->prp_group
= group
;
1093 rp
->prp_last
= last
;
1095 if( _procs
[i
].pr_recipe
== NIL(RCP
) )
1096 _procs
[i
].pr_recipe
= _procs
[i
].pr_recipe_end
= rp
;
1098 _procs
[i
].pr_recipe_end
->prp_next
= rp
;
1099 _procs
[i
].pr_recipe_end
= rp
;