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