mirror of
https://github.com/mirror/make.git
synced 2025-01-27 21:00:22 +08:00
* Fix jobserver algorithm again.
* A couple of nits. * Fix considered pruning for double-colon rules.
This commit is contained in:
parent
b3fa4b3c7e
commit
5dc4b92b60
@ -22,3 +22,5 @@ sun4 i386 i386-netbsd hp300-netbsd hp300 rs6000 sun3 news800 amiga
|
|||||||
hp700 hp834 mips sol2 i486-linux
|
hp700 hp834 mips sol2 i486-linux
|
||||||
|
|
||||||
customs
|
customs
|
||||||
|
|
||||||
|
install-sh mkinstalldirs
|
||||||
|
52
ChangeLog
52
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>
|
1999-08-20 Paul D. Smith <psmith@gnu.org>
|
||||||
|
|
||||||
* variable.c (try_variable_definition): Allocate for variable
|
* variable.c (try_variable_definition): Allocate for variable
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
This directory contains the %VERSION% release of GNU Make.
|
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.
|
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/doc/doc.html
|
||||||
http://www.gnu.org/manual/manual.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
|
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
|
section of the manual entitles `Problems and Bugs' for information on
|
||||||
submitting bug reports.
|
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
|
properly on your system. (You must run `configure' beforehand, but you
|
||||||
need not build Make itself to run this test.)
|
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.
|
GNU Make is free software. See the file COPYING for copying conditions.
|
||||||
|
@ -3,7 +3,7 @@ AC_REVISION([$Id$])
|
|||||||
AC_PREREQ(2.13)dnl dnl Minimum Autoconf version required.
|
AC_PREREQ(2.13)dnl dnl Minimum Autoconf version required.
|
||||||
AC_INIT(vpath.c)dnl dnl A distinctive file to look for in srcdir.
|
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)
|
AM_CONFIG_HEADER(config.h)
|
||||||
|
|
||||||
dnl Regular configure stuff
|
dnl Regular configure stuff
|
||||||
|
76
job.c
76
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,
|
complete child, waiting for it to die if necessary. If ERR is nonzero,
|
||||||
print an error message first. */
|
print an error message first. */
|
||||||
|
|
||||||
static int rc_block, rc_reap_all, rc_got_block, rc_start_rfd, rc_end_rfd;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
reap_children (block, err)
|
reap_children (block, err)
|
||||||
int block, err;
|
int block, err;
|
||||||
@ -326,11 +324,6 @@ reap_children (block, err)
|
|||||||
# define REAP_MORE dead_children
|
# define REAP_MORE dead_children
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
rc_block = block;
|
|
||||||
rc_reap_all = 0;
|
|
||||||
rc_got_block = 0;
|
|
||||||
rc_start_rfd = job_rfd;
|
|
||||||
|
|
||||||
/* As long as:
|
/* As long as:
|
||||||
|
|
||||||
We have at least one child outstanding OR a shell function in progress,
|
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. */
|
/* No local children are dead. */
|
||||||
reap_more = 0;
|
reap_more = 0;
|
||||||
rc_reap_all = 1;
|
|
||||||
|
|
||||||
if (!block || !any_remote)
|
if (!block || !any_remote)
|
||||||
break;
|
break;
|
||||||
@ -677,10 +669,8 @@ reap_children (block, err)
|
|||||||
|
|
||||||
/* Only block for one child. */
|
/* Only block for one child. */
|
||||||
block = 0;
|
block = 0;
|
||||||
rc_block = block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_end_rfd = job_rfd;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -691,11 +681,12 @@ free_child (child)
|
|||||||
register struct child *child;
|
register struct child *child;
|
||||||
{
|
{
|
||||||
/* If this child is the only one it was our "free" job, so don't put a
|
/* 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. */
|
/* Write a job token back to the pipe. */
|
||||||
|
|
||||||
@ -874,7 +865,7 @@ start_job_command (child)
|
|||||||
? "%s" : (char *) 0, p);
|
? "%s" : (char *) 0, p);
|
||||||
|
|
||||||
/* Optimize an empty command. People use this for timestamp rules,
|
/* 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 !defined(VMS) && !defined(_AMIGA)
|
||||||
if (
|
if (
|
||||||
@ -1361,6 +1352,7 @@ new_job (file)
|
|||||||
|
|
||||||
/* Wait for a job slot to be freed up. If we allow an infinite number
|
/* 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. */
|
don't bother; also job_slots will == 0 if we're using the jobserver. */
|
||||||
|
|
||||||
if (job_slots != 0)
|
if (job_slots != 0)
|
||||||
while (job_slots_used == job_slots)
|
while (job_slots_used == job_slots)
|
||||||
reap_children (1, 0);
|
reap_children (1, 0);
|
||||||
@ -1369,41 +1361,49 @@ new_job (file)
|
|||||||
/* If we are controlling multiple jobs make sure we have a token before
|
/* If we are controlling multiple jobs make sure we have a token before
|
||||||
starting the child. */
|
starting the child. */
|
||||||
|
|
||||||
else if (job_fds[0] >= 0)
|
/* This can be inefficient. There's a decent chance that this job won't
|
||||||
if (children == 0)
|
actually have to run any subprocesses: the command script may be empty
|
||||||
{
|
or otherwise optimized away. It would be nice if we could defer
|
||||||
char token = '-';
|
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 we don't already have a job started, use our "free" token. */
|
||||||
if (children == 0)
|
if (!children)
|
||||||
token = '+';
|
break;
|
||||||
|
|
||||||
/* Read a token. As long as there's no token available we'll block.
|
/* 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
|
If we get a SIGCHLD we'll return with EINTR. If one happened
|
||||||
before we got here we'll return immediately with EBADF because
|
before we got here we'll return immediately with EBADF because
|
||||||
the signal handler closes the dup'd file descriptor. */
|
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)
|
if (debug_flag)
|
||||||
pfatal_with_name (_("read jobs pipe"));
|
printf (_("Obtained token for child 0x%08lx (%s).\n"),
|
||||||
|
(unsigned long int) c, c->file->name);
|
||||||
/* Re-dup the read side of the pipe, so the signal handler can
|
break;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert (c->job_token != '-');
|
if (errno != EINTR && errno != EBADF)
|
||||||
if (debug_flag)
|
pfatal_with_name (_("read jobs pipe"));
|
||||||
printf (_("Obtained token for child 0x%08lx (%s).\n"),
|
|
||||||
(unsigned long int) c, c->file->name);
|
/* 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
|
#endif
|
||||||
|
|
||||||
/* The job is now primed. Start it running.
|
/* The job is now primed. Start it running.
|
||||||
|
1
job.h
1
job.h
@ -46,7 +46,6 @@ struct child
|
|||||||
|
|
||||||
unsigned int good_stdin:1; /* Nonzero if this child has a good stdin. */
|
unsigned int good_stdin:1; /* Nonzero if this child has a good stdin. */
|
||||||
unsigned int deleted:1; /* Nonzero if targets have been deleted. */
|
unsigned int deleted:1; /* Nonzero if targets have been deleted. */
|
||||||
char job_token; /* The token read from the job pipe. */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct child *children;
|
extern struct child *children;
|
||||||
|
23
main.c
23
main.c
@ -1301,11 +1301,15 @@ int main (int argc, char ** argv)
|
|||||||
{
|
{
|
||||||
char *cp;
|
char *cp;
|
||||||
|
|
||||||
if (jobserver_fds->max > 1)
|
if (jobserver_fds->idx > 1)
|
||||||
fatal (NILF, _("internal error: multiple --jobserver-fds options."));
|
fatal (NILF, _("internal error: multiple --jobserver-fds options"));
|
||||||
|
|
||||||
if (job_slots > 0)
|
/* The combination of a pipe + !job_slots means we're using the
|
||||||
fatal (NILF, _("internal error: --jobserver-fds unexpected."));
|
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. */
|
/* 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)
|
if (sscanf (cp, "%d,%d", &job_fds[0], &job_fds[1]) != 2)
|
||||||
fatal (NILF,
|
fatal (NILF,
|
||||||
_("internal error: invalid --jobserver-fds string `%s'."), cp);
|
_("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;
|
|
||||||
|
|
||||||
/* Create a duplicate pipe, that will be closed in the SIGCHLD
|
/* Create a duplicate pipe, that will be closed in the SIGCHLD
|
||||||
handler. If this fails with EBADF, the parent has closed the pipe
|
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
|
/* 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
|
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 (--job_slots)
|
||||||
while (write (job_fds[1], &c, 1) != 1)
|
while (write (job_fds[1], &c, 1) != 1)
|
||||||
|
22
remake.c
22
remake.c
@ -316,19 +316,19 @@ update_file (file, depth)
|
|||||||
register int status = 0;
|
register int status = 0;
|
||||||
register struct file *f;
|
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)
|
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);
|
status |= update_file_1 (f, depth);
|
||||||
check_renamed (f);
|
check_renamed (f);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user