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