Annotation of src/usr.bin/make/job.c, Revision 1.162
1.162 ! espie 1: /* $OpenBSD: job.c,v 1.161 2020/06/02 12:24:09 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.159 espie 132: static sigset_t sigset, emptyset, origset;
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: } else {
167: if (kill(pid, signo) == 0)
168: return "process got signal";
169: }
1.138 natano 170: if (errno == ESRCH)
1.128 espie 171: job->flags |= JOB_LOST;
1.138 natano 172: return strerror(errno);
1.128 espie 173: }
174:
175: static void
176: may_remove_target(Job *j)
177: {
1.131 espie 178: int dying = check_dying_signal();
179:
180: if (dying && !noExecute && !Targ_Precious(j->node)) {
1.128 espie 181: const char *file = Var(TARGET_INDEX, j->node);
182: int r = eunlink(file);
183:
184: if (DEBUG(JOB) && r == -1)
185: fprintf(stderr, " *** would unlink %s\n", file);
186: if (r != -1)
187: fprintf(stderr, " *** %s removed\n", file);
1.127 espie 188: }
189: }
1.126 espie 190:
1.131 espie 191: static void
192: buf_addcurdir(BUFFER *buf)
193: {
194: const char *v = Var_Value(".CURDIR");
195: if (basedirectory != NULL) {
196: size_t len = strlen(basedirectory);
197: if (strncmp(basedirectory, v, len) == 0 &&
198: v[len] == '/') {
199: v += len+1;
200: } else if (strcmp(basedirectory, v) == 0) {
201: Buf_AddString(buf, ".");
202: return;
203: }
204: }
205: Buf_AddString(buf, v);
206: }
207:
208: static const char *
209: shortened_curdir(void)
210: {
211: static BUFFER buf;
1.140 espie 212: static bool first = true;
1.131 espie 213: if (first) {
214: Buf_Init(&buf, 0);
215: buf_addcurdir(&buf);
216: first = false;
217: }
218: return Buf_Retrieve(&buf);
219: }
220:
221: static void
222: quick_error(Job *j, int signo, bool first)
223: {
224: if (first) {
225: fprintf(stderr, "*** Signal SIG%s", sys_signame[signo]);
226: fprintf(stderr, " in %s (", shortened_curdir());
227: } else
228: fprintf(stderr, " ");
229:
230: fprintf(stderr, "%s", j->node->name);
231: free(j->cmd);
232: }
233:
1.126 espie 234: static void
1.130 espie 235: print_error(Job *j)
1.126 espie 236: {
1.130 espie 237: static bool first = true;
1.131 espie 238: BUFFER buf;
239:
240: Buf_Init(&buf, 0);
1.126 espie 241:
1.131 espie 242: if (j->exit_type == JOB_EXIT_BAD)
243: Buf_printf(&buf, "*** Error %d", j->code);
244: else if (j->exit_type == JOB_SIGNALED) {
1.128 espie 245: if (j->code < NSIG)
1.131 espie 246: Buf_printf(&buf, "*** Signal SIG%s",
1.128 espie 247: sys_signame[j->code]);
248: else
1.131 espie 249: Buf_printf(&buf, "*** unknown signal %d", j->code);
1.128 espie 250: } else
1.131 espie 251: Buf_printf(&buf, "*** Should not happen %d/%d",
252: j->exit_type, j->code);
1.128 espie 253: if (DEBUG(KILL) && (j->flags & JOB_LOST))
1.131 espie 254: Buf_AddChar(&buf, '!');
1.130 espie 255: if (first) {
1.131 espie 256: Buf_AddString(&buf, " in ");
257: buf_addcurdir(&buf);
1.130 espie 258: first = false;
259: }
1.131 espie 260: Buf_printf(&buf, " (%s:%lu", j->location->fname, j->location->lineno);
261: Buf_printf(&buf, " '%s'", j->node->name);
262: if ((j->flags & (JOB_SILENT | JOB_IS_EXPENSIVE)) == JOB_SILENT
1.132 espie 263: && Buf_Size(&buf) < 140-2) {
1.131 espie 264: size_t len = strlen(j->cmd);
265: Buf_AddString(&buf, ": ");
266: if (len + Buf_Size(&buf) < 140)
267: Buf_AddString(&buf, j->cmd);
268: else {
269: Buf_AddChars(&buf, 140 - Buf_Size(&buf), j->cmd);
270: Buf_AddString(&buf, "...");
271: }
272: }
273: fprintf(stderr, "%s)\n", Buf_Retrieve(&buf));
274: Buf_Destroy(&buf);
1.126 espie 275: free(j->cmd);
1.131 espie 276: }
277: static void
278: quick_summary(int signo)
279: {
280: Job *j, *k, *jnext;
281: bool first = true;
282:
283: k = errorJobs;
284: errorJobs = NULL;
285: for (j = k; j != NULL; j = jnext) {
286: jnext = j->next;
287: if ((j->exit_type == JOB_EXIT_BAD && j->code == signo+128) ||
288: (j->exit_type == JOB_SIGNALED && j->code == signo)) {
289: quick_error(j, signo, first);
290: first = false;
291: } else {
292: j->next = errorJobs;
293: errorJobs = j;
294: }
295: }
296: if (!first)
297: fprintf(stderr, ")\n");
1.126 espie 298: }
1.93 espie 299:
1.131 espie 300: static void
301: internal_print_errors()
1.101 espie 302: {
1.126 espie 303: Job *j, *k, *jnext;
1.131 espie 304: int dying;
1.124 espie 305:
1.130 espie 306: if (!errorJobs)
1.133 espie 307: fprintf(stderr, "Stop in %s\n", shortened_curdir());
1.1 deraadt 308:
1.131 espie 309: for (j = errorJobs; j != NULL; j = j->next)
310: may_remove_target(j);
311: dying = check_dying_signal();
312: if (dying)
313: quick_summary(dying);
1.143 espie 314: /* Print errors grouped by file name. */
1.126 espie 315: while (errorJobs != NULL) {
1.143 espie 316: /* Select the first job. */
1.126 espie 317: k = errorJobs;
318: errorJobs = NULL;
319: for (j = k; j != NULL; j = jnext) {
320: jnext = j->next;
321: if (j->location->fname == k->location->fname)
1.143 espie 322: /* Print errors with the same filename. */
1.130 espie 323: print_error(j);
1.126 espie 324: else {
1.143 espie 325: /* Keep others for the next iteration. */
1.126 espie 326: j->next = errorJobs;
327: errorJobs = j;
328: }
329: }
1.101 espie 330: }
1.88 espie 331: }
332:
1.131 espie 333: void
334: print_errors(void)
335: {
336: handle_all_signals();
337: internal_print_errors();
338: }
339:
1.57 espie 340: static void
1.124 espie 341: setup_signal(int sig)
1.57 espie 342: {
1.124 espie 343: if (signal(sig, SIG_IGN) != SIG_IGN) {
344: (void)signal(sig, notice_signal);
345: sigaddset(&sigset, sig);
1.57 espie 346: }
347: }
348:
349: static void
1.124 espie 350: notice_signal(int sig)
1.1 deraadt 351: {
1.126 espie 352:
1.124 espie 353: switch(sig) {
1.117 espie 354: case SIGINT:
355: got_SIGINT++;
1.124 espie 356: got_fatal = 1;
357: break;
1.117 espie 358: case SIGHUP:
359: got_SIGHUP++;
1.124 espie 360: got_fatal = 1;
361: break;
1.117 espie 362: case SIGQUIT:
363: got_SIGQUIT++;
1.124 espie 364: got_fatal = 1;
365: break;
1.117 espie 366: case SIGTERM:
367: got_SIGTERM++;
1.124 espie 368: got_fatal = 1;
1.117 espie 369: break;
1.124 espie 370: case SIGINFO:
371: got_SIGINFO++;
1.117 espie 372: break;
1.124 espie 373: case SIGCHLD:
1.117 espie 374: break;
1.66 espie 375: }
1.124 espie 376: }
1.117 espie 377:
1.159 espie 378: void
379: Sigset_Init()
380: {
381: sigemptyset(&emptyset);
382: sigprocmask(SIG_BLOCK, &emptyset, &origset);
383: }
384:
1.135 espie 385: static void
1.124 espie 386: setup_all_signals(void)
387: {
388: sigemptyset(&sigset);
389: /*
390: * Catch the four signals that POSIX specifies if they aren't ignored.
391: * handle_signal will take care of calling JobInterrupt if appropriate.
392: */
393: setup_signal(SIGINT);
394: setup_signal(SIGHUP);
395: setup_signal(SIGQUIT);
396: setup_signal(SIGTERM);
397: /* Display running jobs on SIGINFO */
398: setup_signal(SIGINFO);
399: /* Have to see SIGCHLD */
400: setup_signal(SIGCHLD);
401: got_fatal = 0;
1.1 deraadt 402: }
403:
1.124 espie 404: static void
405: handle_siginfo(void)
1.1 deraadt 406: {
1.126 espie 407: static BUFFER buf;
408: static size_t length = 0;
409:
1.124 espie 410: Job *job;
411: bool first = true;
1.66 espie 412:
1.124 espie 413: got_SIGINFO = 0;
414: /* we have to store the info in a buffer, because status from all
415: * makes running would get intermixed otherwise
1.66 espie 416: */
1.124 espie 417:
1.126 espie 418: if (length == 0) {
419: Buf_Init(&buf, 0);
1.131 espie 420: Buf_printf(&buf, "%s in ", Var_Value("MAKE"));
421: buf_addcurdir(&buf);
422: Buf_AddString(&buf, ": ");
1.126 espie 423: length = Buf_Size(&buf);
424: } else
425: Buf_Truncate(&buf, length);
1.124 espie 426:
427: for (job = runningJobs; job != NULL ; job = job->next) {
428: if (!first)
429: Buf_puts(&buf, ", ");
430: first = false;
431: Buf_puts(&buf, job->node->name);
432: }
433: Buf_puts(&buf, first ? "nothing running\n" : "\n");
1.1 deraadt 434:
1.124 espie 435: fputs(Buf_Retrieve(&buf), stderr);
1.1 deraadt 436: }
437:
1.131 espie 438: int
439: check_dying_signal(void)
440: {
441: sigset_t set;
442: if (dying_signal)
443: return dying_signal;
444: sigpending(&set);
445: if (got_SIGINT || sigismember(&set, SIGINT))
446: return dying_signal = SIGINT;
447: if (got_SIGHUP || sigismember(&set, SIGHUP))
448: return dying_signal = SIGHUP;
449: if (got_SIGQUIT || sigismember(&set, SIGQUIT))
450: return dying_signal = SIGQUIT;
451: if (got_SIGTERM || sigismember(&set, SIGTERM))
452: return dying_signal = SIGTERM;
453: return 0;
454: }
455:
1.124 espie 456: void
457: handle_all_signals(void)
1.1 deraadt 458: {
1.124 espie 459: if (got_SIGINFO)
460: handle_siginfo();
461: while (got_fatal) {
462: got_fatal = 0;
463: aborting = ABORT_INTERRUPT;
464:
465: if (got_SIGINT) {
466: got_SIGINT=0;
1.126 espie 467: handle_fatal_signal(SIGINT);
1.124 espie 468: }
469: if (got_SIGHUP) {
470: got_SIGHUP=0;
1.126 espie 471: handle_fatal_signal(SIGHUP);
1.124 espie 472: }
473: if (got_SIGQUIT) {
474: got_SIGQUIT=0;
1.126 espie 475: handle_fatal_signal(SIGQUIT);
1.124 espie 476: }
477: if (got_SIGTERM) {
478: got_SIGTERM=0;
1.126 espie 479: handle_fatal_signal(SIGTERM);
1.124 espie 480: }
481: }
1.1 deraadt 482: }
483:
1.128 espie 484: static void
485: debug_vprintf(const char *fmt, va_list va)
486: {
487: (void)printf("[%ld] ", (long)mypid);
488: (void)vprintf(fmt, va);
489: fflush(stdout);
490: }
491:
1.124 espie 492: void
493: debug_job_printf(const char *fmt, ...)
1.84 espie 494: {
495: if (DEBUG(JOB)) {
496: va_list va;
497: va_start(va, fmt);
1.128 espie 498: debug_vprintf(fmt, va);
499: va_end(va);
500: }
501: }
502:
503: static void
504: debug_kill_printf(const char *fmt, ...)
505: {
506: if (DEBUG(KILL)) {
507: va_list va;
508: va_start(va, fmt);
509: debug_vprintf(fmt, va);
1.84 espie 510: va_end(va);
511: }
512: }
1.119 espie 513:
1.1 deraadt 514: /*-
515: *-----------------------------------------------------------------------
1.124 espie 516: * postprocess_job --
517: * Do final processing for the given job including updating
1.119 espie 518: * parents and starting new jobs as available/necessary.
1.1 deraadt 519: *
520: * Side Effects:
1.6 millert 521: * If we got an error and are aborting (aborting == ABORT_ERROR) and
1.1 deraadt 522: * the job list is now empty, we are done for the day.
1.101 espie 523: * If we recognized an error we set the aborting flag
1.1 deraadt 524: * to ABORT_ERROR so no more jobs will be started.
525: *-----------------------------------------------------------------------
526: */
527: /*ARGSUSED*/
1.112 espie 528:
1.1 deraadt 529: static void
1.142 espie 530: postprocess_job(Job *job)
1.2 deraadt 531: {
1.142 espie 532: if (job->exit_type == JOB_EXIT_OKAY &&
1.66 espie 533: aborting != ABORT_ERROR &&
1.124 espie 534: aborting != ABORT_INTERRUPT) {
1.66 espie 535: /* As long as we aren't aborting and the job didn't return a
536: * non-zero status that we shouldn't ignore, we call
1.101 espie 537: * Make_Update to update the parents. */
1.141 espie 538: job->node->built_status = REBUILT;
1.155 espie 539: engine_node_updated(job->node);
1.152 espie 540: }
541: if (job->flags & JOB_KEEPERROR) {
542: job->next = errorJobs;
543: errorJobs = job;
544: } else {
1.148 espie 545: job->next = availableJobs;
546: availableJobs = job;
547: }
1.1 deraadt 548:
1.145 espie 549: if (errorJobs != NULL && aborting != ABORT_INTERRUPT)
1.66 espie 550: aborting = ABORT_ERROR;
1.6 millert 551:
1.124 espie 552: if (aborting == ABORT_ERROR && DEBUG(QUICKDEATH))
1.126 espie 553: handle_fatal_signal(SIGINT);
1.117 espie 554: if (aborting == ABORT_ERROR && Job_Empty())
1.124 espie 555: Finish();
1.1 deraadt 556: }
557:
1.124 espie 558: /* expensive jobs handling: in order to avoid forking an exponential number
559: * of jobs, make tries to figure out "recursive make" configurations.
560: * It may err on the side of caution.
561: * Basically, a command is "expensive" if it's likely to fork an extra
562: * level of make: either by looking at the command proper, or if it has
563: * some specific qualities ('+cmd' are likely to be recursive, as are
564: * .MAKE: commands). It's possible to explicitly say some targets are
565: * expensive or cheap with .EXPENSIVE or .CHEAP.
566: *
567: * While an expensive command is running, no_new_jobs
568: * is set, so jobs that would fork new processes are accumulated in the
569: * heldJobs list instead.
570: *
1.147 espie 571: * XXX This heuristics is also used on error exit: we display silent commands
572: * that failed, unless those ARE expensive commands: expensive commands are
573: * likely to not be failing by themselves, but to be the result of a cascade of
574: * failures in descendant makes.
1.124 espie 575: */
576: void
577: determine_expensive_job(Job *job)
578: {
579: if (expensive_job(job)) {
580: job->flags |= JOB_IS_EXPENSIVE;
581: no_new_jobs = true;
582: } else
583: job->flags &= ~JOB_IS_EXPENSIVE;
584: if (DEBUG(EXPENSIVE))
585: fprintf(stderr, "[%ld] Target %s running %.50s: %s\n",
586: (long)mypid, job->node->name, job->cmd,
587: job->flags & JOB_IS_EXPENSIVE ? "expensive" : "cheap");
1.101 espie 588: }
589:
1.124 espie 590: static bool
591: expensive_job(Job *job)
1.1 deraadt 592: {
1.124 espie 593: if (job->node->type & OP_CHEAP)
594: return false;
595: if (job->node->type & (OP_EXPENSIVE | OP_MAKE))
596: return true;
597: return expensive_command(job->cmd);
1.96 espie 598: }
599:
1.117 espie 600: static bool
601: expensive_command(const char *s)
1.1 deraadt 602: {
1.117 espie 603: const char *p;
604: bool include = false;
605: bool expensive = false;
1.66 espie 606:
1.117 espie 607: /* okay, comments are cheap, always */
608: if (*s == '#')
609: return false;
1.124 espie 610: /* and commands we always execute are expensive */
611: if (*s == '+')
612: return true;
1.66 espie 613:
1.117 espie 614: for (p = s; *p != '\0'; p++) {
615: if (*p == ' ' || *p == '\t') {
616: include = false;
617: if (p[1] == '-' && p[2] == 'I')
618: include = true;
619: }
620: if (include)
621: continue;
622: /* KMP variant, avoid looking twice at the same
623: * letter.
624: */
625: if (*p != 'm')
626: continue;
627: if (p[1] != 'a')
628: continue;
629: p++;
630: if (p[1] != 'k')
631: continue;
632: p++;
633: if (p[1] != 'e')
634: continue;
635: p++;
636: expensive = true;
637: while (p[1] != '\0' && p[1] != ' ' && p[1] != '\t') {
1.124 espie 638: if (p[1] == '.' || p[1] == '/') {
1.117 espie 639: expensive = false;
640: break;
1.66 espie 641: }
1.117 espie 642: p++;
1.1 deraadt 643: }
1.117 espie 644: if (expensive)
645: return true;
1.1 deraadt 646: }
1.117 espie 647: return false;
648: }
649:
1.124 espie 650: static void
651: may_continue_job(Job *job)
652: {
653: if (no_new_jobs) {
654: if (DEBUG(EXPENSIVE))
655: fprintf(stderr, "[%ld] expensive -> hold %s\n",
656: (long)mypid, job->node->name);
657: job->next = heldJobs;
658: heldJobs = job;
1.151 espie 659: } else {
660: bool finished = job_run_next(job);
661: if (finished)
662: postprocess_job(job);
663: else if (!sequential)
664: determine_expensive_job(job);
665: }
1.98 espie 666: }
1.1 deraadt 667:
1.158 espie 668: static void
669: may_continue_heldback_jobs()
670: {
671: while (!no_new_jobs) {
672: if (heldJobs != NULL) {
673: Job *job = heldJobs;
674: heldJobs = heldJobs->next;
675: if (DEBUG(EXPENSIVE))
676: fprintf(stderr, "[%ld] cheap -> release %s\n",
677: (long)mypid, job->node->name);
678: may_continue_job(job);
679: } else
680: break;
681: }
682: }
683:
1.98 espie 684: /*-
685: *-----------------------------------------------------------------------
1.124 espie 686: * Job_Make --
1.98 espie 687: * Start a target-creation process going for the target described
688: * by the graph node gn.
689: *
690: * Side Effects:
1.124 espie 691: * A new Job node is created and its commands continued, which
692: * may fork the first command of that job.
1.98 espie 693: *-----------------------------------------------------------------------
694: */
1.124 espie 695: void
696: Job_Make(GNode *gn)
1.98 espie 697: {
1.154 espie 698: Job *job = availableJobs;
1.124 espie 699:
1.154 espie 700: assert(job != NULL);
701: availableJobs = availableJobs->next;
702: job_attach_node(job, gn);
1.124 espie 703: may_continue_job(job);
1.1 deraadt 704: }
705:
1.101 espie 706: static void
1.124 espie 707: determine_job_next_step(Job *job)
1.2 deraadt 708: {
1.124 espie 709: if (job->flags & JOB_IS_EXPENSIVE) {
710: no_new_jobs = false;
711: if (DEBUG(EXPENSIVE))
712: fprintf(stderr, "[%ld] "
713: "Returning from expensive target %s, "
714: "allowing new jobs\n", (long)mypid,
715: job->node->name);
716: }
1.2 deraadt 717:
1.142 espie 718: if (job->exit_type != JOB_EXIT_OKAY || job->next_cmd == NULL)
1.150 espie 719: postprocess_job(job);
1.124 espie 720: else
721: may_continue_job(job);
1.2 deraadt 722: }
1.111 espie 723:
1.124 espie 724: /*
725: * job = reap_finished_job(pid):
726: * retrieve and remove a job from runningJobs, based on its pid
1.1 deraadt 727: *
1.124 espie 728: * Note that we remove it right away, so that handle_signals()
729: * is accurate.
1.1 deraadt 730: */
1.124 espie 731: static Job *
732: reap_finished_job(pid_t pid)
1.66 espie 733: {
1.124 espie 734: Job **j, *job;
1.1 deraadt 735:
1.124 espie 736: for (j = &runningJobs; *j != NULL; j = &((*j)->next))
737: if ((*j)->pid == pid) {
738: job = *j;
739: *j = job->next;
740: return job;
1.66 espie 741: }
1.1 deraadt 742:
1.124 espie 743: return NULL;
1.101 espie 744: }
1.6 millert 745:
1.124 espie 746: /*
747: * classic waitpid handler: retrieve as many dead children as possible.
748: * returns true if succesful
749: */
750: static bool
751: reap_jobs(void)
1.117 espie 752: {
1.124 espie 753: pid_t pid; /* pid of dead child */
754: int status; /* Exit/termination status */
755: bool reaped = false;
1.117 espie 756: Job *job;
757:
758: while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) {
1.160 espie 759: if (WIFSTOPPED(status))
760: continue;
1.124 espie 761: reaped = true;
762: job = reap_finished_job(pid);
1.1 deraadt 763:
1.124 espie 764: if (job == NULL) {
1.160 espie 765: Punt("Child (%ld) with status %d not in table?",
766: (long)pid, status);
1.66 espie 767: } else {
1.149 espie 768: handle_job_status(job, status);
1.124 espie 769: determine_job_next_step(job);
1.1 deraadt 770: }
1.146 espie 771: may_continue_heldback_jobs();
1.1 deraadt 772: }
1.124 espie 773: /* sanity check, should not happen */
774: if (pid == -1 && errno == ECHILD && runningJobs != NULL)
775: Punt("Process has no children, but runningJobs is not empty ?");
776: return reaped;
1.1 deraadt 777: }
778:
1.159 espie 779: void
780: reset_signal_mask()
781: {
782: sigprocmask(SIG_SETMASK, &origset, NULL);
783: }
784:
1.1 deraadt 785: void
1.124 espie 786: handle_running_jobs(void)
1.1 deraadt 787: {
1.124 espie 788: /* reaping children in the presence of caught signals */
1.91 espie 789:
1.124 espie 790: /* first, we make sure to hold on new signals, to synchronize
791: * reception of new stuff on sigsuspend
792: */
1.159 espie 793: sigprocmask(SIG_BLOCK, &sigset, NULL);
1.135 espie 794: /* note this will NOT loop until runningJobs == NULL.
795: * It's merely an optimisation, namely that we don't need to go
796: * through the logic if no job is present. As soon as a job
797: * gets reaped, we WILL exit the loop through the break.
798: */
1.124 espie 799: while (runningJobs != NULL) {
800: /* did we already have pending stuff that advances things ?
801: * then handle_all_signals() will not return
802: * or reap_jobs() will reap_jobs()
803: */
804: handle_all_signals();
805: if (reap_jobs())
806: break;
807: /* okay, so it's safe to suspend, we have nothing to do but
808: * wait...
809: */
810: sigsuspend(&emptyset);
1.1 deraadt 811: }
1.159 espie 812: reset_signal_mask();
1.1 deraadt 813: }
814:
1.111 espie 815: void
816: loop_handle_running_jobs()
817: {
1.124 espie 818: while (runningJobs != NULL)
1.111 espie 819: handle_running_jobs();
820: }
1.1 deraadt 821:
822: void
1.155 espie 823: Job_Init(int maxJobs)
1.1 deraadt 824: {
1.148 espie 825: Job *j;
826: int i;
827:
1.124 espie 828: runningJobs = NULL;
829: heldJobs = NULL;
830: errorJobs = NULL;
1.148 espie 831: availableJobs = NULL;
832: sequential = maxJobs == 1;
833:
834: /* we allocate n+1 jobs, since we may need an extra job for
835: * running .INTERRUPT. */
836: j = ereallocarray(NULL, sizeof(Job), maxJobs+1);
837: for (i = 0; i != maxJobs; i++) {
838: j[i].next = availableJobs;
839: availableJobs = &j[i];
840: }
841: extra_job = &j[maxJobs];
1.124 espie 842: mypid = getpid();
843:
1.117 espie 844: aborting = 0;
1.124 espie 845: setup_all_signals();
1.1 deraadt 846: }
847:
1.41 espie 848: bool
1.117 espie 849: can_start_job(void)
1.1 deraadt 850: {
1.148 espie 851: if (aborting || availableJobs == NULL)
1.117 espie 852: return false;
1.119 espie 853: else
1.117 espie 854: return true;
1.1 deraadt 855: }
856:
1.41 espie 857: bool
1.56 espie 858: Job_Empty(void)
1.1 deraadt 859: {
1.124 espie 860: return runningJobs == NULL;
1.1 deraadt 861: }
862:
863: /*-
864: *-----------------------------------------------------------------------
1.126 espie 865: * handle_fatal_signal --
866: * Handle the receipt of a fatal interrupt
1.1 deraadt 867: *
868: * Side Effects:
1.126 espie 869: * All children are killed. Another job may be started if there
870: * is an interrupt target and the signal was SIGINT.
1.1 deraadt 871: *-----------------------------------------------------------------------
872: */
873: static void
1.126 espie 874: handle_fatal_signal(int signo)
1.1 deraadt 875: {
1.124 espie 876: Job *job;
1.66 espie 877:
1.128 espie 878: debug_kill_printf("handle_fatal_signal(%d) called.\n", signo);
1.66 espie 879:
1.131 espie 880: dying_signal = signo;
1.124 espie 881: for (job = runningJobs; job != NULL; job = job->next) {
1.128 espie 882: debug_kill_printf("passing to "
883: "child %ld running %s: %s\n", (long)job->pid,
884: job->node->name, really_kill(job, signo));
885: may_remove_target(job);
1.2 deraadt 886: }
1.1 deraadt 887:
1.124 espie 888: if (signo == SIGINT && !touchFlag) {
1.78 espie 889: if ((interrupt_node->type & OP_DUMMY) == 0) {
1.66 espie 890: ignoreErrors = false;
1.148 espie 891: extra_job->next = availableJobs;
892: availableJobs = extra_job;
1.124 espie 893: Job_Make(interrupt_node);
1.66 espie 894: }
1.1 deraadt 895: }
1.124 espie 896: loop_handle_running_jobs();
1.131 espie 897: internal_print_errors();
1.124 espie 898:
899: /* die by that signal */
900: sigprocmask(SIG_BLOCK, &sigset, NULL);
901: signal(signo, SIG_DFL);
1.126 espie 902: kill(getpid(), signo);
1.124 espie 903: sigprocmask(SIG_SETMASK, &emptyset, NULL);
904: /*NOTREACHED*/
1.131 espie 905: fprintf(stderr, "This should never happen\n");
906: exit(1);
1.124 espie 907: }
908:
1.1 deraadt 909: /*-
910: *-----------------------------------------------------------------------
911: * Job_Wait --
912: * Waits for all running jobs to finish and returns. Sets 'aborting'
913: * to ABORT_WAIT to prevent other jobs from starting.
914: *
915: * Side Effects:
916: * Currently running jobs finish.
917: *
918: *-----------------------------------------------------------------------
919: */
920: void
1.56 espie 921: Job_Wait(void)
1.1 deraadt 922: {
1.66 espie 923: aborting = ABORT_WAIT;
1.111 espie 924: loop_handle_running_jobs();
1.66 espie 925: aborting = 0;
1.1 deraadt 926: }
927:
928: /*-
929: *-----------------------------------------------------------------------
930: * Job_AbortAll --
931: * Abort all currently running jobs without handling output or anything.
932: * This function is to be called only in the event of a major
1.124 espie 933: * error.
1.1 deraadt 934: *
935: * Side Effects:
1.124 espie 936: * All children are killed
1.1 deraadt 937: *-----------------------------------------------------------------------
938: */
939: void
1.56 espie 940: Job_AbortAll(void)
1.1 deraadt 941: {
1.66 espie 942: Job *job; /* the job descriptor in that element */
943: int foo;
1.6 millert 944:
1.66 espie 945: aborting = ABORT_ERROR;
1.6 millert 946:
1.124 espie 947: for (job = runningJobs; job != NULL; job = job->next) {
1.161 espie 948: debug_kill_printf("abort: send SIGINT to "
949: "child %ld running %s: %s\n",
950: (long)job->pid, job->node->name, really_kill(job, SIGINT));
951: debug_kill_printf("abort: send SIGKILL to "
952: "child %ld running %s: %s\n",
953: (long)job->pid, job->node->name, really_kill(job, SIGKILL));
1.1 deraadt 954: }
1.6 millert 955:
1.66 espie 956: /*
957: * Catch as many children as want to report in at first, then give up
958: */
1.117 espie 959: while (waitpid(WAIT_ANY, &foo, WNOHANG) > 0)
1.66 espie 960: continue;
1.2 deraadt 961: }