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

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