Complete revamp of the way make handles job control signals.

- Send each type of signal to its own handler.
- Only call JobFinish when a process exits, in particular don't 'fake up'
  'exitstatus' for jobs being continued, nor call it for suspends.
- When a job is stopped, use an entire variable to remember the fact, so
  we know we need to send a SIGCONT.  Don't change any other state.
- In order to report '*** [job3] Suspended' before we suspend ourselves we
  have to call waitpid() from the signal handler - where we don't want to
  process job termination events. Save the exit status and process later.
The code now handles:
- jobs that suspend themselves
- jobs exiting while suspended
- jobs that don't actually suspend at all
Hoewever it still does printfs() from the signal handler, and I haven't yet
stopped it thrashing the signal mask.
This commit is contained in:
dsl 2006-09-23 20:51:28 +00:00
parent 4887a60437
commit 56564e27f6
3 changed files with 201 additions and 265 deletions

View File

@ -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 <sys/cdefs.h>
#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);
}

View File

@ -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);

View File

@ -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 <sys/cdefs.h>
#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();
}