* Start rewrite of jobserver to avoid unique tokens for debugging.

This commit is contained in:
Paul Smith 1999-08-23 05:35:14 +00:00
parent 6fa76a7d15
commit b3fa4b3c7e
2 changed files with 116 additions and 166 deletions

118
job.c
View File

@ -202,11 +202,6 @@ unsigned int job_slots_used = 0;
static int good_stdin_used = 0; static int good_stdin_used = 0;
/* Specifies whether the current process's reserved job token is in use.
'+' means it's available, '-' means it isn't. */
static char my_job_token = '+';
/* Chain of children waiting to run until the load average goes down. */ /* Chain of children waiting to run until the load average goes down. */
static struct child *waiting_jobs = 0; static struct child *waiting_jobs = 0;
@ -224,42 +219,11 @@ int unixy_shell = 1;
*/ */
int w32_kill(int pid, int sig) int w32_kill(int pid, int sig)
{ {
return ((process_kill(pid, sig) == TRUE) ? 0 : -1); return ((process_kill(pid, sig) == TRUE) ? 0 : -1);
} }
#endif /* WINDOWS32 */ #endif /* WINDOWS32 */
static void
free_job_token (child)
struct child *child;
{
switch (child->job_token)
{
case '-':
/* If this child doesn't have a token, punt. */
return;
case '+':
/* If this child has the reserved token, take it back. */
my_job_token = '+';
break;
default:
/* Write any other job tokens back to the pipe. */
while (write (job_fds[1], &child->job_token, 1) != 1)
if (!EINTR_SET)
pfatal_with_name (_("write jobserver"));
break;
}
if (debug_flag)
printf (_("Released token `%c' for child 0x%08lx (%s).\n"),
child->job_token, (unsigned long int) child, child->file->name);
child->job_token = '-';
}
/* Write an error message describing the exit status given in /* Write an error message describing the exit status given in
EXIT_CODE, EXIT_SIG, and COREDUMP, for the target TARGET_NAME. EXIT_CODE, EXIT_SIG, and COREDUMP, for the target TARGET_NAME.
Append "(ignored)" if IGNORED is nonzero. */ Append "(ignored)" if IGNORED is nonzero. */
@ -419,10 +383,9 @@ reap_children (block, err)
any_remote |= c->remote; any_remote |= c->remote;
any_local |= ! c->remote; any_local |= ! c->remote;
if (debug_flag) if (debug_flag)
printf (_("Live child 0x%08lx (%s) PID %ld token %c%s\n"), printf (_("Live child 0x%08lx (%s) PID %ld %s\n"),
(unsigned long int) c, c->file->name, (unsigned long int) c, c->file->name,
(long) c->pid, c->job_token, (long) c->pid, c->remote ? _(" (remote)") : "");
c->remote ? _(" (remote)") : "");
#ifdef VMS #ifdef VMS
break; break;
#endif #endif
@ -580,9 +543,9 @@ reap_children (block, err)
continue; continue;
if (debug_flag) if (debug_flag)
printf (_("Reaping %s child 0x%08lx PID %ld token %c%s\n"), printf (_("Reaping %s child 0x%08lx PID %ld %s\n"),
child_failed ? _("losing") : _("winning"), child_failed ? _("losing") : _("winning"),
(unsigned long int) c, (long) c->pid, c->job_token, (unsigned long int) c, (long) c->pid,
c->remote ? _(" (remote)") : ""); c->remote ? _(" (remote)") : "");
if (c->sh_batch_file) { if (c->sh_batch_file) {
@ -680,8 +643,8 @@ reap_children (block, err)
notice_finished_file (c->file); notice_finished_file (c->file);
if (debug_flag) if (debug_flag)
printf (_("Removing child 0x%08lx PID %ld token %c%s from chain.\n"), printf (_("Removing child 0x%08lx PID %ld %s from chain.\n"),
(unsigned long int) c, (long) c->pid, c->job_token, (unsigned long int) c, (long) c->pid,
c->remote ? _(" (remote)") : ""); c->remote ? _(" (remote)") : "");
/* Block fatal signals while frobnicating the list, so that /* Block fatal signals while frobnicating the list, so that
@ -691,9 +654,6 @@ reap_children (block, err)
live and call reap_children again. */ live and call reap_children again. */
block_sigs (); block_sigs ();
/* If this job has a token out, return it. */
free_job_token (c);
/* There is now another slot open. */ /* There is now another slot open. */
if (job_slots_used > 0) if (job_slots_used > 0)
--job_slots_used; --job_slots_used;
@ -703,8 +663,8 @@ reap_children (block, err)
children = c->next; children = c->next;
else else
lastc->next = c->next; lastc->next = c->next;
if (! handling_fatal_signal) /* Don't bother if about to die. */
free_child (c); free_child (c);
unblock_sigs (); unblock_sigs ();
@ -730,6 +690,27 @@ static void
free_child (child) 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
token back for it. */
if (job_fds[1] >= 0 && (child != children || child->next != 0))
{
char *token = '+';
/* Write a job token back to the pipe. */
while (write (job_fds[1], &token, 1) != 1)
if (!EINTR_SET)
pfatal_with_name (_("write jobserver"));
if (debug_flag)
printf (_("Released token for child 0x%08lx (%s).\n"),
(unsigned long int) child, child->file->name);
}
if (handling_fatal_signal) /* Don't bother free'ing if about to die. */
return;
if (child->command_lines != 0) if (child->command_lines != 0)
{ {
register unsigned int i; register unsigned int i;
@ -746,11 +727,6 @@ free_child (child)
free ((char *) child->environment); free ((char *) child->environment);
} }
/* If this child has a token it hasn't relinquished, give it up now.
This can happen if the job completes immediately, mainly because
all the command lines evaluated to empty strings. */
free_job_token (child);
free ((char *) child); free ((char *) child);
} }
@ -1220,10 +1196,9 @@ start_waiting_job (c)
case cs_running: case cs_running:
c->next = children; c->next = children;
if (debug_flag) if (debug_flag)
printf (_("Putting child 0x%08lx (%s) PID %ld token %c%s on the chain.\n"), printf (_("Putting child 0x%08lx (%s) PID %ld%s on the chain.\n"),
(unsigned long int) c, c->file->name, (unsigned long int) c, c->file->name,
(long) c->pid, c->job_token, (long) c->pid, c->remote ? _(" (remote)") : "");
c->remote ? _(" (remote)") : "");
children = c; children = c;
/* One more job slot is in use. */ /* One more job slot is in use. */
++job_slots_used; ++job_slots_used;
@ -1380,7 +1355,6 @@ new_job (file)
c->command_ptr = 0; c->command_ptr = 0;
c->environment = 0; c->environment = 0;
c->sh_batch_file = NULL; c->sh_batch_file = NULL;
c->job_token = '-';
/* Fetch the first command line to be run. */ /* Fetch the first command line to be run. */
job_next_command (c); job_next_command (c);
@ -1390,22 +1364,26 @@ new_job (file)
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);
#ifdef MAKE_JOBSERVER #ifdef MAKE_JOBSERVER
/* If we are controlling multiple jobs, and we don't yet have one, /* If we are controlling multiple jobs make sure we have a token before
obtain a token before starting the child. */ starting the child. */
else if (job_fds[0] >= 0) else if (job_fds[0] >= 0)
if (children == 0)
{ {
while (c->job_token == '-') char token = '-';
/* If the reserved token is available, just use that. */
if (my_job_token == '+') while (token == '-')
{ /* If we don't already have a job started, use our "free" token. */
c->job_token = my_job_token; if (children == 0)
my_job_token = '-'; token = '+';
}
/* 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) else if (read (job_rfd, &c->job_token, 1) < 1)
{ {
if (errno != EINTR && errno != EBADF) if (errno != EINTR && errno != EBADF)
@ -1423,14 +1401,14 @@ new_job (file)
assert (c->job_token != '-'); assert (c->job_token != '-');
if (debug_flag) if (debug_flag)
printf (_("Obtained token `%c' for child 0x%08lx (%s).\n"), printf (_("Obtained token for child 0x%08lx (%s).\n"),
c->job_token, (unsigned long int) c, c->file->name); (unsigned long int) c, c->file->name);
} }
#endif #endif
/* The job is now primed. Start it running. /* The job is now primed. Start it running.
(This will notice if there are in fact no commands.) */ (This will notice if there are in fact no commands.) */
(void)start_waiting_job (c); (void) start_waiting_job (c);
if (job_slots == 1) if (job_slots == 1)
/* Since there is only one job slot, make things run linearly. /* Since there is only one job slot, make things run linearly.

164
main.c
View File

@ -86,7 +86,6 @@ struct command_switch
flag, /* Turn int flag on. */ flag, /* Turn int flag on. */
flag_off, /* Turn int flag off. */ flag_off, /* Turn int flag off. */
string, /* One string per switch. */ string, /* One string per switch. */
int_string, /* One string. */
positive_int, /* A positive integer. */ positive_int, /* A positive integer. */
floating, /* A floating-point number (double). */ floating, /* A floating-point number (double). */
ignore /* Ignored. */ ignore /* Ignored. */
@ -104,6 +103,7 @@ struct command_switch
char *long_name; /* Long option name. */ char *long_name; /* Long option name. */
char *argdesc; /* Descriptive word for argument. */ char *argdesc; /* Descriptive word for argument. */
char *description; /* Description for usage message. */ char *description; /* Description for usage message. */
/* 0 means internal; don't display help. */
}; };
@ -195,15 +195,14 @@ static struct stringlist *makefiles = 0;
unsigned int job_slots = 1; unsigned int job_slots = 1;
unsigned int default_job_slots = 1; unsigned int default_job_slots = 1;
static char *job_slots_str = "1";
#ifndef MAKE_JOBSERVER
/* Value of job_slots that means no limit. */ /* Value of job_slots that means no limit. */
static unsigned int inf_jobs = 0; static unsigned int inf_jobs = 0;
#endif
/* File descriptors for the jobs pipe. */ /* File descriptors for the jobs pipe. */
static struct stringlist *jobserver_fds = 0;
int job_fds[2] = { -1, -1 }; int job_fds[2] = { -1, -1 };
int job_rfd = -1; int job_rfd = -1;
@ -278,14 +277,13 @@ static const struct command_switch switches[] =
"include-dir", _("DIRECTORY"), "include-dir", _("DIRECTORY"),
_("Search DIRECTORY for included makefiles") }, _("Search DIRECTORY for included makefiles") },
{ 'j', { 'j',
#ifndef MAKE_JOBSERVER
positive_int, (char *) &job_slots, 1, 1, 0, positive_int, (char *) &job_slots, 1, 1, 0,
(char *) &inf_jobs, (char *) &default_job_slots, (char *) &inf_jobs, (char *) &default_job_slots,
#else
int_string, (char *)&job_slots_str, 1, 1, 0, "0", "1",
#endif
"jobs", "N", "jobs", "N",
_("Allow N jobs at once; infinite jobs with no arg") }, _("Allow N jobs at once; infinite jobs with no arg") },
{ 2, string, (char *) &jobserver_fds, 1, 1, 0, 0, 0,
"jobserver-fds", 0,
0 },
{ 'k', flag, (char *) &keep_going_flag, 1, 1, 0, { 'k', flag, (char *) &keep_going_flag, 1, 1, 0,
0, (char *) &default_keep_going_flag, 0, (char *) &default_keep_going_flag,
"keep-going", 0, "keep-going", 0,
@ -338,13 +336,13 @@ static const struct command_switch switches[] =
{ 'w', flag, (char *) &print_directory_flag, 1, 1, 0, 0, 0, { 'w', flag, (char *) &print_directory_flag, 1, 1, 0, 0, 0,
"print-directory", 0, "print-directory", 0,
_("Print the current directory") }, _("Print the current directory") },
{ 2, flag, (char *) &inhibit_print_directory_flag, 1, 1, 0, 0, 0, { 3, flag, (char *) &inhibit_print_directory_flag, 1, 1, 0, 0, 0,
"no-print-directory", 0, "no-print-directory", 0,
_("Turn off -w, even if it was turned on implicitly") }, _("Turn off -w, even if it was turned on implicitly") },
{ 'W', string, (char *) &new_files, 0, 0, 0, 0, 0, { 'W', string, (char *) &new_files, 0, 0, 0, 0, 0,
"what-if", _("FILE"), "what-if", _("FILE"),
_("Consider FILE to be infinitely new") }, _("Consider FILE to be infinitely new") },
{ 3, flag, (char *) &warn_undefined_variables_flag, 1, 1, 0, 0, 0, { 4, flag, (char *) &warn_undefined_variables_flag, 1, 1, 0, 0, 0,
"warn-undefined-variables", 0, "warn-undefined-variables", 0,
_("Warn when an undefined variable is referenced") }, _("Warn when an undefined variable is referenced") },
{ '\0', } { '\0', }
@ -1297,52 +1295,58 @@ int main (int argc, char ** argv)
#endif #endif
#ifdef MAKE_JOBSERVER #ifdef MAKE_JOBSERVER
/* If extended jobs are available then the -j option can have one of 4 /* If the jobserver-fds option is seen, make sure that -j is reasonable. */
formats: (1) not specified: default is "1"; (2) specified with no value:
default is "0" (infinite); (3) specified with a single value: this means
the user wants N job slots; or (4) specified with 2 values separated by
a comma. The latter means we're a submake; the two values are the read
and write FDs, respectively, for the pipe. Note this last form is
undocumented for the user! */
sscanf (job_slots_str, "%d", &job_slots); if (jobserver_fds)
{ {
char *cp = index (job_slots_str, ','); char *cp;
/* In case #4, get the FDs. */ if (jobserver_fds->max > 1)
if (cp && sscanf (cp+1, "%d", &job_fds[1]) == 1) fatal (NILF, _("internal error: multiple --jobserver-fds options."));
if (job_slots > 0)
fatal (NILF, _("internal error: --jobserver-fds unexpected."));
/* Now parse the fds string and make sure it has the proper format. */
cp = jobserver_fds->list[0];
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;
/* Create a duplicate pipe, that will be closed in the SIGCHLD
handler. If this fails with EBADF, the parent has closed the pipe
on us because it didn't think we were a submake. If so, print a
warning then default to -j1. */
if ((job_rfd = dup (job_fds[0])) < 0)
{ {
/* Set up the first FD and set job_slots to 0. The combination of a if (errno != EBADF)
pipe + !job_slots means we're using the jobserver. If !job_slots pfatal_with_name (_("dup jobserver"));
and we don't have a pipe, we can start infinite jobs. */
job_fds[0] = job_slots;
job_slots = 0;
/* Create a duplicate pipe, that will be closed in the SIGCHLD error (NILF,
handler. If this fails with EBADF, the parent has closed the pipe _("warning: jobserver unavailable (using -j1). Add `+' to parent make rule."));
on us because it didn't think we were a submake. If so, print a job_slots = 1;
warning then default to -j1. */ job_fds[0] = job_fds[1] = -1;
if ((job_rfd = dup (job_fds[0])) < 0) free (jobserver_fds->list);
{ free (jobserver_fds);
if (errno != EBADF) jobserver_fds = 0;
pfatal_with_name (_("dup jobserver"));
error (NILF,
_("warning: jobserver unavailable (using -j1). Add `+' to parent make rule."));
job_slots = 1;
job_fds[0] = job_fds[1] = -1;
job_slots_str = "1";
}
} }
} }
/* In case #3 above, set up the pipe and set up the submake options /* If we have >1 slot but no jobserver-fds, then we're a top-level make.
properly. */ Set up the pipe and install the fds option for our children. */
if (job_slots > 1) else if (job_slots > 1)
{ {
char buf[(sizeof ("1024")*2)+1]; char c = '+';
char c = '0';
if (pipe (job_fds) < 0 || (job_rfd = dup (job_fds[0])) < 0) if (pipe (job_fds) < 0 || (job_rfd = dup (job_fds[0])) < 0)
pfatal_with_name (_("creating jobs pipe")); pfatal_with_name (_("creating jobs pipe"));
@ -1351,23 +1355,21 @@ int main (int argc, char ** argv)
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. */
job_slots = 1; /* !!!!!DEBUG!!!!! */
while (--job_slots) while (--job_slots)
{ while (write (job_fds[1], &c, 1) != 1)
write (job_fds[1], &c, 1); if (!EINTR_SET)
if (c == '9') pfatal_with_name (_("init jobserver pipe"));
c = 'a';
else if (c == 'z')
c = 'A';
else if (c == 'Z')
c = '0'; /* Start over again!! */
else
++c;
}
sprintf (buf, "%d,%d", job_fds[0], job_fds[1]); /* Fill in the jobserver_fds struct for our children. */
job_slots_str = xstrdup (buf);
jobserver_fds = (struct stringlist *)
xmalloc (sizeof (struct stringlist));
jobserver_fds->list = (char **) xmalloc (sizeof (char *));
jobserver_fds->list[0] = xmalloc ((sizeof ("1024")*2)+1);
sprintf (jobserver_fds->list[0], "%d,%d", job_fds[0], job_fds[1]);
jobserver_fds->idx = 1;
jobserver_fds->max = 1;
} }
#endif #endif
@ -1790,7 +1792,6 @@ init_switches ()
long_options[i].has_arg = no_argument; long_options[i].has_arg = no_argument;
break; break;
case int_string:
case string: case string:
case positive_int: case positive_int:
case floating: case floating:
@ -1904,7 +1905,7 @@ print_usage (bad)
{ {
char buf[1024], shortarg[50], longarg[50], *p; char buf[1024], shortarg[50], longarg[50], *p;
if (cs->description[0] == '-') if (!cs->description || cs->description[0] == '-')
continue; continue;
switch (long_options[cs - switches].has_arg) switch (long_options[cs - switches].has_arg)
@ -1949,8 +1950,9 @@ print_usage (bad)
{ {
const struct command_switch *ncs = cs; const struct command_switch *ncs = cs;
while ((++ncs)->c != '\0') while ((++ncs)->c != '\0')
if (ncs->description[0] == '-' && if (ncs->description
ncs->description[1] == cs->c) && ncs->description[0] == '-'
&& ncs->description[1] == cs->c)
{ {
/* This is another switch that does the same /* This is another switch that does the same
one as the one we are processing. We want one as the one we are processing. We want
@ -2044,20 +2046,6 @@ decode_switches (argc, argv, env)
*(int *) cs->value_ptr = cs->type == flag; *(int *) cs->value_ptr = cs->type == flag;
break; break;
case int_string:
if (optarg == 0 && argc > optind
&& isdigit (argv[optind][0]))
optarg = argv[optind++];
if (!doit)
break;
if (optarg == 0)
optarg = cs->noarg_value;
*(char **) cs->value_ptr = optarg;
break;
case string: case string:
if (!doit) if (!doit)
break; break;
@ -2356,22 +2344,6 @@ define_makeflags (all, makefile)
break; break;
#endif #endif
case int_string:
if (all)
{
char *vp = *(char **) cs->value_ptr;
if (cs->default_value != 0
&& streq (vp, cs->default_value))
break;
if (cs->noarg_value != 0
&& streq (vp, cs->noarg_value))
ADD_FLAG ("", 0); /* Optional value omitted; see below. */
else
ADD_FLAG (vp, strlen (vp));
}
break;
case string: case string:
if (all) if (all)
{ {