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