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