[BACK]Return to job.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / make

Annotation of src/usr.bin/make/job.c, Revision 1.130

1.130   ! espie       1: /*     $OpenBSD: job.c,v 1.129 2012/10/06 19:19:53 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 "";
1.130   ! espie     208:        } else
        !           209:                return "should not happen";
1.128     espie     210: }
                    211:
                    212: static void
                    213: may_remove_target(Job *j)
                    214: {
                    215:        if ((j->sent_signal == SIGINT || j->sent_signal == SIGQUIT ||
                    216:            j->sent_signal == SIGHUP || j->sent_signal == SIGTERM)
                    217:            && !noExecute && !Targ_Precious(j->node)) {
                    218:                const char *file = Var(TARGET_INDEX, j->node);
                    219:                int r = eunlink(file);
                    220:
                    221:                if (DEBUG(JOB) && r == -1)
                    222:                        fprintf(stderr, " *** would unlink %s\n", file);
                    223:                if (r != -1)
                    224:                        fprintf(stderr, " *** %s removed\n", file);
1.127     espie     225:        }
                    226: }
1.126     espie     227:
                    228: static void
1.130   ! espie     229: print_error(Job *j)
1.126     espie     230: {
1.130   ! espie     231:        static bool first = true;
1.126     espie     232:
1.128     espie     233:        if (j->exit_type == JOB_EXIT_BAD) {
                    234:                fprintf(stderr, "*** Error %d", j->code);
                    235:                if (j->sent_signal != 0 && j->code == j->sent_signal + 128)
                    236:                        fprintf(stderr, " (SIG%s in shell)",
                    237:                            sys_signame[j->sent_signal]);
                    238:        } else if (j->exit_type == JOB_SIGNALED) {
                    239:                if (j->code < NSIG)
1.130   ! espie     240:                        fprintf(stderr, "*** Signal SIG%s",
1.128     espie     241:                            sys_signame[j->code]);
                    242:                else
                    243:                        fprintf(stderr, "*** unknown signal %d", j->code);
                    244:        } else
                    245:                fprintf(stderr, "*** Should not happen %d", j->code);
                    246:        if (DEBUG(KILL) && (j->flags & JOB_LOST))
                    247:                fprintf(stderr, "!");
1.130   ! espie     248:        if (first) {
        !           249:                fprintf(stderr, " in %s", Var_Value(".CURDIR"));
        !           250:                first = false;
        !           251:        }
        !           252:        fprintf(stderr, " (%s:%lu", j->location->fname, j->location->lineno);
        !           253:        fprintf(stderr, " '%s'", j->node->name);
1.126     espie     254:        if ((j->flags & (JOB_SILENT | JOB_IS_EXPENSIVE)) == JOB_SILENT)
1.130   ! espie     255:                fprintf(stderr, ": %.120s%s", j->cmd,
        !           256:                    strlen(j->cmd) > 120 ? "..." : "");
        !           257:        fprintf(stderr, ")\n");
1.126     espie     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:
1.130   ! espie     267:        if (!errorJobs)
        !           268:                fprintf(stderr, "Stop in %s.\n", Var_Value(".CURDIR"));
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)
1.130   ! espie     276:                                print_error(j);
1.126     espie     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: }