[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.126

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