Bump for 4.0-11
[LibreOffice.git] / dmake / unix / runargv.c
blobee6fd2ef0ad159f01af7088b972942dd045f72bb
1 /*
2 --
3 -- SYNOPSIS
4 -- Invoke a sub process.
5 --
6 -- DESCRIPTION
7 -- Use the standard methods of executing a sub process.
8 --
9 -- AUTHOR
10 -- Dennis Vadura, dvadura@dmake.wticorp.com
12 -- WWW
13 -- http://dmake.wticorp.com/
15 -- COPYRIGHT
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.
22 -- LOG
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 +--------------------------------+
39 | runargv | <+
40 +--------------------------------+ |
41 | ^ |
42 | | returns if |
43 | calls | wfc is false |
44 v | |
45 +--------------------------------+ |
46 | _add_child | |
47 +--------------------------------+ |
48 | ^ |
49 | calls if | | if another process
50 | wfc is true | returns | is queued:
51 v | | recursive call
52 +--------------------------------+ |
53 | Wait_for_Child | |
54 +--------------------------------+ |
55 | ^ |
56 | | process queue |
57 | calls | is empty |
58 v | |
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
72 created and handled.
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
77 available.
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
81 with execvp.
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
93 of them.
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
97 queue.
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
102 queue).
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
106 with runargv().
109 #include <signal.h>
111 #include "extern.h"
113 #ifdef HAVE_WAIT_H
114 # include <wait.h>
115 #else
116 # ifdef HAVE_SYS_WAIT_H
117 # include <sys/wait.h>
118 # endif
119 #endif
121 #if HAVE_SPAWN_H && ENABLE_SPAWN
122 # include <spawn.h>
123 #endif
125 #if __CYGWIN__ && ENABLE_SPAWN
126 #if HAVE_CYGWIN_PROCESS_H
127 # include <cygwin/process.h>
128 #else
129 # include <process.h>
130 #endif
131 #endif
133 #ifdef __EMX__
134 # include <process.h>
135 #define _P_NOWAIT P_NOWAIT
136 #endif
138 #include "sysintf.h"
139 #if HAVE_ERRNO_H
140 # include <errno.h>
141 #else
142 extern int errno;
143 #endif
145 typedef struct prp {
146 char *prp_cmd;
147 int prp_group;
148 t_attr prp_attr;
149 int prp_last;
150 struct prp *prp_next;
151 } RCP, *RCPPTR;
153 #if defined(USE_CREATEPROCESS)
154 /* MS's HANDLE is basically a (void *) (winnt.h). */
155 typedef HANDLE DMHANDLE;
156 #else
157 typedef int DMHANDLE;
158 #endif
160 typedef struct pr {
161 int pr_valid;
162 DMHANDLE pr_pid;
163 DMHANDLE pr_tid;
164 CELLPTR pr_target;
165 int pr_ignore;
166 int pr_last;
167 int pr_wfc;
168 RCPPTR pr_recipe;
169 RCPPTR pr_recipe_end;
170 char *pr_dir;
171 } PR;
173 typedef struct tpid {
174 DMHANDLE pid;
175 DMHANDLE tid;
176 } 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. */
187 #endif
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 **));
204 static TPID
205 dmspawn( argv )
206 char **argv;
208 TPID pid;
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);
213 pid.tid = 0;
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) );
223 si.cb = 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.
233 * No creation flags.
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;
241 } else {
242 fprintf(stderr, "CreateProcess failed (%d).\n", GetLastError() );
243 pid.pid = (DMHANDLE)-1;
245 #else /* Non cygwin, OS/2, MinGW and MSC */
246 int tpid;
247 if (posix_spawnp (&tpid, argv[0], NULL, NULL, argv, (char *)NULL))
248 tpid = -1; /* posix_spawn failed */
250 pid.pid = tpid;
251 pid.tid = 0;
252 #endif /* __CYGWIN__ */
253 return pid;
256 #endif /* USE_SPAWN */
258 static int
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. */
270 *wid = wait(status);
272 /* If ECHILD is set from waitpid/wait then no child was left. */
273 if( *wid == -1 ) {
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) */
279 return -2;
280 } else {
281 return -1;
284 #else
285 DWORD pEvent;
286 DWORD dwExitCode;
287 int i;
288 int numProc = 0;
290 *status = 0;
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;
298 if( numProc == 0 ) {
299 fprintf(stderr, "%s: Internal Error: dmwaitnext() failed: "
300 "Nothing to wait for.\n", Pname );
301 return -1;
304 /* Wait ... */
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++ )
313 if( i == Max_proc )
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);
320 dwExitCode = 1;
321 fprintf(stderr, "%s: Internal Error: Process still running - "
322 "terminate it!\n", Pname );
325 /* Close process and thread handles. */
326 CloseHandle( *wid );
327 CloseHandle( _procs[i].pr_tid );
328 *status = dwExitCode;
330 else {
331 int err = GetLastError();
332 LPVOID lpMsgBuf;
334 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
335 FORMAT_MESSAGE_FROM_SYSTEM |
336 FORMAT_MESSAGE_IGNORE_INSERTS,
337 NULL,
338 err,
339 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
340 (LPTSTR) &lpMsgBuf,
341 0, NULL );
343 fprintf(stderr, "%s: Internal Error: WaitForMultipleObjects() (%d) failed:"
344 " %d - %s\n", Pname, numProc, err, lpMsgBuf);
345 LocalFree(lpMsgBuf);
347 /* No way to identify something comparable to ECHILD, always return -2.*/
348 return -2;
351 #endif
352 return 1;
356 static int
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. */
369 if( *wid == 0 ) {
370 *status = 0;
371 return 0;
373 /* If ECHILD is set from waitpid/wait then no child was left. */
374 if( *wid == -1 ) {
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) */
380 return -2;
381 } else {
382 return -1;
385 #else
386 DWORD pEvent;
387 DWORD dwExitCode;
389 *wid = _procs[pqid].pr_pid;
390 *status = 0;
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);
400 dwExitCode = 1;
401 fprintf(stderr, "%s: Internal Error: Process still running - "
402 "terminate it!\n", Pname );
405 /* Close process and thread handles. */
406 CloseHandle( *wid );
407 CloseHandle( _procs[pqid].pr_tid );
408 *status = dwExitCode;
410 else if( pEvent == WAIT_TIMEOUT ) {
411 return 0;
413 else {
414 int err = GetLastError();
415 LPVOID lpMsgBuf;
417 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
418 FORMAT_MESSAGE_FROM_SYSTEM |
419 FORMAT_MESSAGE_IGNORE_INSERTS,
420 NULL,
421 err,
422 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
423 (LPTSTR) &lpMsgBuf,
424 0, NULL );
426 fprintf(stderr, "%s: Internal Error: WaitForSingleObject() failed:"
427 " %d - %s\n", Pname, err, lpMsgBuf);
428 LocalFree(lpMsgBuf);
430 /* No way to identify something comparable to ECHILD, always return -2.*/
431 return -2;
433 #endif
435 return 1;
439 #if ! HAVE_STRERROR
440 static char *
441 private_strerror (errnum)
442 int errnum;
444 #ifndef __APPLE__
445 # if defined(arm32) || defined(linux) || defined(__FreeBSD__) || \
446 defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
447 extern const char * const sys_errlist[];
448 # else
449 extern char *sys_errlist[];
450 # endif
451 #endif
452 extern int sys_nerr;
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 */
461 PUBLIC int
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.
469 CELLPTR target;
470 int group;
471 int last;
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. */
480 TPID pid;
481 int st_pq = 0; /* Current _exec_shell target process index */
482 char *tcmd = *cmd; /* For saver/easier string arithmetic on *cmd. */
483 char **argv;
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 ) {
496 RCPPTR rp;
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);
505 } else {
506 if( _running(target) != -1 /*&& Max_proc != 1*/ ) {
507 /* The command will be executed when the previous recipe
508 * line completes. */
509 _attach_cmd( *cmd, group, target, cmnd_attr, last );
510 DB_RETURN( 1 );
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')) ) {
524 internal = 1;
526 else if( !shell && /* internal echo only if not in shell */
527 strncmp(tcmd, "echo", 4) == 0 &&
528 (iswhite(tcmd[4]) || tcmd[4] == '\0') ) {
529 int nl = 1;
531 tcmd = tcmd+4;
532 while( iswhite(*tcmd) ) ++tcmd;
533 if ( strncmp(tcmd,"-n",2 ) == 0) {
534 nl = 0;
535 tcmd = tcmd+2;
536 while( iswhite(*tcmd) ) ++tcmd;
539 /* redirect output for _exec_shell / @@-recipes. */
540 if( Is_exec_shell ) {
541 /* Add error checking? */
542 old_stdout = dup(1);
543 dup2( fileno(stdout_redir), 1 );
545 if( mute ) {
546 old_stderr = dup(2);
547 dup2( zerofd, 2 );
549 if( !Is_exec_shell ) {
550 old_stdout = dup(1);
551 dup2( zerofd, 1 );
555 printf("%s%s", tcmd, nl ? "\n" : "");
556 fflush(stdout);
558 /* Restore stdout/stderr if needed. */
559 if( old_stdout != -1 ) {
560 dup2(old_stdout, 1);
561 close(old_stdout);
562 if( old_stderr != -1 ) {
563 dup2(old_stderr, 2);
564 close(old_stderr);
568 internal = 1;
570 if ( internal ) {
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 );
574 DB_RETURN( 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
583 * is save. */
584 if( Is_exec_shell ) {
585 /* Add error checking? */
586 old_stdout = dup(1);
587 dup2( fileno(stdout_redir), 1 );
589 if( mute ) {
590 old_stderr = dup(2);
591 dup2( zerofd, 2 );
593 if( !Is_exec_shell ) {
594 old_stdout = dup(1);
595 dup2( zerofd, 1 );
599 pid = dmspawn( argv );
600 terrno = errno;
602 if( old_stdout != -1 ) {
603 dup2(old_stdout, 1);
604 close(old_stdout);
605 if( old_stderr != -1 ) {
606 dup2(old_stderr, 2);
607 close(old_stderr);
610 if(pid.pid == (DMHANDLE)-1) {
611 /* spawn failed */
612 int cur_proc;
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
629 * finished. */
630 DB_RETURN( 0 );
631 } else {
632 _add_child(pid, target, ignore, last, wfc);
634 #else /* USE_SPAWN */
636 fflush(stdout);
637 switch( pid.pid = fork() ){
639 case -1: /* fork failed */
640 Fatal("fork failed: %s: %s", argv[0], strerror( errno ));
642 case 0: /* child */
643 /* redirect output for _exec_shell / @@-recipes. */
644 if( Is_exec_shell ) {
645 /* Add error checking? */
646 old_stdout = dup(1);
647 dup2( fileno(stdout_redir), 1 );
649 if( mute ) {
650 old_stderr = dup(2);
651 dup2( zerofd, 2 );
653 if( !Is_exec_shell ) {
654 old_stdout = dup(1);
655 dup2( zerofd, 1 );
658 execvp(argv[0], argv);
659 /* restoring output to catch potential error output if execvp()
660 * failed. */
661 if( old_stdout != -1 ) {
662 dup2(old_stdout, 1);
663 close(old_stdout);
664 if( old_stderr != -1 ) {
665 dup2(old_stderr, 2);
666 close(old_stderr);
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);
677 /*NOTREACHED*/
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. */
687 if( wfc ) {
688 DB_RETURN( 0 );
689 } else {
690 DB_RETURN( 1 );
695 PUBLIC int
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
703 of this file.
704 Return 0 if we successfully waited for a process and -1 if there was nothing
705 to wait for.
707 int abort_flg;
708 int pqid;
710 DMHANDLE pid;
711 DMHANDLE wid;
712 int status;
713 int waitret; /* return value of the dmwait functions. */
714 /* Never wait for internal commands. */
715 int waitchild;
716 int is_exec_shell_status = Is_exec_shell;
718 if( !_procs ) {
719 /* No process was ever created, i.e. _procs is not yet initialized.
720 * Nothing to wait for. */
721 return -1;
724 if( pqid > Max_proc ) Fatal("Internal Error: pqid > Max_proc !");
726 if( pqid == -1 ) {
727 /* Check if there is something to wait for. */
728 int i;
729 for( i=0; i<Max_proc && !_procs[i].pr_valid; i++ )
731 if( i == Max_proc )
732 return(-1);
734 pid = (DMHANDLE)-1;
735 waitchild = FALSE;
737 else {
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!?");
742 return(-1);
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;
757 do {
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. */
768 else {
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. */
772 if( waitret < 0 ) {
773 pid = (DMHANDLE)-1;
777 /* If ECHILD is set from waitpid/wait then no child was left. */
778 if( waitret < 0 ) {
779 if(waitret == -2) {
780 /* Wait was interrupted or a child was terminated (SIGCHLD) */
781 if ( in_quit() ) {
782 /* We're already terminating, just continue. */
783 return 0;
784 } else {
785 Fatal( "dmake was interrupted or a child terminated. "
786 "Stopping all children ..." );
788 } else {
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);
796 _proc_cnt--;
798 } else {
799 /* otherwise disable all remaining pq's. As we don't know
800 * which pid failed there is no gracefull way to terminate. */
801 int i;
802 for( i=0; i<Max_proc; i++ ) {
803 _procs[i].pr_valid = 0;
804 _procs[i].pr_recipe = NIL(RCP);
806 _proc_cnt = 0;
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);
819 _abort_flg = FALSE;
820 if( waitchild ) {
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(). */
824 if( pid != wid ) {
825 if( !_procs[pqid].pr_valid || _procs[pqid].pr_pid != pid ) {
826 /* Someone finished pid, no need to wait further. */
827 waitchild = FALSE;
830 else
831 /* We finished pid, no need to wait further. */
832 waitchild = FALSE;
835 while( waitchild );
837 Is_exec_shell = is_exec_shell_status;
838 return(0);
842 PUBLIC void
843 Clean_up_processes()
845 if( _procs != NIL(PR) )
847 register int i;
848 for( i=0; i<Max_proc; i++ )
849 if( _procs[i].pr_valid )
851 #if !defined(USE_CREATEPROCESS)
852 int ret;
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 );
858 #else
859 TerminateProcess(_procs[i].pr_pid, 1);
860 #endif
866 static int
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
872 returns -1.
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.
876 TPID pid;
877 CELLPTR target;
878 int ignore;
879 int last;
880 int wfc;
882 register int i;
883 register PR *pp;
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!" );
898 #endif
900 else {
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 )
913 break;
916 pp = &(_procs[i]);
918 pp->pr_valid = 1;
919 pp->pr_pid = pid.pid;
920 pp->pr_tid = pid.tid;
921 pp->pr_target = target;
922 pp->pr_ignore = ignore;
923 pp->pr_last = last;
924 pp->pr_wfc = wfc;
926 if( pp->pr_dir != NIL(char) )
927 FREE(pp->pr_dir);
928 pp->pr_dir = DmStrDup(Get_current_dir());
930 Current_target = NIL(CELL);
932 _proc_cnt++;
934 if( pid.pid != (DMHANDLE)-1 ) {
935 /* Wait for each recipe to finish if wfc is TRUE. This
936 * basically forces sequential execution. */
937 if( wfc ) {
938 Wait_for_child( FALSE, i );
941 return -1;
942 } else
943 return i;
947 static void
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
954 internal command.
956 DMHANDLE cid;
957 int status;
959 register int i;
960 char *dir;
962 if((int)cid < 1) { /* Force int. */
963 /* internal command */
964 i = -((int)cid);
966 else {
967 for( i=0; i<Max_proc; i++ )
968 if( _procs[i].pr_valid && _procs[i].pr_pid == cid )
969 break;
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);
975 return;
979 /* Not a running process anymore, the next runargv() will not use
980 * _attach_cmd(). */
981 _procs[i].pr_valid = 0;
983 if( Measure & M_RECIPE )
984 Do_profile_output( "e", M_RECIPE, _procs[i].pr_target );
986 _proc_cnt--;
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;
1005 _use_i = i;
1006 /* Run next recipe line. The rp->prp_attr propagates a possible
1007 * wfc condition. */
1008 runargv( _procs[i].pr_target, rp->prp_group,
1009 rp->prp_last, rp->prp_attr, &rp->prp_cmd );
1010 _use_i = -1;
1012 FREE( rp->prp_cmd );
1013 FREE( rp );
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 );
1021 else {
1022 /* empty the queue on abort. */
1023 if( _abort_flg )
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() */
1032 if( !Doing_bang ) {
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;
1038 _use_i = -1;
1039 Update_time_stamp( _procs[i].pr_target );
1040 _use_i = my_use_i;
1045 Set_dir(dir);
1046 FREE(dir);
1050 static int
1051 _running( cp )/*
1052 ================
1053 Check if target exists in process array AND is running. Return its
1054 process array index if it is running, return -1 otherwise.
1056 CELLPTR cp;
1058 register int i;
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 )
1065 break;
1067 return( i == Max_proc ? -1 : i );
1071 static void
1072 _attach_cmd( cmd, group, cp, cmnd_attr, last )/*
1073 ================================================
1074 Attach to an active process queue. Inherit wfc setting. */
1075 char *cmd;
1076 int group;
1077 CELLPTR cp;
1078 t_attr cmnd_attr;
1079 int last;
1081 register int i;
1082 RCPPTR rp;
1084 for( i=0; i<Max_proc; i++ )
1085 if( _procs[i].pr_valid &&
1086 _procs[i].pr_target == cp )
1087 break;
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;
1100 else {
1101 _procs[i].pr_recipe_end->prp_next = rp;
1102 _procs[i].pr_recipe_end = rp;