diff --git a/usr.bin/make/job.c b/usr.bin/make/job.c index 6a5640c95194..38314f955a71 100644 --- a/usr.bin/make/job.c +++ b/usr.bin/make/job.c @@ -1,4 +1,4 @@ -/* $NetBSD: job.c,v 1.115 2006/09/22 21:55:52 dsl Exp $ */ +/* $NetBSD: job.c,v 1.116 2006/09/23 20:51:28 dsl Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -70,14 +70,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: job.c,v 1.115 2006/09/22 21:55:52 dsl Exp $"; +static char rcsid[] = "$NetBSD: job.c,v 1.116 2006/09/23 20:51:28 dsl Exp $"; #else #include #ifndef lint #if 0 static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; #else -__RCSID("$NetBSD: job.c,v 1.115 2006/09/22 21:55:52 dsl Exp $"); +__RCSID("$NetBSD: job.c,v 1.116 2006/09/23 20:51:28 dsl Exp $"); #endif #endif /* not lint */ #endif @@ -301,12 +301,12 @@ int exit_pipe[2] = { -1, -1 }; /* child exit signal pipe. */ static sigset_t caught_signals; /* Set of signals we handle */ #if defined(USE_PGRP) && defined(SYSV) -# define KILL(pid, sig) kill(-(pid), (sig)) +# define KILLPG(pid, sig) kill(-(pid), (sig)) #else # if defined(USE_PGRP) -# define KILL(pid, sig) killpg((pid), (sig)) +# define KILLPG(pid, sig) killpg((pid), (sig)) # else -# define KILL(pid, sig) kill((pid), (sig)) +# define KILLPG(pid, sig) kill((pid), (sig)) # endif #endif @@ -323,20 +323,16 @@ static sigset_t caught_signals; /* Set of signals we handle */ #define W_EXITCODE(ret, sig) ((ret << 8) | (sig)) #endif -static void JobCondPassSig(int); -static void JobPassSig(int); static void JobChildSig(int); #ifdef USE_PGRP static void JobContinueSig(int); #endif -static Job *JobCmpPid(int, int); +static Job *JobFindPid(int, int); static int JobPrintCommand(ClientData, ClientData); static int JobSaveCommand(ClientData, ClientData); static void JobClose(Job *); -static void JobFinish(Job *, int *); static void JobExec(Job *, char **); static void JobMakeArgv(Job *, char **); -static int JobRestart(Job *); static int JobStart(GNode *, int); static char *JobOutput(Job *, char *, char *, int); static void JobDoOutput(Job *, Boolean); @@ -355,10 +351,10 @@ job_table_dump(const char *where) { Job *job; - fprintf(stderr, "job table @ %s\n", where); + fprintf(stdout, "job table @ %s\n", where); for (job = job_table; job < job_table_end; job++) { - fprintf(stderr, "job %d, status %d, flags %d, pid %d\n", - (int)(job - job_table), job->job_status, job->flags, job->pid); + fprintf(stdout, "job %d, status %d, flags %d, pid %d\n", + (int)(job - job_table), job->job_state, job->flags, job->pid); } } @@ -399,8 +395,13 @@ JobCondPassSig(int signo) { Job *job; + if (DEBUG(JOB)) { + (void)fprintf(stdout, "JobCondPassSig(%d) called.\n", signo); + (void)fflush(stdout); + } + for (job = job_table; job < job_table_end; job++) { - if (job->job_status != JOB_ST_RUNNING) + if (job->job_state != JOB_ST_RUNNING) continue; if (DEBUG(JOB)) { (void)fprintf(stdout, @@ -408,7 +409,7 @@ JobCondPassSig(int signo) signo, job->pid); (void)fflush(stdout); } - KILL(job->pid, signo); + KILLPG(job->pid, signo); } } @@ -456,6 +457,10 @@ JobChildSig(int signo __unused) static void JobContinueSig(int signo __unused) { + /* + * Defer sending to SIGCONT to out stopped children until we return + * from the signal handler. + */ write(exit_pipe[1], DO_JOB_RESUME, 1); } #endif @@ -478,38 +483,39 @@ JobContinueSig(int signo __unused) *----------------------------------------------------------------------- */ static void -JobPassSig(int signo) +JobPassSig_int(int signo) +{ + /* Run .INTERRUPT target then exit */ + JobInterrupt(TRUE, signo); +} + +static void +JobPassSig_term(int signo) +{ + /* Dont run .INTERRUPT target then exit */ + JobInterrupt(FALSE, signo); +} + +static void +JobPassSig_suspend(int signo) { sigset_t nmask, omask; struct sigaction act; + int sigcount; - if (DEBUG(JOB)) { - (void)fprintf(stdout, "JobPassSig(%d) called.\n", signo); - (void)fflush(stdout); - } + /* Pass the signal onto every job */ JobCondPassSig(signo); - /* - * Deal with proper cleanup based on the signal received. We only run - * the .INTERRUPT target if the signal was in fact an interrupt. The other - * three termination signals are more of a "get out *now*" command. - */ - if (signo == SIGINT) { - JobInterrupt(TRUE, signo); - } else if ((signo == SIGHUP) || (signo == SIGTERM) || (signo == SIGQUIT)) { - JobInterrupt(FALSE, signo); - } - - /* - * Leave gracefully if SIGQUIT, rather than core dumping. - */ - if (signo == SIGQUIT) { - Finish(0); - } - if (signo == SIGTSTP) { - Job_CatchChildren(FALSE); + /* Give children a short chance to run and suspend themselves */ + for (sigcount = maxJobs; sigcount != 0; sigcount--) { + if (poll(0, 0, 1) != -1 || errno != EINTR) + break; + } + /* Then report any that have... (gets messages sequenced properly) */ + Job_CatchChildren(CATCH_DEFER); } + /* * Send ourselves the signal now we've given the message to everyone else. * Note we block everything else possible while we're getting the signal. @@ -534,21 +540,32 @@ JobPassSig(int signo) (void)kill(getpid(), signo); /* - * If we didn't die, then likely as not all our children are suspended - * so loop through and wake them up. + * We've been continued. + * + * A whole host of signals continue to happen! + * Any SIGCHLD for the suspends that we didn't catch above. + * SIGCHLD for any processes that exited while we were alseep. + * The SIGCONT that actually caused us to wakeup. + * + * Since we defer passing the SIGCONT on to our children until + * the main processing loop, we can be sure that all the SIGCHLD + * events will have happened by then - and that the waitpid() will + * collect the child 'suspended' events. + * For correct sequencing we just need to ensure we process the + * waitpid() before passign on the SIGCONT. + * + * In any case nothing else is needed here. */ - if (signo != SIGTSTP) - JobCondPassSig(SIGCONT); /* Restore handler and signal mask */ - act.sa_handler = JobPassSig; + act.sa_handler = JobPassSig_suspend; (void)sigaction(signo, &act, NULL); (void)sigprocmask(SIG_SETMASK, &omask, NULL); } /*- *----------------------------------------------------------------------- - * JobCmpPid -- + * JobFindPid -- * Compare the pid of the job with the given pid and return 0 if they * are equal. This function is called from Job_CatchChildren via * Lst_Find to find the job descriptor of the finished job. @@ -565,14 +582,12 @@ JobPassSig(int signo) *----------------------------------------------------------------------- */ static Job * -JobCmpPid(int pid, int status) +JobFindPid(int pid, int status) { Job *job; for (job = job_table; job < job_table_end; job++) { - if (job->job_status != status) - continue; - if (job->pid == pid) + if ((job->job_state == status) && job->pid == pid) return job; } if (DEBUG(JOB)) @@ -911,13 +926,19 @@ JobClose(Job *job) */ /*ARGSUSED*/ static void -JobFinish(Job *job, int *status) +JobFinish(Job *job, int status) { Boolean done, return_job_token; - if ((WIFEXITED(*status) && - (((WEXITSTATUS(*status) != 0) && !(job->flags & JOB_IGNERR)))) || - WIFSIGNALED(*status)) + if (DEBUG(JOB)) { + fprintf(stdout, "Jobfinish: %d [%s], status %d\n", + job->pid, job->node->name, status); + fflush(stdout); + } + + if ((WIFEXITED(status) && + (((WEXITSTATUS(status) != 0) && !(job->flags & JOB_IGNERR)))) || + WIFSIGNALED(status)) { /* * If it exited non-zero and either we're doing things our @@ -933,14 +954,14 @@ JobFinish(Job *job, int *status) job->cmdFILE = NULL; } done = TRUE; - } else if (WIFEXITED(*status)) { + } else if (WIFEXITED(status)) { /* * Deal with ignored errors in -B mode. We need to print a message * telling of the ignored error as well as setting status.w_status * to 0 so the next command gets run. To do this, we set done to be * TRUE if in -B mode and the job exited non-zero. */ - done = WEXITSTATUS(*status) != 0; + done = WEXITSTATUS(status) != 0; /* * Old comment said: "Note we don't * want to close down any of the streams until we know we're at the @@ -956,28 +977,24 @@ JobFinish(Job *job, int *status) done = FALSE; } - if (done || WIFSTOPPED(*status) || - (WIFSIGNALED(*status) && (WTERMSIG(*status) == SIGCONT))) { - - if (WIFEXITED(*status)) { + if (done) { + if (WIFEXITED(status)) { if (DEBUG(JOB)) { (void)fprintf(stdout, "Process %d [%s] exited.\n", job->pid, job->node->name); (void)fflush(stdout); } - if (WEXITSTATUS(*status) != 0) { + if (WEXITSTATUS(status) != 0) { if (usePipes && job->node != lastNode) { MESSAGE(stdout, job->node); lastNode = job->node; } (void)printf("*** [%s] Error code %d%s\n", job->node->name, - WEXITSTATUS(*status), + WEXITSTATUS(status), (job->flags & JOB_IGNERR) ? "(ignored)" : ""); - - if (job->flags & JOB_IGNERR) { - *status = 0; - } + if (job->flags & JOB_IGNERR) + status = 0; } else if (DEBUG(JOB)) { if (usePipes && job->node != lastNode) { MESSAGE(stdout, job->node); @@ -986,71 +1003,14 @@ JobFinish(Job *job, int *status) (void)printf("*** [%s] Completed successfully\n", job->node->name); } - } else if (WIFSTOPPED(*status) && WSTOPSIG(*status) != SIGCONT) { - if (DEBUG(JOB)) { - (void)fprintf(stdout, "Process %d (%s) stopped.\n", - job->pid, job->node->name); - (void)fflush(stdout); - } - if (usePipes && job->node != lastNode) { - MESSAGE(stdout, job->node); - lastNode = job->node; - } - switch (WSTOPSIG(*status)) { - case SIGTSTP: - (void)printf("*** [%s] Suspended\n", - job->node->name); - break; - case SIGSTOP: - (void)printf("*** [%s] Stopped\n", - job->node->name); - break; - default: - (void)printf("*** [%s] Stopped -- signal %d\n", - job->node->name, WSTOPSIG(*status)); - } - job->flags |= JOB_RESUME; - job->job_status = JOB_ST_STOPPED; - (void)fflush(stdout); - return; - } else if (WIFSTOPPED(*status) && WSTOPSIG(*status) == SIGCONT) { - /* - * If the beastie has continued, shift the Job from the stopped - * list to the running one. - */ - if (job->flags & JOB_RESUME) { - if (usePipes && job->node != lastNode) { - MESSAGE(stdout, job->node); - lastNode = job->node; - } - (void)printf("*** [%s] Continued\n", job->node->name); - } - if (!(job->flags & JOB_CONTINUING)) { - if (DEBUG(JOB)) { - (void)fprintf(stdout, - "Warning: process %d [%s] was not continuing.\n", - job->pid, job->node->name); - (void)fflush(stdout); - } - } - job->flags &= ~JOB_CONTINUING; - job->job_status = JOB_ST_RUNNING; - if (DEBUG(JOB)) { - (void)fprintf(stdout, "Process %d is continuing.\n", - job->pid); - (void)fflush(stdout); - } - (void)fflush(stdout); - return; } else { if (usePipes && job->node != lastNode) { MESSAGE(stdout, job->node); lastNode = job->node; } (void)printf("*** [%s] Signal %d\n", - job->node->name, WTERMSIG(*status)); + job->node->name, WTERMSIG(status)); } - (void)fflush(stdout); } @@ -1058,13 +1018,13 @@ JobFinish(Job *job, int *status) Trace_Log(JOBEND, job); if (!(job->flags & JOB_SPECIAL)) { - if ((*status != 0) || + if ((status != 0) || (aborting == ABORT_ERROR) || (aborting == ABORT_INTERRUPT)) return_job_token = TRUE; } - if ((aborting != ABORT_ERROR) && (aborting != ABORT_INTERRUPT) && (*status == 0)) { + if ((aborting != ABORT_ERROR) && (aborting != ABORT_INTERRUPT) && (status == 0)) { /* * As long as we aren't aborting and the job didn't return a non-zero * status that we shouldn't ignore, we call Make_Update to update @@ -1080,10 +1040,10 @@ JobFinish(Job *job, int *status) if (!(job->flags & JOB_SPECIAL)) return_job_token = TRUE; Make_Update(job->node); - job->job_status = JOB_ST_FREE; - } else if (*status != 0) { + job->job_state = JOB_ST_FREE; + } else if (status != 0) { errors += 1; - job->job_status = JOB_ST_FREE; + job->job_state = JOB_ST_FREE; } /* @@ -1256,8 +1216,7 @@ Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...)) /*- *----------------------------------------------------------------------- * JobExec -- - * Execute the shell for the given job. Called from JobStart and - * JobRestart. + * Execute the shell for the given job. Called from JobStart * * Input: * job Job to execute @@ -1305,9 +1264,15 @@ JobExec(Job *job, char **argv) /* No interruptions until this job is on the `jobs' list */ JobSigLock(&mask); - if ((cpid = vfork()) == -1) { + /* Pre-emptively mark job running, pid still zero though */ + job->job_state = JOB_ST_RUNNING; + + cpid = vfork(); + if (cpid == -1) Punt("Cannot vfork: %s", strerror(errno)); - } else if (cpid == 0) { + + if (cpid == 0) { + /* Child */ /* * Reset all signal handlers; this is necessary because we also @@ -1387,25 +1352,26 @@ JobExec(Job *job, char **argv) (void)execv(shellPath, argv); execError("exec", shellPath); _exit(1); - } else { - job->pid = cpid; + } - Trace_Log(JOBSTART, job); + /* Parent, continuing after the child exec */ + job->pid = cpid; - if (usePipes) { - /* - * Set the current position in the buffer to the beginning - * and mark another stream to watch in the outputs mask - */ - job->curPos = 0; + Trace_Log(JOBSTART, job); - watchfd(job); - } + if (usePipes) { + /* + * Set the current position in the buffer to the beginning + * and mark another stream to watch in the outputs mask + */ + job->curPos = 0; - if (job->cmdFILE != NULL && job->cmdFILE != stdout) { - (void)fclose(job->cmdFILE); - job->cmdFILE = NULL; - } + watchfd(job); + } + + if (job->cmdFILE != NULL && job->cmdFILE != stdout) { + (void)fclose(job->cmdFILE); + job->cmdFILE = NULL; } /* @@ -1416,7 +1382,6 @@ JobExec(Job *job, char **argv) job->node->name, job->pid); job_table_dump("job started"); } - job->job_status = JOB_ST_RUNNING; JobSigUnlock(&mask); } @@ -1473,59 +1438,6 @@ JobMakeArgv(Job *job, char **argv) argv[argc] = NULL; } -/*- - *----------------------------------------------------------------------- - * JobRestart -- - * Restart a job that stopped for some reason. - * - * Input: - * job Job to restart - * - * Results: - * 1 if max number of running jobs has been reached, 0 otherwise. - * - *----------------------------------------------------------------------- - */ -static int -JobRestart(Job *job) -{ - Boolean error; - int status; - - /* - * The job has stopped and needs to be restarted. Why it stopped, - * we don't know... - */ - if (DEBUG(JOB)) { - (void)fprintf(stdout, "Resuming %s...", job->node->name); - (void)fflush(stdout); - } - - error = (KILL(job->pid, SIGCONT) != 0); - - if (!error) { - /* - * Make sure the user knows we've continued the beast and - * actually put the thing in the job table. - */ - job->flags |= JOB_CONTINUING; - status = W_STOPCODE(SIGCONT); - JobFinish(job, &status); - - job->flags &= ~(JOB_RESUME|JOB_CONTINUING); - if (DEBUG(JOB)) { - (void)fprintf(stdout, "done\n"); - (void)fflush(stdout); - } - } else { - Error("couldn't resume %s: %s", - job->node->name, strerror(errno)); - status = W_EXITCODE(1, 0); - JobFinish(job, &status); - } - return 0; -} - /*- *----------------------------------------------------------------------- * JobStart -- @@ -1561,13 +1473,13 @@ JobStart(GNode *gn, int flags) int tfd; /* File descriptor to the temp file */ for (job = job_table; job < job_table_end; job++) { - if (job->job_status == JOB_ST_FREE) + if (job->job_state == JOB_ST_FREE) break; } if (job >= job_table_end) Punt("JobStart out of memory"); memset(job, 0, sizeof *job); - job->job_status = JOB_ST_SETUP; + job->job_state = JOB_ST_SETUP; if (gn->type & OP_SPECIAL) flags |= JOB_SPECIAL; @@ -1717,10 +1629,10 @@ JobStart(GNode *gn, int flags) job->node->made = MADE; Make_Update(job->node); } - job->job_status = JOB_ST_FREE; + job->job_state = JOB_ST_FREE; return(JOB_FINISHED); } else { - job->job_status = JOB_ST_FREE; + job->job_state = JOB_ST_FREE; return(JOB_ERROR); } } else { @@ -2025,7 +1937,7 @@ JobRun(GNode *targ) JobStart(targ, JOB_SPECIAL); while (jobTokensRunning) { Job_CatchOutput(); - Job_CatchChildren(!usePipes); + Job_CatchChildren(usePipes ? 0 : CATCH_BLOCK); } #else Compat_Make(targ, targ); @@ -2058,8 +1970,9 @@ JobRun(GNode *targ) * *----------------------------------------------------------------------- */ + void -Job_CatchChildren(Boolean block) +Job_CatchChildren(unsigned int flags) { int pid; /* pid of dead child */ Job *job; /* job descriptor for dead child */ @@ -2068,37 +1981,52 @@ Job_CatchChildren(Boolean block) /* * Don't even bother if we know there's no one around. */ - if (jobTokensRunning == 0) { + if (jobTokensRunning == 0) return; - } while ((pid = waitpid((pid_t) -1, &status, - (block?0:WNOHANG)|WUNTRACED)) > 0) - { + flags & CATCH_BLOCK ? WUNTRACED : WNOHANG | WUNTRACED)) > 0) { if (DEBUG(JOB)) { - (void)fprintf(stdout, "Process %d exited or stopped %x.\n", pid, + (void)fprintf(stdout, "Process %d exited/stopped status %x.\n", pid, status); (void)fflush(stdout); } - job = JobCmpPid(pid, JOB_ST_RUNNING); + job = JobFindPid(pid, JOB_ST_RUNNING); if (job == NULL) { - if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGCONT)) { - job = JobCmpPid(pid, JOB_ST_STOPPED); - if (job == NULL) { - Error("Resumed child (%d) not in table", pid); - continue; - } - job->job_status = JOB_ST_FINISHED; - } else { - Error("Child (%d) status %x not in table?", pid, status); - continue; + Error("Child (%d) status %x not in table?", pid, status); + continue; + } + if (WIFSTOPPED(status)) { + if (DEBUG(JOB)) { + (void)fprintf(stdout, "Process %d (%s) stopped.\n", + job->pid, job->node->name); + (void)fflush(stdout); } - } else { - job->job_status = JOB_ST_FINISHED; + switch (WSTOPSIG(status)) { + case SIGTSTP: + (void)printf("*** [%s] Suspended\n", job->node->name); + break; + case SIGSTOP: + (void)printf("*** [%s] Stopped\n", job->node->name); + break; + default: + (void)printf("*** [%s] Stopped -- signal %d\n", + job->node->name, WSTOPSIG(status)); + } + job->job_suspended = 1; + (void)fflush(stdout); + continue; } - JobFinish(job, &status); + job->job_state = JOB_ST_FINISHED; + job->exit_status = status; + + if (flags & CATCH_DEFER) + /* We don't want to process the termination now... */ + write(exit_pipe[1], DO_JOB_RESUME, 1); + else + JobFinish(job, status); } } @@ -2133,17 +2061,18 @@ Job_CatchOutput(void) sigset_t mask; if (readyfd(&childExitJob)) { - char token; - (void)read(childExitJob.inPipe, &token, 1); + char token = 0; nready -= 1; + (void)read(childExitJob.inPipe, &token, 1); if (token == DO_JOB_RESUME[0]) + /* Complete relay requested from our SIGCONT handler */ JobRestartJobs(); } JobSigLock(&mask); for (job = job_table; nready && job < job_table_end; job++) { - if (job->job_status != JOB_ST_RUNNING) + if (job->job_state != JOB_ST_RUNNING) continue; if (readyfd(job)) { JobDoOutput(job, FALSE); @@ -2274,10 +2203,10 @@ Job_Init(void) * Catch the four signals that POSIX specifies if they aren't ignored. * JobPassSig will take care of calling JobInterrupt if appropriate. */ - ADDSIG(SIGINT, JobPassSig) - ADDSIG(SIGHUP, JobPassSig) - ADDSIG(SIGTERM, JobPassSig) - ADDSIG(SIGQUIT, JobPassSig) + ADDSIG(SIGINT, JobPassSig_int) + ADDSIG(SIGHUP, JobPassSig_term) + ADDSIG(SIGTERM, JobPassSig_term) + ADDSIG(SIGQUIT, JobPassSig_term) /* * There are additional signals that need to be caught and passed if @@ -2286,10 +2215,10 @@ Job_Init(void) * signals from the terminal driver as we own the terminal) */ #if defined(USE_PGRP) - ADDSIG(SIGTSTP, JobPassSig) - ADDSIG(SIGTTOU, JobPassSig) - ADDSIG(SIGTTIN, JobPassSig) - ADDSIG(SIGWINCH, JobPassSig) + ADDSIG(SIGTSTP, JobPassSig_suspend) + ADDSIG(SIGTTOU, JobPassSig_suspend) + ADDSIG(SIGTTIN, JobPassSig_suspend) + ADDSIG(SIGWINCH, JobCondPassSig) ADDSIG(SIGCONT, JobContinueSig) #endif #undef ADDSIG @@ -2574,7 +2503,7 @@ JobInterrupt(int runINTERRUPT, int signo) JobSigLock(&mask); for (job = job_table; job < job_table_end; job++) { - if (job->job_status != JOB_ST_RUNNING) + if (job->job_state != JOB_ST_RUNNING) continue; gn = job->node; @@ -2592,7 +2521,7 @@ JobInterrupt(int runINTERRUPT, int signo) signo, job->pid); (void)fflush(stdout); } - KILL(job->pid, signo); + KILLPG(job->pid, signo); } } @@ -2676,7 +2605,7 @@ Job_Wait(void) aborting = ABORT_WAIT; while (jobTokensRunning != 0) { Job_CatchOutput(); - Job_CatchChildren(!usePipes); + Job_CatchChildren(usePipes ? 0 : CATCH_BLOCK); } aborting = 0; } @@ -2708,14 +2637,14 @@ Job_AbortAll(void) JobSigLock(&mask); for (job = job_table; job < job_table_end; job++) { - if (job->job_status != JOB_ST_RUNNING) + if (job->job_state != JOB_ST_RUNNING) continue; /* * kill the child process with increasingly drastic signals to make * darn sure it's dead. */ - KILL(job->pid, SIGINT); - KILL(job->pid, SIGKILL); + KILLPG(job->pid, SIGINT); + KILLPG(job->pid, SIGKILL); } JobSigUnlock(&mask); } @@ -2739,7 +2668,7 @@ Job_AbortAll(void) * None. * * Side Effects: - * Resumes(and possibly migrates) jobs. + * Resumes jobs. * *----------------------------------------------------------------------- */ @@ -2751,14 +2680,23 @@ JobRestartJobs(void) JobSigLock(&mask); for (job = job_table; job < job_table_end; job++) { - if (job->job_status != JOB_ST_STOPPED) - continue; - if (DEBUG(JOB)) { - (void)fprintf(stdout, "Restarting a stopped job.\n"); + if (job->job_state == JOB_ST_RUNNING && job->job_suspended) { + job->job_suspended = 0; + if (DEBUG(JOB)) { + (void)fprintf(stdout, "Restarting stopped job pid %d.\n", + job->pid); + (void)fflush(stdout); + } + (void)printf("*** [%s] Continued\n", job->node->name); (void)fflush(stdout); + if (KILLPG(job->pid, SIGCONT) != 0 && DEBUG(JOB)) { + fprintf(stdout, "Failed to send SIGCONT to %d\n", job->pid); + (void)fflush(stdout); + } } - if (JobRestart(job) != 0) - break; + if (job->job_state == JOB_ST_FINISHED) + /* Job exit deferred after calling waitpid() in a signal handler */ + JobFinish(job, job->exit_status); } JobSigUnlock(&mask); } diff --git a/usr.bin/make/job.h b/usr.bin/make/job.h index 2a09cfe54dae..c368df1f2b78 100644 --- a/usr.bin/make/job.h +++ b/usr.bin/make/job.h @@ -1,4 +1,4 @@ -/* $NetBSD: job.h,v 1.29 2006/09/22 19:07:09 dsl Exp $ */ +/* $NetBSD: job.h,v 1.30 2006/09/23 20:51:28 dsl Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -151,12 +151,13 @@ typedef struct Job { * saved when the job has been run */ FILE *cmdFILE; /* When creating the shell script, this is * where the commands go */ - short job_status; /* status of the job entry */ + int exit_status; /* from wait4() in signal handler */ + char job_state; /* status of the job entry */ #define JOB_ST_FREE 0 /* Job is available */ #define JOB_ST_SETUP 1 /* Job is allocated but otherwise invalid */ -#define JOB_ST_RUNNING 2 /* Job is running, pid valid */ -#define JOB_ST_STOPPED 3 /* Job is stopped (ie after ^Z) */ +#define JOB_ST_RUNNING 3 /* Job is running, pid valid */ #define JOB_ST_FINISHED 4 /* Job is done (ie after SIGCHILD) */ + char job_suspended; short flags; /* Flags to control treatment of job */ #define JOB_IGNERR 0x001 /* Ignore non-zero exits */ #define JOB_SILENT 0x002 /* no output */ @@ -164,11 +165,6 @@ typedef struct Job { * if we can't export it and maxLocal is 0 */ #define JOB_IGNDOTS 0x008 /* Ignore "..." lines when processing * commands */ -#define JOB_RESUME 0x100 /* Job needs to be resumed b/c it stopped, - * for some reason */ -#define JOB_CONTINUING 0x200 /* We are in the process of resuming this job. - * Used to avoid infinite recursion between - * JobFinish and JobRestart */ #define JOB_TRACED 0x400 /* we've sent 'set -x' */ union { @@ -280,7 +276,9 @@ void Shell_Init(void); const char *Shell_GetNewline(void); void Job_Touch(GNode *, Boolean); Boolean Job_CheckCommands(GNode *, void (*abortProc )(const char *, ...)); -void Job_CatchChildren(Boolean); +#define CATCH_BLOCK 1 +#define CATCH_DEFER 2 +void Job_CatchChildren(unsigned int); void Job_CatchOutput(void); void Job_Make(GNode *); void Job_Init(void); diff --git a/usr.bin/make/make.c b/usr.bin/make/make.c index 98c5ed5edd37..54efb9aa7fab 100644 --- a/usr.bin/make/make.c +++ b/usr.bin/make/make.c @@ -1,4 +1,4 @@ -/* $NetBSD: make.c,v 1.62 2006/03/31 21:05:34 dsl Exp $ */ +/* $NetBSD: make.c,v 1.63 2006/09/23 20:51:28 dsl Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -69,14 +69,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: make.c,v 1.62 2006/03/31 21:05:34 dsl Exp $"; +static char rcsid[] = "$NetBSD: make.c,v 1.63 2006/09/23 20:51:28 dsl Exp $"; #else #include #ifndef lint #if 0 static char sccsid[] = "@(#)make.c 8.1 (Berkeley) 6/6/93"; #else -__RCSID("$NetBSD: make.c,v 1.62 2006/03/31 21:05:34 dsl Exp $"); +__RCSID("$NetBSD: make.c,v 1.63 2006/09/23 20:51:28 dsl Exp $"); #endif #endif /* not lint */ #endif @@ -1230,7 +1230,7 @@ Make_Run(Lst targs) */ while (!Lst_IsEmpty(toBeMade) || jobTokensRunning > 0) { Job_CatchOutput(); - Job_CatchChildren(!usePipes); + Job_CatchChildren(usePipes ? 0 : CATCH_BLOCK); (void)MakeStartJobs(); }