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