* Fix jobserver algorithm again.
authorPaul Smith <psmith@gnu.org>
Mon, 23 Aug 1999 22:15:17 +0000 (22:15 +0000)
committerPaul Smith <psmith@gnu.org>
Mon, 23 Aug 1999 22:15:17 +0000 (22:15 +0000)
* A couple of nits.
* Fix considered pruning for double-colon rules.

.cvsignore
ChangeLog
README.template
configure.in
job.c
job.h
main.c
remake.c

index 446fbca..fb15a2b 100644 (file)
@@ -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
index c6e22bb..92e54e2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,55 @@
+1999-08-23  Paul D. Smith  <psmith@gnu.org>
+
+       * 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  <psmith@gnu.org>
 
        * variable.c (try_variable_definition): Allocate for variable
index c9a199d..a8ea5a8 100644 (file)
@@ -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.
index c320a2a..9cc0b05 100644 (file)
@@ -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 (file)
--- 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;
 }
 \f
@@ -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 (file)
--- 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 (file)
--- 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)
index 74c4a9a..d96d4ed 100644 (file)
--- 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);