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