From 890e9a1734c943c5e296b66a644b8ded1329e8fa Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Fri, 23 Feb 2024 10:34:42 -0800 Subject: [PATCH] wip --- build.c | 59 ++++++++++++------------------------ build.h | 2 +- samu.c | 93 +++++++++++++++++++++++++++++---------------------------- 3 files changed, 68 insertions(+), 86 deletions(-) diff --git a/build.c b/build.c index 6bc2b74..6f40b0f 100644 --- a/build.c +++ b/build.c @@ -33,7 +33,7 @@ static struct edge *work; static size_t nstarted, nfinished, ntotal; static bool consoleused; static struct timespec starttime; -static char gmaketokens[512], *gmakelatest = gmaketokens; +static char jobtokens[512], *gmakelatest = gmaketokens; void buildreset(void) @@ -320,15 +320,6 @@ jobstart(struct job *j, struct edge *e) warn("posix_spawn_file_actions_addclose:"); goto err3; } - if (buildopts.gmakepipe[0] >= 0) { - /* do not allow children to steal GNU/tokens */ - for (i = 0; i < 2; ++i) { - if ((errno = posix_spawn_file_actions_addclose(&actions, buildopts.gmakepipe[i]))) { - warn("posix_spawn_file_actions_addclose:"); - goto err3; - } - } - } if (e->pool != &consolepool) { if ((errno = posix_spawn_file_actions_addopen(&actions, 0, "/dev/null", O_RDONLY, 0))) { warn("posix_spawn_file_actions_addopen:"); @@ -548,30 +539,13 @@ queryload(void) #endif } -/* returns remaining GNU/tokens */ -static ssize_t -returngmake(void) -{ - ssize_t returned = 0; - if (buildopts.gmakepipe[1] >= 0) - if ((returned = write(buildopts.gmakepipe[1], gmaketokens, gmakelatest - gmaketokens)) >= 0) - gmakelatest = gmaketokens; - return returned; -} - static void -gmakeatexit(void) +jobserverclose(void) { - if (returngmake() < 0) - warn("last write to jobserver:"); -} - -static void -termsignal(int signum) -{ - write(2, "terminating due to signal\n", 27); - (void)returngmake(); - _exit(128 + signum); + if (buildopts.jobserver[1] == -1) + return; + if (write(buildopts.jobserver[1], jobtokens, njobtokens) < 0) + warn("jobserver: write:"); } void @@ -589,7 +563,10 @@ build(void) return; } - if (buildopts.gmakepipe[0] >= 0) { + if (buildopts.jobserver[0] != -1) { + maxjobs = 0; + fds = xmalloc(sizeof *fds); + fds = xreallocarray(fds, jobslen, sizeof(fds[0])); if (atexit(gmakeatexit) == 0) { maxjobs = 1; /* will change dynamically as tokens are exchanged */ tokenin.fd = buildopts.gmakepipe[0]; @@ -640,18 +617,18 @@ build(void) if (jobslen > buildopts.maxjobs) jobslen = buildopts.maxjobs; jobs = xreallocarray(jobs, jobslen, sizeof(jobs[0])); - fds = xreallocarray(fds, jobslen, sizeof(fds[0])); + fds = xreallocarray(1 + fds, jobslen, sizeof(fds[0])); for (i = next; i < jobslen; ++i) { jobs[i].buf.data = NULL; jobs[i].buf.len = 0; jobs[i].buf.cap = 0; jobs[i].next = i + 1; - fds[i].fd = -1; - fds[i].events = POLLIN; + fds[1 + i].fd = -1; + fds[1 + i].events = POLLIN; } } - fds[next].fd = jobstart(&jobs[next], e); - if (fds[next].fd < 0) { + fds[1 + next].fd = jobstart(&jobs[next], e); + if (fds[1 + next].fd < 0) { warn("job failed to start"); ++numfail; } else { @@ -661,9 +638,11 @@ build(void) } if (numjobs == 0) break; - if (poll(fds, jobslen, 5000) < 0) + if (poll(fds, 1 + jobslen, 5000) < 0) fatal("poll:"); - for (i = 0; i < jobslen; ++i) { + if (fds[0].revents) { + } + for (i = 1; i <= jobslen; ++i) { if (!fds[i].revents || jobwork(&jobs[i])) continue; --numjobs; diff --git a/build.h b/build.h index 3760031..f87ef83 100644 --- a/build.h +++ b/build.h @@ -5,7 +5,7 @@ struct buildoptions { _Bool verbose, explain, keepdepfile, keeprsp, dryrun; const char *statusfmt; double maxload; - int gmakepipe[2]; + int jobserver[2]; }; extern struct buildoptions buildopts; diff --git a/samu.c b/samu.c index 3ce1ba4..2a8b025 100644 --- a/samu.c +++ b/samu.c @@ -4,9 +4,9 @@ #include #include #include -#include /* for chdir */ +#include /* for chdir */ #include /* for poll */ -#include /* for open */ +#include /* for open, fcntl */ #include "arg.h" #include "build.h" #include "deps.h" @@ -93,58 +93,61 @@ jobsflag(const char *flag) } static void -jobserverflags(const char *flag) +parsegmakeflags(const char *flag) { - int read_end, write_end; - char *fifo_path; - struct pollfd check[2]; + char authbuf[1024]; + const char *auth, *end; + size_t authlen; + int rfd, wfd; if (!flag) return; - if (sscanf(flag, "%d,%d", &read_end, &write_end) == 2) { - /* prepare error message */ - errno = EBADF; - } else if (sscanf(flag,"fifo:%ms", &fifo_path) == 1) { - read_end = open(fifo_path, O_RDONLY); - write_end = open(fifo_path, O_WRONLY); - free(fifo_path); - } else { - fatal("invalid jobserver parameter"); + for (; *flag != ' '; ++flag) { + switch (*flag) { + case 'n': + buildopts.dryrun = true; + break; + case '\0': + return; + } } - - check[0].fd = read_end; - check[1].fd = write_end; - if (write_end <= 0 || read_end <= 0 || poll(check, 2, 0) == -1 || check[0].revents & POLLNVAL || check[1].revents & POLLNVAL) { - fatal("invalid jobserver fds:"); - return; + while (flag) { + ++flag; + end = strchr(flag, ' '); + if (strncmp(flag, "--jobserver-auth=", 17) == 0) { + auth = flag + 17; + authlen = end ? end - auth : strlen(auth); + } + flag = end; } - buildopts.gmakepipe[0] = check[0].fd; - buildopts.gmakepipe[1] = check[1].fd; - warn("using GNU Make jobserver"); -} - -static void -parsegmakeflags(char *env) { - char *arg; - - if (!env) + if (authlen >= sizeof(authbuf)) { + warn("jobserver: MAKEFLAGS option is too long; ignoring"); return; - env = xmemdup(env, strlen(env) + 1); - - arg = strtok(env, " "); - /* first word might contain dry run */ - if (arg && strchr(arg, 'n')) - buildopts.dryrun = true; - arg = strtok(NULL, " "); - while (arg) { - if (strncmp(arg, "-j", 2) == 0) { - /* handled by parent process */ - } else if (strncmp(arg, "--jobserver-auth=", 17) == 0 || strncmp(arg, "--jobserver-fds=", 16) == 0) { - jobserverflags(strchr(arg, '=')+1); + } + memcpy(authbuf, auth, authlen); + authbuf[authlen] = 0; + auth = authbuf; + + if (strncmp(auth, "fifo:", 5) == 0) { + auth += 5; + rfd = wfd = open(auth, O_RDONLY | O_CLOEXEC); + if (rfd < 0) { + warn("jobserver: open %s:", auth); + return; } - arg = strtok(NULL, " "); + } else if (sscanf(auth, "%d,%d", &rfd, &wfd) == 2) { + if (rfd < 0 || wfd < 0) + return; /* jobserver is disabled */ + if (fcntl(rfd, F_SETFD, FD_CLOEXEC) != 0 || fcntl(wfd, F_SETFD, FD_CLOEXEC) != 0) { + warn("jobserver: fcntl set FD_CLOEXEC:"); + return; + } + } else { + warn("jobserver: MAKEFLAGS option has unrecognized format; ignoring"); + return; } - free(env); + buildops.jobserver[0] = rfd; + buildops.jobserver[1] = wfd; } static void