From 5dc4b92b606351290d979371da4a500ce8f6a57e Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Mon, 23 Aug 1999 22:15:17 +0000 Subject: * Fix jobserver algorithm again. * A couple of nits. * Fix considered pruning for double-colon rules. --- .cvsignore | 2 ++ ChangeLog | 52 +++++++++++++++++++++++++++++++++++++++++ README.template | 11 ++++----- configure.in | 2 +- job.c | 72 ++++++++++++++++++++++++++++----------------------------- job.h | 1 - main.c | 23 +++++++++--------- remake.c | 22 +++++++++--------- 8 files changed, 118 insertions(+), 67 deletions(-) diff --git a/.cvsignore b/.cvsignore index 446fbca..fb15a2b 100644 --- a/.cvsignore +++ b/.cvsignore @@ -22,3 +22,5 @@ sun4 i386 i386-netbsd hp300-netbsd hp300 rs6000 sun3 news800 amiga hp700 hp834 mips sol2 i486-linux customs + +install-sh mkinstalldirs diff --git a/ChangeLog b/ChangeLog index c6e22bb..92e54e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,55 @@ +1999-08-23 Paul D. Smith + + * remake.c (update_file): Move the considered check into the + double-colon rule loop, so we consider double-colon rules + individually (otherwise after the first is pruned, the rest might + not get run). + + * README.template: Minor changes. + + Remove the debugging features of the jobserver, so it no longer + writes distinct tokens to the pipe. Thus, we don't need to store + the token we get. A side effect of this is to remove a potential + "unavailable token" situation: make-1 invokes make-2 with its + special token and make-3 with a normal token; make-2 completes. + Now we're waiting for make-3 but using 2 tokens; our special token + is idle. In the new version we don't have special tokens per se, + we merely decide if we already have a child or not. If we don't, + we don't need a token. If we do, we have to get one to run the + next child. Similar for putting tokens back: if we're cleaning up + the last child, we don't put a token back. Otherwise, we do. + + * main.c: Add a new, internal flag --jobserver-fds instead of + overloading the meaning of -j. Remove job_slots_str and add the + stringlist jobserver_fds. + (struct command_switch): We don't need the int_string type. + (switches[]): Add a new option for --jobserver-fds and remove + conditions around -j. Make the description for the former 0 so it + doesn't print during "make --help". + (main): Rework jobserver parsing. If we got --jobserver-fds + make sure it's valid. We only get one and job_slots must be 0. + If we're the toplevel make (-jN without --jobserver-fds) create + the pipe and write generic tokens. + Create the stringlist struct for the submakes. + Clean up the stringlist where necessary. + (init_switches): Remove int_string handling. + (print_usage): Don't print internal flags (description ptr is 0). + (decode_switches): Remove int_string handling. + (define_makeflags): Remove int_string handling. + + * job.c: Remove my_job_token flag and all references to the + child->job_token field. + (free_job_token): Remove this and merge it into free_child(). + (reap_children): Rework the "reaped a child" logic slightly. + Don't call defunct free_job_token anymore. Always call + free_child, even if we're dying. + (free_child): If we're not freeing the only child, put a token + back in the pipe. Then, if we're dying, don't bother to free. + (new_job): If we are using the jobserver, loop checking to see if + a) there are no children or b) we get a token from the pipe. + + * job.h (struct child): Remove the job_token field. + 1999-08-20 Paul D. Smith * variable.c (try_variable_definition): Allocate for variable diff --git a/README.template b/README.template index c9a199d..a8ea5a8 100644 --- a/README.template +++ b/README.template @@ -1,6 +1,7 @@ This directory contains the %VERSION% release of GNU Make. -All bugs reported for previous releases have been fixed. -Some bugs surely remain. + +See the file NEWS for the user-visible changes from previous releases. +In addition, there have been bugs fixed. For general building and installation instructions, see the file INSTALL. @@ -24,6 +25,8 @@ site. There is information there about ordering hardcopy documentation. http://www.gnu.org/doc/doc.html http://www.gnu.org/manual/manual.html +You can also find the latest versions of GNU Make from there. + Please send GNU make bug reports to bug-make@gnu.org. Please see the section of the manual entitles `Problems and Bugs' for information on submitting bug reports. @@ -61,9 +64,5 @@ debug this code, you can do `make check-loadavg' to see if it works properly on your system. (You must run `configure' beforehand, but you need not build Make itself to run this test.) -See the file NEWS for what has changed since previous releases. - -GNU Make is fully documented in make.texinfo. See the section entitled -`Problems and Bugs' for information on submitting bug reports. GNU Make is free software. See the file COPYING for copying conditions. diff --git a/configure.in b/configure.in index c320a2a..9cc0b05 100644 --- a/configure.in +++ b/configure.in @@ -3,7 +3,7 @@ AC_REVISION([$Id$]) AC_PREREQ(2.13)dnl dnl Minimum Autoconf version required. AC_INIT(vpath.c)dnl dnl A distinctive file to look for in srcdir. -AM_INIT_AUTOMAKE(make, 3.77.93) +AM_INIT_AUTOMAKE(make, 3.77.94) AM_CONFIG_HEADER(config.h) dnl Regular configure stuff diff --git a/job.c b/job.c index 34d1ddd..01a99ae 100644 --- a/job.c +++ b/job.c @@ -310,8 +310,6 @@ extern int shell_function_pid, shell_function_completed; complete child, waiting for it to die if necessary. If ERR is nonzero, print an error message first. */ -static int rc_block, rc_reap_all, rc_got_block, rc_start_rfd, rc_end_rfd; - void reap_children (block, err) int block, err; @@ -326,11 +324,6 @@ reap_children (block, err) # define REAP_MORE dead_children #endif - rc_block = block; - rc_reap_all = 0; - rc_got_block = 0; - rc_start_rfd = job_rfd; - /* As long as: We have at least one child outstanding OR a shell function in progress, @@ -451,7 +444,6 @@ reap_children (block, err) { /* No local children are dead. */ reap_more = 0; - rc_reap_all = 1; if (!block || !any_remote) break; @@ -677,10 +669,8 @@ reap_children (block, err) /* Only block for one child. */ block = 0; - rc_block = block; } - rc_end_rfd = job_rfd; return; } @@ -691,11 +681,12 @@ free_child (child) register struct child *child; { /* If this child is the only one it was our "free" job, so don't put a - token back for it. */ + token back for it. This child has already been removed from the list, + so if there any left this wasn't the last one. */ - if (job_fds[1] >= 0 && (child != children || child->next != 0)) + if (job_fds[1] >= 0 && children) { - char *token = '+'; + char token = '+'; /* Write a job token back to the pipe. */ @@ -874,7 +865,7 @@ start_job_command (child) ? "%s" : (char *) 0, p); /* Optimize an empty command. People use this for timestamp rules, - and forking a useless shell all the time leads to inefficiency. */ + so avoid forking a useless shell. */ #if !defined(VMS) && !defined(_AMIGA) if ( @@ -1361,6 +1352,7 @@ new_job (file) /* Wait for a job slot to be freed up. If we allow an infinite number don't bother; also job_slots will == 0 if we're using the jobserver. */ + if (job_slots != 0) while (job_slots_used == job_slots) reap_children (1, 0); @@ -1369,41 +1361,49 @@ new_job (file) /* If we are controlling multiple jobs make sure we have a token before starting the child. */ + /* This can be inefficient. There's a decent chance that this job won't + actually have to run any subprocesses: the command script may be empty + or otherwise optimized away. It would be nice if we could defer + obtaining a token until just before we need it, in start_job_command. + To do that we'd need to keep track of whether we'd already obtained a + token (since start_job_command is called for each line of the job, not + just once). Also more thought needs to go into the entire algorithm; + this is where the old parallel job code waits, so... */ + else if (job_fds[0] >= 0) - if (children == 0) - { - char token = '-'; + while (1) + { + char token; - while (token == '-') /* If we don't already have a job started, use our "free" token. */ - if (children == 0) - token = '+'; + if (!children) + break; /* Read a token. As long as there's no token available we'll block. If we get a SIGCHLD we'll return with EINTR. If one happened before we got here we'll return immediately with EBADF because the signal handler closes the dup'd file descriptor. */ - else if (read (job_rfd, &c->job_token, 1) < 1) + if (read (job_rfd, &token, 1) == 1) { - if (errno != EINTR && errno != EBADF) - pfatal_with_name (_("read jobs pipe")); + if (debug_flag) + printf (_("Obtained token for child 0x%08lx (%s).\n"), + (unsigned long int) c, c->file->name); + break; + } - /* Re-dup the read side of the pipe, so the signal handler can - notify us if we miss a child. */ - if (job_rfd < 0) - job_rfd = dup (job_fds[0]); + if (errno != EINTR && errno != EBADF) + pfatal_with_name (_("read jobs pipe")); - /* Something's done. We don't want to block for a whole child, - just reap whatever's there. */ - reap_children (0, 0); - } + /* Re-dup the read side of the pipe, so the signal handler can + notify us if we miss a child. */ + if (job_rfd < 0) + job_rfd = dup (job_fds[0]); - assert (c->job_token != '-'); - if (debug_flag) - printf (_("Obtained token for child 0x%08lx (%s).\n"), - (unsigned long int) c, c->file->name); - } + /* Something's done. We don't want to block for a whole child, + just reap whatever's there. */ + reap_children (0, 0); + } #endif /* The job is now primed. Start it running. diff --git a/job.h b/job.h index 4c5e7e5..00e9599 100644 --- a/job.h +++ b/job.h @@ -46,7 +46,6 @@ struct child unsigned int good_stdin:1; /* Nonzero if this child has a good stdin. */ unsigned int deleted:1; /* Nonzero if targets have been deleted. */ - char job_token; /* The token read from the job pipe. */ }; extern struct child *children; diff --git a/main.c b/main.c index dcab8b5..de82b59 100644 --- a/main.c +++ b/main.c @@ -1301,11 +1301,15 @@ int main (int argc, char ** argv) { char *cp; - if (jobserver_fds->max > 1) - fatal (NILF, _("internal error: multiple --jobserver-fds options.")); + if (jobserver_fds->idx > 1) + fatal (NILF, _("internal error: multiple --jobserver-fds options")); - if (job_slots > 0) - fatal (NILF, _("internal error: --jobserver-fds unexpected.")); + /* The combination of a pipe + !job_slots means we're using the + jobserver. If !job_slots and we don't have a pipe, we can start + infinite jobs. */ + + if (job_slots != 0) + fatal (NILF, _("internal error: --jobserver-fds unexpected")); /* Now parse the fds string and make sure it has the proper format. */ @@ -1313,13 +1317,7 @@ int main (int argc, char ** argv) if (sscanf (cp, "%d,%d", &job_fds[0], &job_fds[1]) != 2) fatal (NILF, - _("internal error: invalid --jobserver-fds string `%s'."), cp); - - /* Set job_slots to 0. The combination of a pipe + !job_slots means - we're using the jobserver. If !job_slots and we don't have a pipe, we - can start infinite jobs. */ - - job_slots = 0; + _("internal error: invalid --jobserver-fds string `%s'"), cp); /* Create a duplicate pipe, that will be closed in the SIGCHLD handler. If this fails with EBADF, the parent has closed the pipe @@ -1353,7 +1351,8 @@ int main (int argc, char ** argv) /* Every make assumes that it always has one job it can run. For the submakes it's the token they were given by their parent. For the - top make, we just subtract one from the number the user wants. */ + top make, we just subtract one from the number the user wants. We + want job_slots to be 0 to indicate we're using the jobserver. */ while (--job_slots) while (write (job_fds[1], &c, 1) != 1) diff --git a/remake.c b/remake.c index 74c4a9a..d96d4ed 100644 --- a/remake.c +++ b/remake.c @@ -316,19 +316,19 @@ update_file (file, depth) register int status = 0; register struct file *f; - /* Prune the dependency graph: if we've already been here on _this_ pass - through the dependency graph, we don't have to go any further. We won't - reap_children until we start the next pass, so no state change is - possible below here until then. */ - if (file->considered == considered) - { - DEBUGPR (_("Pruning file `%s'.\n")); - return 0; - } - file->considered = considered; - for (f = file->double_colon ? file->double_colon : file; f != 0; f = f->prev) { + /* Prune the dependency graph: if we've already been here on _this_ + pass through the dependency graph, we don't have to go any further. + We won't reap_children until we start the next pass, so no state + change is possible below here until then. */ + if (f->considered == considered) + { + DEBUGPR (_("Pruning file `%s'.\n")); + continue; + } + f->considered = considered; + status |= update_file_1 (f, depth); check_renamed (f); -- cgit v1.2.3