mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-30 16:51:41 +00:00
Fix a (very) long standing bug in make (this has been there probably
from the beginning). Make used to handle all its interrupt-time stuff directly from the signal handler, including calls to printf, accessing global data and so on. This is of course wrong and could provoke a core dump when interrupting make. Just set a flag in the signal handler and do everything else from the main thread. PR: bin/29103
This commit is contained in:
parent
8280421a43
commit
4253bd82b6
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=137605
@ -79,6 +79,8 @@ static char meta[256];
|
||||
|
||||
static GNode *curTarg = NULL;
|
||||
static GNode *ENDNode;
|
||||
static sig_atomic_t interrupted;
|
||||
|
||||
static void CompatInterrupt(int);
|
||||
static int CompatMake(void *, void *);
|
||||
static int shellneed(char *);
|
||||
@ -101,6 +103,16 @@ CompatInit(void)
|
||||
meta[0] = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupt handler - set flag and defer handling to the main code
|
||||
*/
|
||||
static void
|
||||
CompatCatchSig(int signo)
|
||||
{
|
||||
|
||||
interrupted = signo;
|
||||
}
|
||||
|
||||
/*-
|
||||
*-----------------------------------------------------------------------
|
||||
* CompatInterrupt --
|
||||
@ -120,6 +132,17 @@ static void
|
||||
CompatInterrupt (int signo)
|
||||
{
|
||||
GNode *gn;
|
||||
sigset_t nmask, omask;
|
||||
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGINT);
|
||||
sigaddset(&nmask, SIGTERM);
|
||||
sigaddset(&nmask, SIGHUP);
|
||||
sigaddset(&nmask, SIGQUIT);
|
||||
sigprocmask(SIG_SETMASK, &nmask, &omask);
|
||||
|
||||
/* prevent recursion in evaluation of .INTERRUPT */
|
||||
interrupted = 0;
|
||||
|
||||
if ((curTarg != NULL) && !Targ_Precious (curTarg)) {
|
||||
char *p1;
|
||||
@ -129,18 +152,20 @@ CompatInterrupt (int signo)
|
||||
printf ("*** %s removed\n", file);
|
||||
}
|
||||
free(p1);
|
||||
|
||||
/*
|
||||
* Run .INTERRUPT only if hit with interrupt signal
|
||||
*/
|
||||
if (signo == SIGINT) {
|
||||
gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);
|
||||
if (gn != NULL) {
|
||||
Lst_ForEach(gn->commands, Compat_RunCommand, (void *)gn);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Run .INTERRUPT only if hit with interrupt signal
|
||||
*/
|
||||
if (signo == SIGINT) {
|
||||
gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);
|
||||
if (gn != NULL) {
|
||||
Lst_ForEach(gn->commands, Compat_RunCommand, (void *)gn);
|
||||
}
|
||||
}
|
||||
|
||||
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||
|
||||
if (signo == SIGQUIT)
|
||||
exit(signo);
|
||||
(void) signal(signo, SIG_DFL);
|
||||
@ -373,10 +398,12 @@ Compat_RunCommand (void *cmdp, void *gnp)
|
||||
while (1) {
|
||||
|
||||
while ((rstat = wait(&reason)) != cpid) {
|
||||
if (rstat == -1 && errno != EINTR) {
|
||||
break;
|
||||
if (interrupted || (rstat == -1 && errno != EINTR)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (interrupted)
|
||||
CompatInterrupt(interrupted);
|
||||
|
||||
if (rstat > -1) {
|
||||
if (WIFSTOPPED(reason)) {
|
||||
@ -660,16 +687,16 @@ Compat_Run(Lst targs)
|
||||
Shell_Init(); /* Set up shell. */
|
||||
|
||||
if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
|
||||
signal(SIGINT, CompatInterrupt);
|
||||
signal(SIGINT, CompatCatchSig);
|
||||
}
|
||||
if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
|
||||
signal(SIGTERM, CompatInterrupt);
|
||||
signal(SIGTERM, CompatCatchSig);
|
||||
}
|
||||
if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
|
||||
signal(SIGHUP, CompatInterrupt);
|
||||
signal(SIGHUP, CompatCatchSig);
|
||||
}
|
||||
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) {
|
||||
signal(SIGQUIT, CompatInterrupt);
|
||||
signal(SIGQUIT, CompatCatchSig);
|
||||
}
|
||||
|
||||
ENDNode = Targ_FindNode(".END", TARG_CREATE);
|
||||
|
@ -259,6 +259,9 @@ STATIC Lst stoppedJobs; /* Lst of Job structures describing
|
||||
* limits or externally */
|
||||
|
||||
|
||||
static sig_atomic_t interrupted;
|
||||
|
||||
|
||||
#if defined(USE_PGRP) && defined(SYSV)
|
||||
# define KILL(pid, sig) killpg(-(pid), (sig))
|
||||
#else
|
||||
@ -306,6 +309,19 @@ static Shell *JobMatchShell(char *);
|
||||
static void JobInterrupt(int, int);
|
||||
static void JobRestartJobs(void);
|
||||
|
||||
/*
|
||||
* JobCatchSignal
|
||||
*
|
||||
* Got a signal. Set global variables and hope that someone will
|
||||
* handle it.
|
||||
*/
|
||||
static void
|
||||
JobCatchSig(int signo)
|
||||
{
|
||||
|
||||
interrupted = signo;
|
||||
}
|
||||
|
||||
/*-
|
||||
*-----------------------------------------------------------------------
|
||||
* JobCondPassSig --
|
||||
@ -351,6 +367,10 @@ JobPassSig(int signo)
|
||||
sigset_t nmask, omask;
|
||||
struct sigaction act;
|
||||
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, signo);
|
||||
sigprocmask(SIG_SETMASK, &nmask, &omask);
|
||||
|
||||
DEBUGF(JOB, ("JobPassSig(%d) called.\n", signo));
|
||||
Lst_ForEach(jobs, JobCondPassSig, (void *) &signo);
|
||||
|
||||
@ -377,10 +397,8 @@ JobPassSig(int signo)
|
||||
* Note we block everything else possible while we're getting the signal.
|
||||
* This ensures that all our jobs get continued when we wake up before
|
||||
* we take any other signal.
|
||||
* XXX this comment seems wrong.
|
||||
*/
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, signo);
|
||||
sigprocmask(SIG_SETMASK, &nmask, &omask);
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
@ -1366,6 +1384,10 @@ JobStart(GNode *gn, int flags, Job *previous)
|
||||
Boolean noExec; /* Set true if we decide not to run the job */
|
||||
int tfd; /* File descriptor for temp file */
|
||||
|
||||
if (interrupted) {
|
||||
JobPassSig(interrupted);
|
||||
return (JOB_ERROR);
|
||||
}
|
||||
if (previous != NULL) {
|
||||
previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT);
|
||||
job = previous;
|
||||
@ -1709,6 +1731,14 @@ JobDoOutput(Job *job, Boolean finish)
|
||||
|
||||
nRead = read(job->inPipe, &job->outBuf[job->curPos],
|
||||
JOB_BUFSIZE - job->curPos);
|
||||
/*
|
||||
* Check for interrupt here too, because the above read may block
|
||||
* when the child process is stopped. In this case the interrupt
|
||||
* will unblock it (we don't use SA_RESTART).
|
||||
*/
|
||||
if (interrupted)
|
||||
JobPassSig(interrupted);
|
||||
|
||||
if (nRead < 0) {
|
||||
DEBUGF(JOB, ("JobDoOutput(piperead)"));
|
||||
nr = 0;
|
||||
@ -1921,6 +1951,8 @@ Job_CatchChildren(Boolean block)
|
||||
|
||||
JobFinish(job, &status);
|
||||
}
|
||||
if (interrupted)
|
||||
JobPassSig(interrupted);
|
||||
}
|
||||
|
||||
/*-
|
||||
@ -1961,6 +1993,8 @@ Job_CatchOutput(void)
|
||||
if ((nfds = kevent(kqfd, NULL, 0, kev, KEV_SIZE, NULL)) == -1) {
|
||||
if (errno != EINTR)
|
||||
Punt("kevent: %s", strerror(errno));
|
||||
if (interrupted)
|
||||
JobPassSig(interrupted);
|
||||
} else {
|
||||
for (i = 0; i < nfds; i++) {
|
||||
if (kev[i].flags & EV_ERROR) {
|
||||
@ -1984,9 +2018,11 @@ Job_CatchOutput(void)
|
||||
timeout.tv_usec = SEL_USEC;
|
||||
|
||||
if ((nfds = select(FD_SETSIZE, &readfds, (fd_set *) 0,
|
||||
(fd_set *) 0, &timeout)) <= 0)
|
||||
(fd_set *) 0, &timeout)) <= 0) {
|
||||
if (interrupted)
|
||||
JobPassSig(interrupted);
|
||||
return;
|
||||
else {
|
||||
} else {
|
||||
if (Lst_Open(jobs) == FAILURE) {
|
||||
Punt("Cannot open job table");
|
||||
}
|
||||
@ -2055,6 +2091,7 @@ void
|
||||
Job_Init(int maxproc)
|
||||
{
|
||||
GNode *begin; /* node for commands to do at the very start */
|
||||
struct sigaction sa;
|
||||
|
||||
jobs = Lst_Init(FALSE);
|
||||
stoppedJobs = Lst_Init(FALSE);
|
||||
@ -2087,19 +2124,24 @@ Job_Init(int maxproc)
|
||||
|
||||
/*
|
||||
* Catch the four signals that POSIX specifies if they aren't ignored.
|
||||
* JobPassSig will take care of calling JobInterrupt if appropriate.
|
||||
* JobCatchSignal will just set global variables and hope someone
|
||||
* else is going to handle the interrupt.
|
||||
*/
|
||||
sa.sa_handler = JobCatchSig;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
|
||||
if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
|
||||
(void) signal(SIGINT, JobPassSig);
|
||||
(void) sigaction(SIGINT, &sa, NULL);
|
||||
}
|
||||
if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
|
||||
(void) signal(SIGHUP, JobPassSig);
|
||||
(void) sigaction(SIGHUP, &sa, NULL);
|
||||
}
|
||||
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) {
|
||||
(void) signal(SIGQUIT, JobPassSig);
|
||||
(void) sigaction(SIGQUIT, &sa, NULL);
|
||||
}
|
||||
if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
|
||||
(void) signal(SIGTERM, JobPassSig);
|
||||
(void) sigaction(SIGTERM, &sa, NULL);
|
||||
}
|
||||
/*
|
||||
* There are additional signals that need to be caught and passed if
|
||||
@ -2109,16 +2151,16 @@ Job_Init(int maxproc)
|
||||
*/
|
||||
#if defined(USE_PGRP)
|
||||
if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) {
|
||||
(void) signal(SIGTSTP, JobPassSig);
|
||||
(void) sigaction(SIGTSTP, &sa, NULL);
|
||||
}
|
||||
if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) {
|
||||
(void) signal(SIGTTOU, JobPassSig);
|
||||
(void) sigaction(SIGTTOU, &sa, NULL);
|
||||
}
|
||||
if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) {
|
||||
(void) signal(SIGTTIN, JobPassSig);
|
||||
(void) sigaction(SIGTTIN, &sa, NULL);
|
||||
}
|
||||
if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) {
|
||||
(void) signal(SIGWINCH, JobPassSig);
|
||||
(void) sigaction(SIGWINCH, &sa, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2447,6 +2489,10 @@ JobInterrupt(int runINTERRUPT, int signo)
|
||||
}
|
||||
|
||||
if (runINTERRUPT && !touchFlag) {
|
||||
/* clear the interrupted flag because we would get an
|
||||
* infinite loop otherwise */
|
||||
interrupted = 0;
|
||||
|
||||
interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);
|
||||
if (interrupt != NULL) {
|
||||
ignoreErrors = FALSE;
|
||||
|
Loading…
Reference in New Issue
Block a user