Annotation of src/usr.bin/make/job.c, Revision 1.158
1.158 ! espie 1: /* $OpenBSD: job.c,v 1.157 2020/01/13 15:55:57 espie Exp $ */
1.6 millert 2: /* $NetBSD: job.c,v 1.16 1996/11/06 17:59:08 christos Exp $ */
1.1 deraadt 3:
4: /*
1.124 espie 5: * Copyright (c) 2012 Marc Espie.
6: *
7: * Extensive code modifications for the OpenBSD project.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
19: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD
22: * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29: */
30: /*
1.1 deraadt 31: * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
32: * Copyright (c) 1988, 1989 by Adam de Boor
33: * Copyright (c) 1989 by Berkeley Softworks
34: * All rights reserved.
35: *
36: * This code is derived from software contributed to Berkeley by
37: * Adam de Boor.
38: *
39: * Redistribution and use in source and binary forms, with or without
40: * modification, are permitted provided that the following conditions
41: * are met:
42: * 1. Redistributions of source code must retain the above copyright
43: * notice, this list of conditions and the following disclaimer.
44: * 2. Redistributions in binary form must reproduce the above copyright
45: * notice, this list of conditions and the following disclaimer in the
46: * documentation and/or other materials provided with the distribution.
1.55 millert 47: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 48: * may be used to endorse or promote products derived from this software
49: * without specific prior written permission.
50: *
51: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61: * SUCH DAMAGE.
62: */
63:
64: /*-
65: * job.c --
66: * handle the creation etc. of our child processes.
67: *
68: * Interface:
1.40 espie 69: * Job_Make Start the creation of the given target.
1.1 deraadt 70: *
1.124 espie 71: * Job_Init Called to initialize this module.
72: *
1.117 espie 73: * can_start_job Return true if we can start job
1.40 espie 74: *
1.41 espie 75: * Job_Empty Return true if the job table is completely
1.40 espie 76: * empty.
77: *
1.117 espie 78: * Job_AbortAll Abort all current jobs. It doesn't
1.40 espie 79: * handle output or do anything for the jobs,
1.124 espie 80: * just kills them.
1.1 deraadt 81: *
1.117 espie 82: * Job_Wait Wait for all running jobs to finish.
1.1 deraadt 83: */
84:
85: #include <sys/types.h>
86: #include <sys/wait.h>
1.41 espie 87: #include <ctype.h>
88: #include <errno.h>
1.1 deraadt 89: #include <fcntl.h>
1.41 espie 90: #include <signal.h>
1.69 espie 91: #include <stdarg.h>
1.1 deraadt 92: #include <stdio.h>
1.42 espie 93: #include <stdlib.h>
1.1 deraadt 94: #include <string.h>
1.41 espie 95: #include <unistd.h>
96: #include "config.h"
97: #include "defines.h"
1.1 deraadt 98: #include "job.h"
1.63 espie 99: #include "engine.h"
1.1 deraadt 100: #include "pathnames.h"
1.41 espie 101: #include "var.h"
102: #include "targ.h"
103: #include "error.h"
1.124 espie 104: #include "extern.h"
1.41 espie 105: #include "lst.h"
106: #include "gnode.h"
107: #include "memory.h"
1.124 espie 108: #include "buf.h"
1.155 espie 109: #include "enginechoice.h"
1.78 espie 110:
1.40 espie 111: static int aborting = 0; /* why is the make aborting? */
112: #define ABORT_ERROR 1 /* Because of an error */
113: #define ABORT_INTERRUPT 2 /* Because it was interrupted */
114: #define ABORT_WAIT 3 /* Waiting for jobs to finish */
1.1 deraadt 115:
1.124 espie 116: static bool no_new_jobs; /* Mark recursive shit so we shouldn't start
117: * something else at the same time
118: */
1.148 espie 119: bool sequential;
1.124 espie 120: Job *runningJobs; /* Jobs currently running a process */
121: Job *errorJobs; /* Jobs in error at end */
1.148 espie 122: Job *availableJobs; /* Pool of available jobs */
1.124 espie 123: static Job *heldJobs; /* Jobs not running yet because of expensive */
1.134 espie 124: static pid_t mypid; /* Used for printing debugging messages */
1.148 espie 125: static Job *extra_job; /* Needed for .INTERRUPT */
1.1 deraadt 126:
1.128 espie 127: static volatile sig_atomic_t got_fatal;
1.112 espie 128:
1.124 espie 129: static volatile sig_atomic_t got_SIGINT, got_SIGHUP, got_SIGQUIT, got_SIGTERM,
1.128 espie 130: got_SIGINFO;
1.112 espie 131:
1.124 espie 132: static sigset_t sigset, emptyset;
1.112 espie 133:
1.126 espie 134: static void handle_fatal_signal(int);
1.124 espie 135: static void handle_siginfo(void);
1.142 espie 136: static void postprocess_job(Job *);
1.124 espie 137: static void determine_job_next_step(Job *);
138: static void may_continue_job(Job *);
139: static Job *reap_finished_job(pid_t);
140: static bool reap_jobs(void);
1.157 espie 141: static void may_continue_heldback_jobs(void);
1.112 espie 142:
1.124 espie 143: static bool expensive_job(Job *);
144: static bool expensive_command(const char *);
145: static void setup_signal(int);
146: static void notice_signal(int);
147: static void setup_all_signals(void);
1.128 espie 148: static const char *really_kill(Job *, int);
149: static void debug_kill_printf(const char *, ...);
150: static void debug_vprintf(const char *, va_list);
151: static void may_remove_target(Job *);
1.131 espie 152: static void print_error(Job *);
153: static void internal_print_errors(void);
154:
155: static int dying_signal = 0;
156:
157: const char * basedirectory = NULL;
1.127 espie 158:
1.128 espie 159: static const char *
160: really_kill(Job *job, int signo)
161: {
162: pid_t pid = job->pid;
163: if (getpgid(pid) != getpgrp()) {
164: if (killpg(pid, signo) == 0)
165: return "group got signal";
166: pid = -pid;
167: } else {
168: if (kill(pid, signo) == 0)
169: return "process got signal";
170: }
1.138 natano 171: if (errno == ESRCH)
1.128 espie 172: job->flags |= JOB_LOST;
1.138 natano 173: return strerror(errno);
1.128 espie 174: }
175:
176: static void
177: may_remove_target(Job *j)
178: {
1.131 espie 179: int dying = check_dying_signal();
180:
181: if (dying && !noExecute && !Targ_Precious(j->node)) {
1.128 espie 182: const char *file = Var(TARGET_INDEX, j->node);
183: int r = eunlink(file);
184:
185: if (DEBUG(JOB) && r == -1)
186: fprintf(stderr, " *** would unlink %s\n", file);
187: if (r != -1)
188: fprintf(stderr, " *** %s removed\n", file);
1.127 espie 189: }
190: }
1.126 espie 191:
1.131 espie 192: static void
193: buf_addcurdir(BUFFER *buf)
194: {
195: const char *v = Var_Value(".CURDIR");
196: if (basedirectory != NULL) {
197: size_t len = strlen(basedirectory);
198: if (strncmp(basedirectory, v, len) == 0 &&
199: v[len] == '/') {
200: v += len+1;
201: } else if (strcmp(basedirectory, v) == 0) {
202: Buf_AddString(buf, ".");
203: return;
204: }
205: }
206: Buf_AddString(buf, v);
207: }
208:
209: static const char *
210: shortened_curdir(void)
211: {
212: static BUFFER buf;
1.140 espie 213: static bool first = true;
1.131 espie 214: if (first) {
215: Buf_Init(&buf, 0);
216: buf_addcurdir(&buf);
217: first = false;
218: }
219: return Buf_Retrieve(&buf);
220: }
221:
222: static void
223: quick_error(Job *j, int signo, bool first)
224: {
225: if (first) {
226: fprintf(stderr, "*** Signal SIG%s", sys_signame[signo]);
227: fprintf(stderr, " in %s (", shortened_curdir());
228: } else
229: fprintf(stderr, " ");
230:
231: fprintf(stderr, "%s", j->node->name);
232: free(j->cmd);
233: }
234:
1.126 espie 235: static void
1.130 espie 236: print_error(Job *j)
1.126 espie 237: {
1.130 espie 238: static bool first = true;
1.131 espie 239: BUFFER buf;
240:
241: Buf_Init(&buf, 0);
1.126 espie 242:
1.131 espie 243: if (j->exit_type == JOB_EXIT_BAD)
244: Buf_printf(&buf, "*** Error %d", j->code);
245: else if (j->exit_type == JOB_SIGNALED) {
1.128 espie 246: if (j->code < NSIG)
1.131 espie 247: Buf_printf(&buf, "*** Signal SIG%s",
1.128 espie 248: sys_signame[j->code]);
249: else
1.131 espie 250: Buf_printf(&buf, "*** unknown signal %d", j->code);
1.128 espie 251: } else
1.131 espie 252: Buf_printf(&buf, "*** Should not happen %d/%d",
253: j->exit_type, j->code);
1.128 espie 254: if (DEBUG(KILL) && (j->flags & JOB_LOST))
1.131 espie 255: Buf_AddChar(&buf, '!');
1.130 espie 256: if (first) {
1.131 espie 257: Buf_AddString(&buf, " in ");
258: buf_addcurdir(&buf);
1.130 espie 259: first = false;
260: }
1.131 espie 261: Buf_printf(&buf, " (%s:%lu", j->location->fname, j->location->lineno);
262: Buf_printf(&buf, " '%s'", j->node->name);
263: if ((j->flags & (JOB_SILENT | JOB_IS_EXPENSIVE)) == JOB_SILENT
1.132 espie 264: && Buf_Size(&buf) < 140-2) {
1.131 espie 265: size_t len = strlen(j->cmd);
266: Buf_AddString(&buf, ": ");
267: if (len + Buf_Size(&buf) < 140)
268: Buf_AddString(&buf, j->cmd);
269: else {
270: Buf_AddChars(&buf, 140 - Buf_Size(&buf), j->cmd);
271: Buf_AddString(&buf, "...");
272: }
273: }
274: fprintf(stderr, "%s)\n", Buf_Retrieve(&buf));
275: Buf_Destroy(&buf);
1.126 espie 276: free(j->cmd);
1.131 espie 277: }
278: static void
279: quick_summary(int signo)
280: {
281: Job *j, *k, *jnext;
282: bool first = true;
283:
284: k = errorJobs;
285: errorJobs = NULL;
286: for (j = k; j != NULL; j = jnext) {
287: jnext = j->next;
288: if ((j->exit_type == JOB_EXIT_BAD && j->code == signo+128) ||
289: (j->exit_type == JOB_SIGNALED && j->code == signo)) {
290: quick_error(j, signo, first);
291: first = false;
292: } else {
293: j->next = errorJobs;
294: errorJobs = j;
295: }
296: }
297: if (!first)
298: fprintf(stderr, ")\n");
1.126 espie 299: }
1.93 espie 300:
1.131 espie 301: static void
302: internal_print_errors()
1.101 espie 303: {
1.126 espie 304: Job *j, *k, *jnext;
1.131 espie 305: int dying;
1.124 espie 306:
1.130 espie 307: if (!errorJobs)
1.133 espie 308: fprintf(stderr, "Stop in %s\n", shortened_curdir());
1.1 deraadt 309:
1.131 espie 310: for (j = errorJobs; j != NULL; j = j->next)
311: may_remove_target(j);
312: dying = check_dying_signal();
313: if (dying)
314: quick_summary(dying);
1.143 espie 315: /* Print errors grouped by file name. */
1.126 espie 316: while (errorJobs != NULL) {
1.143 espie 317: /* Select the first job. */
1.126 espie 318: k = errorJobs;
319: errorJobs = NULL;
320: for (j = k; j != NULL; j = jnext) {
321: jnext = j->next;
322: if (j->location->fname == k->location->fname)
1.143 espie 323: /* Print errors with the same filename. */
1.130 espie 324: print_error(j);
1.126 espie 325: else {
1.143 espie 326: /* Keep others for the next iteration. */
1.126 espie 327: j->next = errorJobs;
328: errorJobs = j;
329: }
330: }
1.101 espie 331: }
1.88 espie 332: }
333:
1.131 espie 334: void
335: print_errors(void)
336: {
337: handle_all_signals();
338: internal_print_errors();
339: }
340:
1.57 espie 341: static void
1.124 espie 342: setup_signal(int sig)
1.57 espie 343: {
1.124 espie 344: if (signal(sig, SIG_IGN) != SIG_IGN) {
345: (void)signal(sig, notice_signal);
346: sigaddset(&sigset, sig);
1.57 espie 347: }
348: }
349:
350: static void
1.124 espie 351: notice_signal(int sig)
1.1 deraadt 352: {
1.126 espie 353:
1.124 espie 354: switch(sig) {
1.117 espie 355: case SIGINT:
356: got_SIGINT++;
1.124 espie 357: got_fatal = 1;
358: break;
1.117 espie 359: case SIGHUP:
360: got_SIGHUP++;
1.124 espie 361: got_fatal = 1;
362: break;
1.117 espie 363: case SIGQUIT:
364: got_SIGQUIT++;
1.124 espie 365: got_fatal = 1;
366: break;
1.117 espie 367: case SIGTERM:
368: got_SIGTERM++;
1.124 espie 369: got_fatal = 1;
1.117 espie 370: break;
1.124 espie 371: case SIGINFO:
372: got_SIGINFO++;
1.117 espie 373: break;
1.124 espie 374: case SIGCHLD:
1.117 espie 375: break;
1.66 espie 376: }
1.124 espie 377: }
1.117 espie 378:
1.135 espie 379: static void
1.124 espie 380: setup_all_signals(void)
381: {
382: sigemptyset(&sigset);
383: sigemptyset(&emptyset);
384: /*
385: * Catch the four signals that POSIX specifies if they aren't ignored.
386: * handle_signal will take care of calling JobInterrupt if appropriate.
387: */
388: setup_signal(SIGINT);
389: setup_signal(SIGHUP);
390: setup_signal(SIGQUIT);
391: setup_signal(SIGTERM);
392: /* Display running jobs on SIGINFO */
393: setup_signal(SIGINFO);
394: /* Have to see SIGCHLD */
395: setup_signal(SIGCHLD);
396: got_fatal = 0;
1.1 deraadt 397: }
398:
1.124 espie 399: static void
400: handle_siginfo(void)
1.1 deraadt 401: {
1.126 espie 402: static BUFFER buf;
403: static size_t length = 0;
404:
1.124 espie 405: Job *job;
406: bool first = true;
1.66 espie 407:
1.124 espie 408: got_SIGINFO = 0;
409: /* we have to store the info in a buffer, because status from all
410: * makes running would get intermixed otherwise
1.66 espie 411: */
1.124 espie 412:
1.126 espie 413: if (length == 0) {
414: Buf_Init(&buf, 0);
1.131 espie 415: Buf_printf(&buf, "%s in ", Var_Value("MAKE"));
416: buf_addcurdir(&buf);
417: Buf_AddString(&buf, ": ");
1.126 espie 418: length = Buf_Size(&buf);
419: } else
420: Buf_Truncate(&buf, length);
1.124 espie 421:
422: for (job = runningJobs; job != NULL ; job = job->next) {
423: if (!first)
424: Buf_puts(&buf, ", ");
425: first = false;
426: Buf_puts(&buf, job->node->name);
427: }
428: Buf_puts(&buf, first ? "nothing running\n" : "\n");
1.1 deraadt 429:
1.124 espie 430: fputs(Buf_Retrieve(&buf), stderr);
1.1 deraadt 431: }
432:
1.131 espie 433: int
434: check_dying_signal(void)
435: {
436: sigset_t set;
437: if (dying_signal)
438: return dying_signal;
439: sigpending(&set);
440: if (got_SIGINT || sigismember(&set, SIGINT))
441: return dying_signal = SIGINT;
442: if (got_SIGHUP || sigismember(&set, SIGHUP))
443: return dying_signal = SIGHUP;
444: if (got_SIGQUIT || sigismember(&set, SIGQUIT))
445: return dying_signal = SIGQUIT;
446: if (got_SIGTERM || sigismember(&set, SIGTERM))
447: return dying_signal = SIGTERM;
448: return 0;
449: }
450:
1.124 espie 451: void
452: handle_all_signals(void)
1.1 deraadt 453: {
1.124 espie 454: if (got_SIGINFO)
455: handle_siginfo();
456: while (got_fatal) {
457: got_fatal = 0;
458: aborting = ABORT_INTERRUPT;
459:
460: if (got_SIGINT) {
461: got_SIGINT=0;
1.126 espie 462: handle_fatal_signal(SIGINT);
1.124 espie 463: }
464: if (got_SIGHUP) {
465: got_SIGHUP=0;
1.126 espie 466: handle_fatal_signal(SIGHUP);
1.124 espie 467: }
468: if (got_SIGQUIT) {
469: got_SIGQUIT=0;
1.126 espie 470: handle_fatal_signal(SIGQUIT);
1.124 espie 471: }
472: if (got_SIGTERM) {
473: got_SIGTERM=0;
1.126 espie 474: handle_fatal_signal(SIGTERM);
1.124 espie 475: }
476: }
1.1 deraadt 477: }
478:
1.128 espie 479: static void
480: debug_vprintf(const char *fmt, va_list va)
481: {
482: (void)printf("[%ld] ", (long)mypid);
483: (void)vprintf(fmt, va);
484: fflush(stdout);
485: }
486:
1.124 espie 487: void
488: debug_job_printf(const char *fmt, ...)
1.84 espie 489: {
490: if (DEBUG(JOB)) {
491: va_list va;
492: va_start(va, fmt);
1.128 espie 493: debug_vprintf(fmt, va);
494: va_end(va);
495: }
496: }
497:
498: static void
499: debug_kill_printf(const char *fmt, ...)
500: {
501: if (DEBUG(KILL)) {
502: va_list va;
503: va_start(va, fmt);
504: debug_vprintf(fmt, va);
1.84 espie 505: va_end(va);
506: }
507: }
1.119 espie 508:
1.1 deraadt 509: /*-
510: *-----------------------------------------------------------------------
1.124 espie 511: * postprocess_job --
512: * Do final processing for the given job including updating
1.119 espie 513: * parents and starting new jobs as available/necessary.
1.1 deraadt 514: *
515: * Side Effects:
1.6 millert 516: * If we got an error and are aborting (aborting == ABORT_ERROR) and
1.1 deraadt 517: * the job list is now empty, we are done for the day.
1.101 espie 518: * If we recognized an error we set the aborting flag
1.1 deraadt 519: * to ABORT_ERROR so no more jobs will be started.
520: *-----------------------------------------------------------------------
521: */
522: /*ARGSUSED*/
1.112 espie 523:
1.1 deraadt 524: static void
1.142 espie 525: postprocess_job(Job *job)
1.2 deraadt 526: {
1.142 espie 527: if (job->exit_type == JOB_EXIT_OKAY &&
1.66 espie 528: aborting != ABORT_ERROR &&
1.124 espie 529: aborting != ABORT_INTERRUPT) {
1.66 espie 530: /* As long as we aren't aborting and the job didn't return a
531: * non-zero status that we shouldn't ignore, we call
1.101 espie 532: * Make_Update to update the parents. */
1.141 espie 533: job->node->built_status = REBUILT;
1.155 espie 534: engine_node_updated(job->node);
1.152 espie 535: }
536: if (job->flags & JOB_KEEPERROR) {
537: job->next = errorJobs;
538: errorJobs = job;
539: } else {
1.148 espie 540: job->next = availableJobs;
541: availableJobs = job;
542: }
1.1 deraadt 543:
1.145 espie 544: if (errorJobs != NULL && aborting != ABORT_INTERRUPT)
1.66 espie 545: aborting = ABORT_ERROR;
1.6 millert 546:
1.124 espie 547: if (aborting == ABORT_ERROR && DEBUG(QUICKDEATH))
1.126 espie 548: handle_fatal_signal(SIGINT);
1.117 espie 549: if (aborting == ABORT_ERROR && Job_Empty())
1.124 espie 550: Finish();
1.1 deraadt 551: }
552:
1.124 espie 553: /* expensive jobs handling: in order to avoid forking an exponential number
554: * of jobs, make tries to figure out "recursive make" configurations.
555: * It may err on the side of caution.
556: * Basically, a command is "expensive" if it's likely to fork an extra
557: * level of make: either by looking at the command proper, or if it has
558: * some specific qualities ('+cmd' are likely to be recursive, as are
559: * .MAKE: commands). It's possible to explicitly say some targets are
560: * expensive or cheap with .EXPENSIVE or .CHEAP.
561: *
562: * While an expensive command is running, no_new_jobs
563: * is set, so jobs that would fork new processes are accumulated in the
564: * heldJobs list instead.
565: *
1.147 espie 566: * XXX This heuristics is also used on error exit: we display silent commands
567: * that failed, unless those ARE expensive commands: expensive commands are
568: * likely to not be failing by themselves, but to be the result of a cascade of
569: * failures in descendant makes.
1.124 espie 570: */
571: void
572: determine_expensive_job(Job *job)
573: {
574: if (expensive_job(job)) {
575: job->flags |= JOB_IS_EXPENSIVE;
576: no_new_jobs = true;
577: } else
578: job->flags &= ~JOB_IS_EXPENSIVE;
579: if (DEBUG(EXPENSIVE))
580: fprintf(stderr, "[%ld] Target %s running %.50s: %s\n",
581: (long)mypid, job->node->name, job->cmd,
582: job->flags & JOB_IS_EXPENSIVE ? "expensive" : "cheap");
1.101 espie 583: }
584:
1.124 espie 585: static bool
586: expensive_job(Job *job)
1.1 deraadt 587: {
1.124 espie 588: if (job->node->type & OP_CHEAP)
589: return false;
590: if (job->node->type & (OP_EXPENSIVE | OP_MAKE))
591: return true;
592: return expensive_command(job->cmd);
1.96 espie 593: }
594:
1.117 espie 595: static bool
596: expensive_command(const char *s)
1.1 deraadt 597: {
1.117 espie 598: const char *p;
599: bool include = false;
600: bool expensive = false;
1.66 espie 601:
1.117 espie 602: /* okay, comments are cheap, always */
603: if (*s == '#')
604: return false;
1.124 espie 605: /* and commands we always execute are expensive */
606: if (*s == '+')
607: return true;
1.66 espie 608:
1.117 espie 609: for (p = s; *p != '\0'; p++) {
610: if (*p == ' ' || *p == '\t') {
611: include = false;
612: if (p[1] == '-' && p[2] == 'I')
613: include = true;
614: }
615: if (include)
616: continue;
617: /* KMP variant, avoid looking twice at the same
618: * letter.
619: */
620: if (*p != 'm')
621: continue;
622: if (p[1] != 'a')
623: continue;
624: p++;
625: if (p[1] != 'k')
626: continue;
627: p++;
628: if (p[1] != 'e')
629: continue;
630: p++;
631: expensive = true;
632: while (p[1] != '\0' && p[1] != ' ' && p[1] != '\t') {
1.124 espie 633: if (p[1] == '.' || p[1] == '/') {
1.117 espie 634: expensive = false;
635: break;
1.66 espie 636: }
1.117 espie 637: p++;
1.1 deraadt 638: }
1.117 espie 639: if (expensive)
640: return true;
1.1 deraadt 641: }
1.117 espie 642: return false;
643: }
644:
1.124 espie 645: static void
646: may_continue_job(Job *job)
647: {
648: if (no_new_jobs) {
649: if (DEBUG(EXPENSIVE))
650: fprintf(stderr, "[%ld] expensive -> hold %s\n",
651: (long)mypid, job->node->name);
652: job->next = heldJobs;
653: heldJobs = job;
1.151 espie 654: } else {
655: bool finished = job_run_next(job);
656: if (finished)
657: postprocess_job(job);
658: else if (!sequential)
659: determine_expensive_job(job);
660: }
1.98 espie 661: }
1.1 deraadt 662:
1.158 ! espie 663: static void
! 664: may_continue_heldback_jobs()
! 665: {
! 666: while (!no_new_jobs) {
! 667: if (heldJobs != NULL) {
! 668: Job *job = heldJobs;
! 669: heldJobs = heldJobs->next;
! 670: if (DEBUG(EXPENSIVE))
! 671: fprintf(stderr, "[%ld] cheap -> release %s\n",
! 672: (long)mypid, job->node->name);
! 673: may_continue_job(job);
! 674: } else
! 675: break;
! 676: }
! 677: }
! 678:
1.98 espie 679: /*-
680: *-----------------------------------------------------------------------
1.124 espie 681: * Job_Make --
1.98 espie 682: * Start a target-creation process going for the target described
683: * by the graph node gn.
684: *
685: * Side Effects:
1.124 espie 686: * A new Job node is created and its commands continued, which
687: * may fork the first command of that job.
1.98 espie 688: *-----------------------------------------------------------------------
689: */
1.124 espie 690: void
691: Job_Make(GNode *gn)
1.98 espie 692: {
1.154 espie 693: Job *job = availableJobs;
1.124 espie 694:
1.154 espie 695: assert(job != NULL);
696: availableJobs = availableJobs->next;
697: job_attach_node(job, gn);
1.124 espie 698: may_continue_job(job);
1.1 deraadt 699: }
700:
1.101 espie 701: static void
1.124 espie 702: determine_job_next_step(Job *job)
1.2 deraadt 703: {
1.124 espie 704: if (job->flags & JOB_IS_EXPENSIVE) {
705: no_new_jobs = false;
706: if (DEBUG(EXPENSIVE))
707: fprintf(stderr, "[%ld] "
708: "Returning from expensive target %s, "
709: "allowing new jobs\n", (long)mypid,
710: job->node->name);
711: }
1.2 deraadt 712:
1.142 espie 713: if (job->exit_type != JOB_EXIT_OKAY || job->next_cmd == NULL)
1.150 espie 714: postprocess_job(job);
1.124 espie 715: else
716: may_continue_job(job);
1.2 deraadt 717: }
1.111 espie 718:
1.124 espie 719: /*
720: * job = reap_finished_job(pid):
721: * retrieve and remove a job from runningJobs, based on its pid
1.1 deraadt 722: *
1.124 espie 723: * Note that we remove it right away, so that handle_signals()
724: * is accurate.
1.1 deraadt 725: */
1.124 espie 726: static Job *
727: reap_finished_job(pid_t pid)
1.66 espie 728: {
1.124 espie 729: Job **j, *job;
1.1 deraadt 730:
1.124 espie 731: for (j = &runningJobs; *j != NULL; j = &((*j)->next))
732: if ((*j)->pid == pid) {
733: job = *j;
734: *j = job->next;
735: return job;
1.66 espie 736: }
1.1 deraadt 737:
1.124 espie 738: return NULL;
1.101 espie 739: }
1.6 millert 740:
1.124 espie 741: /*
742: * classic waitpid handler: retrieve as many dead children as possible.
743: * returns true if succesful
744: */
745: static bool
746: reap_jobs(void)
1.117 espie 747: {
1.124 espie 748: pid_t pid; /* pid of dead child */
749: int status; /* Exit/termination status */
750: bool reaped = false;
1.117 espie 751: Job *job;
752:
753: while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) {
1.124 espie 754: reaped = true;
755: job = reap_finished_job(pid);
1.1 deraadt 756:
1.124 espie 757: if (job == NULL) {
758: Punt("Child (%ld) not in table?", (long)pid);
1.66 espie 759: } else {
1.149 espie 760: handle_job_status(job, status);
1.124 espie 761: determine_job_next_step(job);
1.1 deraadt 762: }
1.146 espie 763: may_continue_heldback_jobs();
1.1 deraadt 764: }
1.124 espie 765: /* sanity check, should not happen */
766: if (pid == -1 && errno == ECHILD && runningJobs != NULL)
767: Punt("Process has no children, but runningJobs is not empty ?");
768: return reaped;
1.1 deraadt 769: }
770:
771: void
1.124 espie 772: handle_running_jobs(void)
1.1 deraadt 773: {
1.124 espie 774: sigset_t old;
775: /* reaping children in the presence of caught signals */
1.91 espie 776:
1.124 espie 777: /* first, we make sure to hold on new signals, to synchronize
778: * reception of new stuff on sigsuspend
779: */
780: sigprocmask(SIG_BLOCK, &sigset, &old);
1.135 espie 781: /* note this will NOT loop until runningJobs == NULL.
782: * It's merely an optimisation, namely that we don't need to go
783: * through the logic if no job is present. As soon as a job
784: * gets reaped, we WILL exit the loop through the break.
785: */
1.124 espie 786: while (runningJobs != NULL) {
787: /* did we already have pending stuff that advances things ?
788: * then handle_all_signals() will not return
789: * or reap_jobs() will reap_jobs()
790: */
791: handle_all_signals();
792: if (reap_jobs())
793: break;
794: /* okay, so it's safe to suspend, we have nothing to do but
795: * wait...
796: */
797: sigsuspend(&emptyset);
1.1 deraadt 798: }
1.124 espie 799: sigprocmask(SIG_SETMASK, &old, NULL);
1.1 deraadt 800: }
801:
1.111 espie 802: void
803: loop_handle_running_jobs()
804: {
1.124 espie 805: while (runningJobs != NULL)
1.111 espie 806: handle_running_jobs();
807: }
1.1 deraadt 808:
809: void
1.155 espie 810: Job_Init(int maxJobs)
1.1 deraadt 811: {
1.148 espie 812: Job *j;
813: int i;
814:
1.124 espie 815: runningJobs = NULL;
816: heldJobs = NULL;
817: errorJobs = NULL;
1.148 espie 818: availableJobs = NULL;
819: sequential = maxJobs == 1;
820:
821: /* we allocate n+1 jobs, since we may need an extra job for
822: * running .INTERRUPT. */
823: j = ereallocarray(NULL, sizeof(Job), maxJobs+1);
824: for (i = 0; i != maxJobs; i++) {
825: j[i].next = availableJobs;
826: availableJobs = &j[i];
827: }
828: extra_job = &j[maxJobs];
1.124 espie 829: mypid = getpid();
830:
1.117 espie 831: aborting = 0;
1.124 espie 832: setup_all_signals();
1.1 deraadt 833: }
834:
1.41 espie 835: bool
1.117 espie 836: can_start_job(void)
1.1 deraadt 837: {
1.148 espie 838: if (aborting || availableJobs == NULL)
1.117 espie 839: return false;
1.119 espie 840: else
1.117 espie 841: return true;
1.1 deraadt 842: }
843:
1.41 espie 844: bool
1.56 espie 845: Job_Empty(void)
1.1 deraadt 846: {
1.124 espie 847: return runningJobs == NULL;
1.1 deraadt 848: }
849:
850: /*-
851: *-----------------------------------------------------------------------
1.126 espie 852: * handle_fatal_signal --
853: * Handle the receipt of a fatal interrupt
1.1 deraadt 854: *
855: * Side Effects:
1.126 espie 856: * All children are killed. Another job may be started if there
857: * is an interrupt target and the signal was SIGINT.
1.1 deraadt 858: *-----------------------------------------------------------------------
859: */
860: static void
1.126 espie 861: handle_fatal_signal(int signo)
1.1 deraadt 862: {
1.124 espie 863: Job *job;
1.66 espie 864:
1.128 espie 865: debug_kill_printf("handle_fatal_signal(%d) called.\n", signo);
1.66 espie 866:
1.131 espie 867: dying_signal = signo;
1.124 espie 868: for (job = runningJobs; job != NULL; job = job->next) {
1.128 espie 869: debug_kill_printf("passing to "
870: "child %ld running %s: %s\n", (long)job->pid,
871: job->node->name, really_kill(job, signo));
872: may_remove_target(job);
1.2 deraadt 873: }
1.1 deraadt 874:
1.124 espie 875: if (signo == SIGINT && !touchFlag) {
1.78 espie 876: if ((interrupt_node->type & OP_DUMMY) == 0) {
1.66 espie 877: ignoreErrors = false;
1.148 espie 878: extra_job->next = availableJobs;
879: availableJobs = extra_job;
1.124 espie 880: Job_Make(interrupt_node);
1.66 espie 881: }
1.1 deraadt 882: }
1.124 espie 883: loop_handle_running_jobs();
1.131 espie 884: internal_print_errors();
1.124 espie 885:
886: /* die by that signal */
887: sigprocmask(SIG_BLOCK, &sigset, NULL);
888: signal(signo, SIG_DFL);
1.126 espie 889: kill(getpid(), signo);
1.124 espie 890: sigprocmask(SIG_SETMASK, &emptyset, NULL);
891: /*NOTREACHED*/
1.131 espie 892: fprintf(stderr, "This should never happen\n");
893: exit(1);
1.124 espie 894: }
895:
1.1 deraadt 896: /*-
897: *-----------------------------------------------------------------------
898: * Job_Wait --
899: * Waits for all running jobs to finish and returns. Sets 'aborting'
900: * to ABORT_WAIT to prevent other jobs from starting.
901: *
902: * Side Effects:
903: * Currently running jobs finish.
904: *
905: *-----------------------------------------------------------------------
906: */
907: void
1.56 espie 908: Job_Wait(void)
1.1 deraadt 909: {
1.66 espie 910: aborting = ABORT_WAIT;
1.111 espie 911: loop_handle_running_jobs();
1.66 espie 912: aborting = 0;
1.1 deraadt 913: }
914:
915: /*-
916: *-----------------------------------------------------------------------
917: * Job_AbortAll --
918: * Abort all currently running jobs without handling output or anything.
919: * This function is to be called only in the event of a major
1.124 espie 920: * error.
1.1 deraadt 921: *
922: * Side Effects:
1.124 espie 923: * All children are killed
1.1 deraadt 924: *-----------------------------------------------------------------------
925: */
926: void
1.56 espie 927: Job_AbortAll(void)
1.1 deraadt 928: {
1.66 espie 929: Job *job; /* the job descriptor in that element */
930: int foo;
1.6 millert 931:
1.66 espie 932: aborting = ABORT_ERROR;
1.6 millert 933:
1.124 espie 934: for (job = runningJobs; job != NULL; job = job->next) {
1.126 espie 935: killpg(job->pid, SIGINT);
936: killpg(job->pid, SIGKILL);
1.1 deraadt 937: }
1.6 millert 938:
1.66 espie 939: /*
940: * Catch as many children as want to report in at first, then give up
941: */
1.117 espie 942: while (waitpid(WAIT_ANY, &foo, WNOHANG) > 0)
1.66 espie 943: continue;
1.2 deraadt 944: }