diff options
| author | pk <pk@NetBSD.org> | 2002-03-18 13:28:25 +0000 |
|---|---|---|
| committer | pk <pk@NetBSD.org> | 2002-03-18 13:28:25 +0000 |
| commit | b9f8785382efd8bcfef074d604ef6a1319ea3bba (patch) | |
| tree | a83494011841fdabba00620c9cb79cb2002e1357 /usr.bin/make | |
| parent | df95562a0f9780dd87cf86b41941564497f9c541 (diff) | |
Block signals during Lst_Open/Lst_Close list traverals and in JobExec
while setting up a child process. This prevents the major sources of
list inconsistencies that may result from doing list manipulations
from a signal handler.
XXX - all Lst_*() operations are at risk; look for ways to avoid touching
so much global state from the signal handlers.
Diffstat (limited to 'usr.bin/make')
| -rw-r--r-- | usr.bin/make/job.c | 180 |
1 files changed, 123 insertions, 57 deletions
diff --git a/usr.bin/make/job.c b/usr.bin/make/job.c index 0467109e35e..ce8a55b5438 100644 --- a/usr.bin/make/job.c +++ b/usr.bin/make/job.c @@ -1,4 +1,4 @@ -/* $NetBSD: job.c,v 1.68 2002/03/18 12:28:07 pk Exp $ */ +/* $NetBSD: job.c,v 1.69 2002/03/18 13:28:25 pk Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -39,14 +39,14 @@ */ #ifdef MAKE_BOOTSTRAP -static char rcsid[] = "$NetBSD: job.c,v 1.68 2002/03/18 12:28:07 pk Exp $"; +static char rcsid[] = "$NetBSD: job.c,v 1.69 2002/03/18 13:28:25 pk 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.68 2002/03/18 12:28:07 pk Exp $"); +__RCSID("$NetBSD: job.c,v 1.69 2002/03/18 13:28:25 pk Exp $"); #endif #endif /* not lint */ #endif @@ -282,6 +282,7 @@ STATIC Lst stoppedJobs; /* Lst of Job structures describing * limits or migration home */ +sigset_t caught_signals; /* Set of signals we handle */ #if defined(USE_PGRP) && defined(SYSV) # define KILL(pid, sig) kill(-(pid), (sig)) #else @@ -333,6 +334,32 @@ static Shell *JobMatchShell __P((char *)); static void JobInterrupt __P((int, int)); static void JobRestartJobs __P((void)); static void JobTokenAdd __P((void)); +static void JobSigLock(sigset_t *); +static void JobSigUnlock(sigset_t *); +static void JobSigReset(void); + + + +/* + * JobSigLock/JobSigUnlock + * + * Signal lock routines to get exclusive access. Currently used to + * protect `jobs' and `stoppedJobs' list manipulations. + */ +static void JobSigLock(omaskp) + sigset_t *omaskp; +{ + if (sigprocmask(SIG_BLOCK, &caught_signals, omaskp) != 0) { + Punt("JobSigLock: sigprocmask: %s", strerror(errno)); + sigemptyset(omaskp); + } +} + +static void JobSigUnlock(omaskp) + sigset_t *omaskp; +{ + (void) sigprocmask(SIG_SETMASK, omaskp, NULL); +} /*- *----------------------------------------------------------------------- @@ -1283,6 +1310,7 @@ JobExec(job, argv) char **argv; { int cpid; /* ID of new child */ + sigset_t mask; job->flags &= ~JOB_TRACED; @@ -1317,11 +1345,23 @@ JobExec(job, argv) } #endif /* RMT_NO_EXEC */ + /* No interruptions until this job is on the `jobs' list */ + JobSigLock(&mask); + if ((cpid = vfork()) == -1) { Punt("Cannot vfork: %s", strerror(errno)); } else if (cpid == 0) { /* + * Reset all signal handlers; this is necessary because we also + * need to unblock signals before we exec(2). + */ + JobSigReset(); + + /* Now unblock signals */ + JobSigUnlock(&mask); + + /* * Must duplicate the input stream down to the child's input and * reset it to the beginning (again). Since the stream was marked * close-on-exec, we must clear that bit in the new input. @@ -1397,12 +1437,6 @@ JobExec(job, argv) } _exit(1); } else { -#ifdef REMOTE - sigset_t nmask, omask; - sigemptyset(&nmask); - sigaddset(&nmask, SIGCHLD); - sigprocmask(SIG_BLOCK, &nmask, &omask); -#endif job->pid = cpid; Trace_Log(JOBSTART, job); @@ -1442,9 +1476,6 @@ JobExec(job, argv) job->cmdFILE = NULL; } } -#ifdef REMOTE - sigprocmask(SIG_SETMASK, &omask, NULL); -#endif } #ifdef RMT_NO_EXEC @@ -1453,8 +1484,13 @@ jobExecFinish: /* * Now the job is actually running, add it to the table. */ + if (DEBUG(JOB)) { + printf("JobExec(%s): pid %d added to jobs table\n", + job->node->name, job->pid); + } nJobs += 1; (void) Lst_AtEnd(jobs, (ClientData)job); + JobSigUnlock(&mask); } /*- @@ -1826,6 +1862,7 @@ JobStart(gn, flags, previous) * the make process in a 6-character field with leading zeroes. */ char tfile[sizeof(TMPPAT)]; + sigset_t mask; /* * We're serious here, but if the commands were bogus, we're * also dead... @@ -1834,10 +1871,12 @@ JobStart(gn, flags, previous) DieHorribly(); } + JobSigLock(&mask); (void)strcpy(tfile, TMPPAT); if ((tfd = mkstemp(tfile)) == -1) Punt("Could not create temporary file %s", strerror(errno)); (void) eunlink(tfile); + JobSigUnlock(&mask); job->cmdFILE = fdopen(tfd, "w+"); if (job->cmdFILE == NULL) { @@ -2351,9 +2390,7 @@ Job_CatchChildren(block) (void) fflush(stdout); } - jnode = Lst_Find(jobs, (ClientData)&pid, JobCmpPid); - if (jnode == NILLNODE) { if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGCONT)) { jnode = Lst_Find(stoppedJobs, (ClientData) &pid, JobCmpPid); @@ -2375,7 +2412,7 @@ Job_CatchChildren(block) if (!(job->flags & JOB_REMOTE)) { if (DEBUG(JOB)) { (void) fprintf(stdout, - "Job queue has one fewer local process.\n"); + "Job queue has one fewer local process.\n"); (void) fflush(stdout); } nLocal -= 1; @@ -2442,8 +2479,8 @@ Job_CatchOutput() #else if (usePipes) { #ifdef USE_SELECT - struct timeval timeout; - fd_set readfds; + struct timeval timeout; + fd_set readfds; readfds = outputs; timeout.tv_sec = SEL_SEC; @@ -2458,6 +2495,8 @@ Job_CatchOutput() return; #endif else { + sigset_t mask; + JobSigLock(&mask); if (Lst_Open(jobs) == FAILURE) { Punt("Cannot open job table"); } @@ -2475,6 +2514,7 @@ Job_CatchOutput() } Lst_Close(jobs); + JobSigUnlock(&mask); } } #endif /* RMT_WILL_WATCH */ @@ -2568,27 +2608,28 @@ Job_Init(maxproc, maxlocal) commandShell->echo = ""; } + sigemptyset(&caught_signals); /* - * Catch the four signals that POSIX specifies if they aren't ignored. - * JobPassSig will take care of calling JobInterrupt if appropriate. + * Install a NOOP SIGCHLD handler so we are woken up if we're blocked. */ - if (signal(SIGINT, SIG_IGN) != SIG_IGN) { - (void) signal(SIGINT, JobPassSig); - } - if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { - (void) signal(SIGHUP, JobPassSig); - } - if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { - (void) signal(SIGQUIT, JobPassSig); - } - if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { - (void) signal(SIGTERM, JobPassSig); + (void)signal(SIGCHLD, JobIgnoreSig); + sigaddset(&caught_signals, SIGCHLD); + +#define ADDSIG(s,h) \ + if (signal(s, SIG_IGN) != SIG_IGN) { \ + sigaddset(&caught_signals, s); \ + (void) signal(s, h); \ } + /* - * Install a NOOP SIGCHLD handler so we are woken up if we're blocked. + * Catch the four signals that POSIX specifies if they aren't ignored. + * JobPassSig will take care of calling JobInterrupt if appropriate. */ - signal(SIGCHLD, JobIgnoreSig); - + ADDSIG(SIGINT, JobPassSig) + ADDSIG(SIGHUP, JobPassSig) + ADDSIG(SIGTERM, JobPassSig) + ADDSIG(SIGQUIT, JobPassSig) + /* * There are additional signals that need to be caught and passed if * either the export system wants to be told directly of signals or if @@ -2596,22 +2637,13 @@ Job_Init(maxproc, maxlocal) * signals from the terminal driver as we own the terminal) */ #if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP) - if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) { - (void) signal(SIGTSTP, JobPassSig); - } - if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) { - (void) signal(SIGTTOU, JobPassSig); - } - if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) { - (void) signal(SIGTTIN, JobPassSig); - } - if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) { - (void) signal(SIGWINCH, JobPassSig); - } - if (signal(SIGCONT, SIG_IGN) != SIG_IGN) { - (void) signal(SIGCONT, JobContinueSig); - } + ADDSIG(SIGTSTP, JobPassSig) + ADDSIG(SIGTTOU, JobPassSig) + ADDSIG(SIGTTIN, JobPassSig) + ADDSIG(SIGWINCH, JobPassSig) + ADDSIG(SIGCONT, JobContinueSig) #endif +#undef ADDSIG begin = Targ_FindNode(".BEGIN", TARG_NOCREATE); @@ -2627,6 +2659,28 @@ Job_Init(maxproc, maxlocal) postCommands = Targ_FindNode(".END", TARG_CREATE); } +static void JobSigReset() +{ +#define DELSIG(s) \ + if (sigismember(&caught_signals, s)) { \ + (void) signal(SIGINT, SIG_DFL); \ + } + + DELSIG(SIGINT) + DELSIG(SIGHUP) + DELSIG(SIGQUIT) + DELSIG(SIGTERM) +#if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP) + DELSIG(SIGTSTP) + DELSIG(SIGTTOU) + DELSIG(SIGTTIN) + DELSIG(SIGWINCH) + DELSIG(SIGCONT) +#endif +#undef DELSIG + (void)signal(SIGCHLD, SIG_DFL); +} + /*- *----------------------------------------------------------------------- * Job_Empty -- @@ -2883,17 +2937,20 @@ Job_ParseShell(line) */ static void JobInterrupt(runINTERRUPT, signo) - int runINTERRUPT; /* Non-zero if commands for the .INTERRUPT - * target should be executed */ - int signo; /* signal received */ + int runINTERRUPT; /* Non-zero if commands for the .INTERRUPT + * target should be executed */ + int signo; /* signal received */ { - LstNode ln; /* element in job table */ - Job *job; /* job descriptor in that element */ - GNode *interrupt; /* the node describing the .INTERRUPT target */ + LstNode ln; /* element in job table */ + Job *job; /* job descriptor in that element */ + GNode *interrupt; /* the node describing the .INTERRUPT target */ + sigset_t mask; aborting = ABORT_INTERRUPT; - (void) Lst_Open(jobs); + JobSigLock(&mask); + + (void) Lst_Open(jobs); while ((ln = Lst_Next(jobs)) != NILLNODE) { GNode *gn; @@ -2929,8 +2986,8 @@ JobInterrupt(runINTERRUPT, signo) if (job->pid) { if (DEBUG(JOB)) { (void) fprintf(stdout, - "JobInterrupt passing signal to child %d.\n", - job->pid); + "JobInterrupt passing signal %d to child %d.\n", + signo, job->pid); (void) fflush(stdout); } KILL(job->pid, signo); @@ -3001,6 +3058,8 @@ JobInterrupt(runINTERRUPT, signo) Lst_Close(stoppedJobs); #endif /* REMOTE */ + JobSigUnlock(&mask); + if (runINTERRUPT && !touchFlag) { interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); if (interrupt != NILGNODE) { @@ -3122,11 +3181,13 @@ Job_AbortAll() LstNode ln; /* element in job table */ Job *job; /* the job descriptor in that element */ int foo; + sigset_t mask; aborting = ABORT_ERROR; if (nJobs) { + JobSigLock(&mask); (void) Lst_Open(jobs); while ((ln = Lst_Next(jobs)) != NILLNODE) { job = (Job *) Lst_Datum(ln); @@ -3149,6 +3210,7 @@ Job_AbortAll() #endif /* RMT_WANTS_SIGNALS */ } Lst_Close(jobs); + JobSigUnlock(&mask); } /* @@ -3229,6 +3291,9 @@ JobFlagForMigration(hostID) static void JobRestartJobs() { + sigset_t mask; + + JobSigLock(&mask); while (!Lst_IsEmpty(stoppedJobs)) { if (DEBUG(JOB)) { (void) fprintf(stdout, "Restarting a stopped job.\n"); @@ -3237,6 +3302,7 @@ JobRestartJobs() if (JobRestart((Job *)Lst_DeQueue(stoppedJobs)) != 0) break; } + JobSigUnlock(&mask); } #ifndef RMT_WILL_WATCH |
