Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kill all children on SIGTERM #106

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 62 additions & 11 deletions build.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
Expand All @@ -34,6 +35,10 @@ static size_t nstarted, nfinished, ntotal;
static bool consoleused;
static struct timespec starttime;

/* for signal handling */
static volatile sig_atomic_t killall;
static volatile sig_atomic_t stopsig;

void
buildreset(void)
{
Expand Down Expand Up @@ -115,6 +120,11 @@ queue(struct edge *e)
*front = e;
}

static bool have_work(void)
{
return work && !stopsig;
}

void
buildadd(struct node *n)
{
Expand Down Expand Up @@ -453,7 +463,8 @@ jobdone(struct job *j)
j->failed = true;
}
} else if (WIFSIGNALED(status)) {
warn("job terminated due to signal %d: %s", WTERMSIG(status), j->cmd->s);
if (stopsig != WTERMSIG(status))
warn("job terminated due to signal %d: %s", WTERMSIG(status), j->cmd->s);
j->failed = true;
} else {
/* cannot happen according to POSIX */
Expand All @@ -465,6 +476,8 @@ jobdone(struct job *j)
fwrite(j->buf.data, 1, j->buf.len, stdout);
j->buf.len = 0;
e = j->edge;
j->edge = NULL;

if (e->pool) {
p = e->pool;

Expand All @@ -484,6 +497,14 @@ jobdone(struct job *j)
edgedone(e);
}

static void
jobkill(struct job *j)
{
kill(j->pid, SIGTERM);
j->failed = true;
jobdone(j);
}

/* returns whether a job still has work to do. if not, sets j->failed */
static bool
jobwork(struct job *j)
Expand All @@ -507,16 +528,16 @@ jobwork(struct job *j)
j->buf.len += n;
return true;
}
if (n == 0)
goto done;
warn("read:");
if (n < 0) {
warn("read:");
goto kill;
}

kill:
kill(j->pid, SIGTERM);
j->failed = true;
done:
jobdone(j);
return false;

kill:
jobkill(j);
return false;
}

Expand All @@ -538,19 +559,40 @@ queryload(void)
#endif
}

static void sighandler(int sig)
{
/*
* Both SIGINT and SIGTERM will not start any more processes,
* but only SIGTERM needs to be forwarded to samurai's child
* processes. That's because samurai is a process group leader
* and SIGINT has already been sent to all children, and they
* will stop on their own.
*/
if (sig == SIGTERM)
killall = true;
stopsig = sig;
}
bonzini marked this conversation as resolved.
Show resolved Hide resolved

void
build(void)
{
struct job *jobs = NULL;
struct pollfd *fds = NULL;
size_t i, next = 0, jobslen = 0, maxjobs = buildopts.maxjobs, numjobs = 0, numfail = 0;
struct edge *e;
struct sigaction sa;

if (ntotal == 0) {
warn("nothing to do");
return;
}

memset(&sa, 0, sizeof(sa));
sa.sa_handler = sighandler;
sa.sa_flags = SA_RESTART;
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);

clock_gettime(CLOCK_MONOTONIC, &starttime);
formatstatus(NULL, 0);

Expand All @@ -560,7 +602,7 @@ build(void)
if (buildopts.maxload)
maxjobs = queryload() > buildopts.maxload ? 1 : buildopts.maxjobs;
/* start ready edges */
while (work && numjobs < maxjobs && numfail < buildopts.maxfail) {
while (have_work() && numjobs < maxjobs && numfail < buildopts.maxfail) {
e = work;
work = work->worknext;
if (e->rule != &phonyrule && buildopts.dryrun) {
Expand Down Expand Up @@ -599,11 +641,16 @@ build(void)
}
if (numjobs == 0)
break;
if (poll(fds, jobslen, 5000) < 0)
if (poll(fds, jobslen, 5000) < 0 && errno != EINTR)
fatal("poll:");
for (i = 0; i < jobslen; ++i) {
if (!fds[i].revents || jobwork(&jobs[i]))
if (fds[i].fd == -1)
continue;
bonzini marked this conversation as resolved.
Show resolved Hide resolved
else if (killall)
jobkill(&jobs[i]);
else if (!fds[i].revents || jobwork(&jobs[i]))
continue;

--numjobs;
jobs[i].next = next;
fds[i].fd = -1;
Expand All @@ -619,6 +666,10 @@ build(void)
if (numfail > 0) {
if (numfail < buildopts.maxfail)
fatal("cannot make progress due to previous errors");
else if (stopsig == SIGINT)
fatal("interrupted by user");
else if (stopsig)
fatal("interrupted by signal %d", stopsig);
else if (numfail > 1)
fatal("subcommands failed");
else
Expand Down