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