* Fix jobserver algorithm again.

* A couple of nits.
* Fix considered pruning for double-colon rules.
This commit is contained in:
Paul Smith 1999-08-23 22:15:17 +00:00
parent b3fa4b3c7e
commit 5dc4b92b60
8 changed files with 120 additions and 69 deletions

View 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

View file

@ -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

View 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.

View 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

76
job.c
View file

@ -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. */
else if (job_fds[0] >= 0)
if (children == 0)
{
char token = '-';
/* 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)
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"));
/* 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]);
/* Something's done. We don't want to block for a whole child,
just reap whatever's there. */
reap_children (0, 0);
if (debug_flag)
printf (_("Obtained token for child 0x%08lx (%s).\n"),
(unsigned long int) c, c->file->name);
break;
}
assert (c->job_token != '-');
if (debug_flag)
printf (_("Obtained token for child 0x%08lx (%s).\n"),
(unsigned long int) c, c->file->name);
}
if (errno != EINTR && errno != EBADF)
pfatal_with_name (_("read jobs pipe"));
/* 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]);
/* 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.

1
job.h
View file

@ -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;

23
main.c
View file

@ -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)

View file

@ -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);