Date: Thu, 11 Nov 2004 20:42:21 +0100 From: Poul-Henning Kamp <phk@phk.freebsd.dk> To: current@freebsd.org Subject: [TEST] make -j patch Message-ID: <80546.1100202141@critter.freebsd.dk>
next in thread | raw e-mail | index | archive | help
This patch makes the '-j' argument to make(1) become a global limit on number of jobs launched for all submakes in the build. Today a "make -j 12" may start many more than 12 jobs because each submake interprets the 12 without reference to other makes. The patch uses a fifo to hold tokens allowing jobstarts. Poul-Henning Index: job.c =================================================================== RCS file: /home/ncvs/src/usr.bin/make/job.c,v retrieving revision 1.55 diff -u -r1.55 job.c --- job.c 11 Nov 2004 12:52:15 -0000 1.55 +++ job.c 11 Nov 2004 19:15:30 -0000 @@ -258,6 +258,8 @@ * jobs that were stopped due to concurrency * limits or externally */ +STATIC int fifoFd; /* Fd of our job fifo */ +STATIC char fifoName[] = "/tmp/make_fifo_XXXXXXXXX"; #if defined(USE_PGRP) && defined(SYSV) # define KILL(pid, sig) killpg(-(pid), (sig)) @@ -1091,6 +1093,8 @@ Punt("Cannot fork"); } else if (cpid == 0) { + if (fifoFd >= 0) + close(fifoFd); /* * Must duplicate the input stream down to the child's input and * reset it to the beginning (again). Since the stream was marked @@ -1891,9 +1895,10 @@ return; } - while ((pid = waitpid((pid_t) -1, &status, - (block?0:WNOHANG)|WUNTRACED)) > 0) - { + for (;;) { + pid = waitpid((pid_t) -1, &status, (block?0:WNOHANG)|WUNTRACED); + if (pid <= 0) + break; DEBUGF(JOB, ("Process %d exited or stopped.\n", pid)); jnode = Lst_Find(jobs, (void *)&pid, JobCmpPid); @@ -1915,8 +1920,17 @@ job = (Job *) Lst_Datum(jnode); (void) Lst_Remove(jobs, jnode); nJobs -= 1; - DEBUGF(JOB, ("Job queue is no longer full.\n")); - jobFull = FALSE; + if (fifoFd >= 0 && nJobs > 0) { + write(fifoFd, "+", 1); + maxJobs--; + if (nJobs >= maxJobs) + jobFull = TRUE; + else + jobFull = FALSE; + } else { + DEBUGF(JOB, ("Job queue is no longer full.\n")); + jobFull = FALSE; + } } JobFinish(job, &status); @@ -1982,23 +1996,28 @@ readfds = outputs; timeout.tv_sec = SEL_SEC; timeout.tv_usec = SEL_USEC; + if (jobFull && fifoFd >= 0) + FD_SET(fifoFd, &readfds); - if ((nfds = select(FD_SETSIZE, &readfds, (fd_set *) 0, - (fd_set *) 0, &timeout)) <= 0) + nfds = select(FD_SETSIZE, &readfds, (fd_set *) 0, + (fd_set *) 0, &timeout); + if (nfds <= 0) return; - else { - if (Lst_Open(jobs) == FAILURE) { - Punt("Cannot open job table"); - } - while (nfds && (ln = Lst_Next(jobs)) != NULL) { - job = (Job *) Lst_Datum(ln); - if (FD_ISSET(job->inPipe, &readfds)) { - JobDoOutput(job, FALSE); - nfds -= 1; - } + if (fifoFd >= 0 && FD_ISSET(fifoFd, &readfds)) { + if (--nfds <= 0) + return; + } + if (Lst_Open(jobs) == FAILURE) { + Punt("Cannot open job table"); + } + while (nfds && (ln = Lst_Next(jobs)) != NULL) { + job = (Job *) Lst_Datum(ln); + if (FD_ISSET(job->inPipe, &readfds)) { + JobDoOutput(job, FALSE); + nfds -= 1; } - Lst_Close(jobs); } + Lst_Close(jobs); #endif /* !USE_KQUEUE */ } } @@ -2055,19 +2074,62 @@ Job_Init(int maxproc) { GNode *begin; /* node for commands to do at the very start */ + const char *env; + fifoFd = -1; jobs = Lst_Init(FALSE); stoppedJobs = Lst_Init(FALSE); - maxJobs = maxproc; + env = getenv("MAKE_JOBS_FIFO"); + if (env == NULL && maxproc > 1) { + /* + * We did not find the environment variable so we are the leader. + * Create the fifo, open it, write one char per allowed job into + * the pipe. + */ + mktemp(fifoName); + if (!mkfifo(fifoName, 0600)) { + fifoFd = open(fifoName, O_RDWR | O_NONBLOCK, 0); + if (fifoFd >= 0) { + fcntl(fifoFd, F_SETFL, O_NONBLOCK); + env = fifoName; + setenv("MAKE_JOBS_FIFO", env, 1); + while (maxproc-- > 0) + write(fifoFd, "+", 1); + /*The master make does not get a magic token */ + jobFull = TRUE; + maxJobs = 0; + } else { + unlink(fifoName); + env = NULL; + } + } + } else if (env != NULL) { + /* + * We had the environment variable so we are a slave. + * Open fifo and give ourselves a magic token which represents + * the token our parent make has grabbed to start his make process. + * Otherwise the sub-makes would gobble up tokens and the proper + * number of tokens to specify to -j would depend on the depth of * the tree and the order of execution. + */ + fifoFd = open(env, O_RDWR, 0); + if (fifoFd >= 0) { + fcntl(fifoFd, F_SETFL, O_NONBLOCK); + maxJobs = 1; + jobFull = FALSE; + } + } + if (fifoFd <= 0) { + maxJobs = maxproc; + jobFull = FALSE; + } nJobs = 0; - jobFull = FALSE; aborting = 0; errors = 0; lastNode = NULL; - if (maxJobs == 1 || beVerbose == 0) { + if ((maxJobs == 1 && fifoFd < 0) || beVerbose == 0) { /* * If only one job can run at a time, there's no need for a banner, * no is there? @@ -2157,7 +2219,19 @@ Boolean Job_Full(void) { - return(aborting || jobFull); + char c; + int i; + + if (aborting) + return(aborting); + if (fifoFd >= 0 && jobFull) { + i = read(fifoFd, &c, 1); + if (i > 0) { + maxJobs++; + jobFull = FALSE; + } + } + return(jobFull); } /*- @@ -2485,6 +2559,8 @@ } } } + if (fifoFd >= 0) + unlink(fifoName); return(errors); } Index: make.c =================================================================== RCS file: /home/ncvs/src/usr.bin/make/make.c,v retrieving revision 1.24 diff -u -r1.24 make.c --- make.c 23 Oct 2002 23:16:43 -0000 1.24 +++ make.c 11 Nov 2004 14:36:35 -0000 @@ -637,7 +637,7 @@ { GNode *gn; - while (!Job_Full() && !Lst_IsEmpty (toBeMade)) { + while (!Lst_IsEmpty (toBeMade) && !Job_Full()) { gn = (GNode *) Lst_DeQueue (toBeMade); DEBUGF(MAKE, ("Examining %s...", gn->name)); /* -- Poul-Henning Kamp | UNIX since Zilog Zeus 3.20 phk@FreeBSD.ORG | TCP/IP since RFC 956 FreeBSD committer | BSD since 4.3-tahoe Never attribute to malice what can adequately be explained by incompetence.
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?80546.1100202141>