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