444 lines
14 KiB
Diff
444 lines
14 KiB
Diff
|
|
From 3112c8799358cb5d051e0b63d0e916357169942c Mon Sep 17 00:00:00 2001
|
||
|
|
From: Paul Smith <psmith@gnu.org>
|
||
|
|
Date: Sat, 4 Aug 2018 12:18:39 -0400
|
||
|
|
Subject: [PATCH 085/104] Queue failed fork() (etc.) to be handled like any
|
||
|
|
other failed job.
|
||
|
|
|
||
|
|
If we failed to fork() we were essentially exiting make immediately
|
||
|
|
without respect to ignore flags, etc. On one hand that makes sense
|
||
|
|
because if you can't fork you're in real trouble, but it doesn't
|
||
|
|
work so well on systems where we don't fork at all. Instead, treat
|
||
|
|
a fork error like any other error by delaying the handling until
|
||
|
|
the next call to reap_children(). Any child with a PID of -1 is
|
||
|
|
considered to have died before starting so check these first without
|
||
|
|
waiting for them.
|
||
|
|
|
||
|
|
* src/commands.c (fatal_error_signal): Don't kill children that
|
||
|
|
never started.
|
||
|
|
* src/function.c (func_shell_base): Handle cleanup properly if the
|
||
|
|
child doesn't start.
|
||
|
|
* src/job.c (reap_children): Check for children that died before
|
||
|
|
starting and handle them without waiting for the PID.
|
||
|
|
(start_job_command): Free memory when the child doesn't start.
|
||
|
|
(start_waiting_job): Don't manage children who never started.
|
||
|
|
(child_execute_job): If the fork fails return PID -1.
|
||
|
|
* src/vmsjobs.c: Check for children that never started.
|
||
|
|
* tests/run_make_tests.pl: Parse config.status to get all options.
|
||
|
|
---
|
||
|
|
commands.c | 6 +-
|
||
|
|
function.c | 28 +++++----
|
||
|
|
job.c | 123 ++++++++++++++++++----------------------
|
||
|
|
job.h | 8 ++-
|
||
|
|
vmsjobs.c | 3 +-
|
||
|
|
tests/run_make_tests.pl | 13 ++++-
|
||
|
|
6 files changed, 93 insertions(+), 88 deletions(-)
|
||
|
|
|
||
|
|
--- a/commands.c 2019-04-10 22:50:51.317814695 -0400
|
||
|
|
+++ b/commands.c 2019-04-10 23:13:38.411814695 -0400
|
||
|
|
@@ -538,7 +538,7 @@ fatal_error_signal (int sig)
|
||
|
|
{
|
||
|
|
struct child *c;
|
||
|
|
for (c = children; c != 0; c = c->next)
|
||
|
|
- if (!c->remote)
|
||
|
|
+ if (!c->remote && c->pid > 0)
|
||
|
|
(void) kill (c->pid, SIGTERM);
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -559,7 +559,7 @@ fatal_error_signal (int sig)
|
||
|
|
/* Remote children won't automatically get signals sent
|
||
|
|
to the process group, so we must send them. */
|
||
|
|
for (c = children; c != 0; c = c->next)
|
||
|
|
- if (c->remote)
|
||
|
|
+ if (c->remote && c->pid > 0)
|
||
|
|
(void) remote_kill (c->pid, sig);
|
||
|
|
|
||
|
|
for (c = children; c != 0; c = c->next)
|
||
|
|
@@ -660,7 +660,7 @@ delete_child_targets (struct child *chil
|
||
|
|
{
|
||
|
|
struct dep *d;
|
||
|
|
|
||
|
|
- if (child->deleted)
|
||
|
|
+ if (child->deleted || child->pid < 0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
/* Delete the target file if it changed. */
|
||
|
|
--- a/function.c 2019-04-10 22:50:51.293814695 -0400
|
||
|
|
+++ b/function.c 2019-04-10 23:19:59.282814695 -0400
|
||
|
|
@@ -1690,7 +1690,7 @@ func_shell_base (char *o, char **argv, i
|
||
|
|
#ifdef __MSDOS__
|
||
|
|
FILE *fpipe;
|
||
|
|
#endif
|
||
|
|
- char **command_argv;
|
||
|
|
+ char **command_argv = NULL;
|
||
|
|
const char *error_prefix;
|
||
|
|
char **envp;
|
||
|
|
int pipedes[2];
|
||
|
|
@@ -1753,7 +1753,8 @@ func_shell_base (char *o, char **argv, i
|
||
|
|
if (pipedes[0] < 0)
|
||
|
|
{
|
||
|
|
perror_with_name (error_prefix, "pipe");
|
||
|
|
- return o;
|
||
|
|
+ pid = -1;
|
||
|
|
+ goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
#elif defined(WINDOWS32)
|
||
|
|
@@ -1766,14 +1767,16 @@ func_shell_base (char *o, char **argv, i
|
||
|
|
/* Open of the pipe failed, mark as failed execution. */
|
||
|
|
shell_completed (127, 0);
|
||
|
|
perror_with_name (error_prefix, "pipe");
|
||
|
|
- return o;
|
||
|
|
+ pid = -1;
|
||
|
|
+ goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
#else
|
||
|
|
if (pipe (pipedes) < 0)
|
||
|
|
{
|
||
|
|
perror_with_name (error_prefix, "pipe");
|
||
|
|
- return o;
|
||
|
|
+ pid = -1;
|
||
|
|
+ goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Close handles that are unnecessary for the child process. */
|
||
|
|
@@ -1790,10 +1793,7 @@ func_shell_base (char *o, char **argv, i
|
||
|
|
}
|
||
|
|
|
||
|
|
if (pid < 0)
|
||
|
|
- {
|
||
|
|
- perror_with_name (error_prefix, "fork");
|
||
|
|
- return o;
|
||
|
|
- }
|
||
|
|
+ goto done;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
{
|
||
|
|
@@ -1806,10 +1806,6 @@ func_shell_base (char *o, char **argv, i
|
||
|
|
#ifndef __MSDOS__
|
||
|
|
shell_function_completed = 0;
|
||
|
|
|
||
|
|
- /* Free the storage only the child needed. */
|
||
|
|
- free (command_argv[0]);
|
||
|
|
- free (command_argv);
|
||
|
|
-
|
||
|
|
/* Close the write side of the pipe. We test for -1, since
|
||
|
|
pipedes[1] is -1 on MS-Windows, and some versions of MS
|
||
|
|
libraries barf when 'close' is called with -1. */
|
||
|
|
@@ -1884,6 +1880,14 @@ func_shell_base (char *o, char **argv, i
|
||
|
|
free (buffer);
|
||
|
|
}
|
||
|
|
|
||
|
|
+ done:
|
||
|
|
+ if (command_argv)
|
||
|
|
+ {
|
||
|
|
+ /* Free the storage only the child needed. */
|
||
|
|
+ free (command_argv[0]);
|
||
|
|
+ free (command_argv);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
return o;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
--- a/job.c 2019-04-10 22:50:51.306814695 -0400
|
||
|
|
+++ b/job.c 2019-04-10 23:44:37.378814695 -0400
|
||
|
|
@@ -622,10 +622,22 @@ reap_children (int block, int err)
|
||
|
|
|
||
|
|
any_remote = 0;
|
||
|
|
any_local = shell_function_pid != 0;
|
||
|
|
- for (c = children; c != 0; c = c->next)
|
||
|
|
+ lastc = 0;
|
||
|
|
+ for (c = children; c != 0; lastc = c, c = c->next)
|
||
|
|
{
|
||
|
|
any_remote |= c->remote;
|
||
|
|
any_local |= ! c->remote;
|
||
|
|
+
|
||
|
|
+ /* If pid < 0, this child never even started. Handle it. */
|
||
|
|
+ if (c->pid < 0)
|
||
|
|
+ {
|
||
|
|
+ exit_sig = 0;
|
||
|
|
+ coredump = 0;
|
||
|
|
+ /* According to POSIX, 127 is used for command not found. */
|
||
|
|
+ exit_code = 127;
|
||
|
|
+ goto process_child;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
DB (DB_JOBS, (_("Live child %p (%s) PID %s %s\n"),
|
||
|
|
c, c->file->name, pid2str (c->pid),
|
||
|
|
c->remote ? _(" (remote)") : ""));
|
||
|
|
@@ -691,9 +703,6 @@ reap_children (int block, int err)
|
||
|
|
exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0;
|
||
|
|
coredump = WCOREDUMP (status);
|
||
|
|
|
||
|
|
- /* If we have started jobs in this second, remove one. */
|
||
|
|
- if (job_counter)
|
||
|
|
- --job_counter;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
@@ -818,6 +827,16 @@ reap_children (int block, int err)
|
||
|
|
Ignore it; it was inherited from our invoker. */
|
||
|
|
continue;
|
||
|
|
|
||
|
|
+ DB (DB_JOBS, (exit_sig == 0 && exit_code == 0
|
||
|
|
+ ? _("Reaping losing child %p PID %s %s\n")
|
||
|
|
+ : _("Reaping winning child %p PID %s %s\n"),
|
||
|
|
+ c, pid2str (c->pid), c->remote ? _(" (remote)") : ""));
|
||
|
|
+
|
||
|
|
+ /* If we have started jobs in this second, remove one. */
|
||
|
|
+ if (job_counter)
|
||
|
|
+ --job_counter;
|
||
|
|
+
|
||
|
|
+ process_child:
|
||
|
|
/* Determine the failure status: 0 for success, 1 for updating target in
|
||
|
|
question mode, 2 for anything else. */
|
||
|
|
if (exit_sig == 0 && exit_code == 0)
|
||
|
|
@@ -827,11 +846,6 @@ reap_children (int block, int err)
|
||
|
|
else
|
||
|
|
child_failed = MAKE_FAILURE;
|
||
|
|
|
||
|
|
- DB (DB_JOBS, (child_failed
|
||
|
|
- ? _("Reaping losing child %p PID %s %s\n")
|
||
|
|
- : _("Reaping winning child %p PID %s %s\n"),
|
||
|
|
- c, pid2str (c->pid), c->remote ? _(" (remote)") : ""));
|
||
|
|
-
|
||
|
|
if (c->sh_batch_file)
|
||
|
|
{
|
||
|
|
int rm_status;
|
||
|
|
@@ -939,7 +953,7 @@ reap_children (int block, int err)
|
||
|
|
|
||
|
|
/* At this point c->file->update_status is success or failed. But
|
||
|
|
c->file->command_state is still cs_running if all the commands
|
||
|
|
- ran; notice_finish_file looks for cs_running to tell it that
|
||
|
|
+ ran; notice_finished_file looks for cs_running to tell it that
|
||
|
|
it's interesting to check the file's modtime again now. */
|
||
|
|
|
||
|
|
if (! handling_fatal_signal)
|
||
|
|
@@ -948,9 +962,6 @@ reap_children (int block, int err)
|
||
|
|
update_status to its also_make files. */
|
||
|
|
notice_finished_file (c->file);
|
||
|
|
|
||
|
|
- DB (DB_JOBS, (_("Removing child %p PID %s%s from chain.\n"),
|
||
|
|
- c, pid2str (c->pid), c->remote ? _(" (remote)") : ""));
|
||
|
|
-
|
||
|
|
/* Block fatal signals while frobnicating the list, so that
|
||
|
|
children and job_slots_used are always consistent. Otherwise
|
||
|
|
a fatal signal arriving after the child is off the chain and
|
||
|
|
@@ -958,9 +969,15 @@ reap_children (int block, int err)
|
||
|
|
live and call reap_children again. */
|
||
|
|
block_sigs ();
|
||
|
|
|
||
|
|
- /* There is now another slot open. */
|
||
|
|
- if (job_slots_used > 0)
|
||
|
|
- --job_slots_used;
|
||
|
|
+ if (c->pid > 0)
|
||
|
|
+ {
|
||
|
|
+ DB (DB_JOBS, (_("Removing child %p PID %s%s from chain.\n"),
|
||
|
|
+ c, pid2str (c->pid), c->remote ? _(" (remote)") : ""));
|
||
|
|
+
|
||
|
|
+ /* There is now another slot open. */
|
||
|
|
+ if (job_slots_used > 0)
|
||
|
|
+ --job_slots_used;
|
||
|
|
+ }
|
||
|
|
|
||
|
|
/* Remove the child from the chain and free it. */
|
||
|
|
if (lastc == 0)
|
||
|
|
@@ -1071,8 +1088,10 @@ start_job_command (struct child *child)
|
||
|
|
int flags;
|
||
|
|
char *p;
|
||
|
|
#ifdef VMS
|
||
|
|
+# define FREE_ARGV(_a)
|
||
|
|
char *argv;
|
||
|
|
#else
|
||
|
|
+# define FREE_ARGV(_a) do{ if (_a) { free ((_a)[0]); free (_a); } }while(0)
|
||
|
|
char **argv;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
@@ -1190,10 +1209,7 @@ start_job_command (struct child *child)
|
||
|
|
error is 2. */
|
||
|
|
if (argv != 0 && question_flag && !(flags & COMMANDS_RECURSE))
|
||
|
|
{
|
||
|
|
-#ifndef VMS
|
||
|
|
- free (argv[0]);
|
||
|
|
- free (argv);
|
||
|
|
-#endif
|
||
|
|
+ FREE_ARGV (argv);
|
||
|
|
#ifdef VMS
|
||
|
|
/* On VMS, argv[0] can be a null string here */
|
||
|
|
if (argv[0] != 0)
|
||
|
|
@@ -1211,13 +1227,7 @@ start_job_command (struct child *child)
|
||
|
|
{
|
||
|
|
/* Go on to the next command. It might be the recursive one.
|
||
|
|
We construct ARGV only to find the end of the command line. */
|
||
|
|
-#ifndef VMS
|
||
|
|
- if (argv)
|
||
|
|
- {
|
||
|
|
- free (argv[0]);
|
||
|
|
- free (argv);
|
||
|
|
- }
|
||
|
|
-#endif
|
||
|
|
+ FREE_ARGV (argv);
|
||
|
|
argv = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -1293,8 +1303,7 @@ start_job_command (struct child *child)
|
||
|
|
&& (argv[2] && argv[2][0] == ':' && argv[2][1] == '\0')
|
||
|
|
&& argv[3] == NULL)
|
||
|
|
{
|
||
|
|
- free (argv[0]);
|
||
|
|
- free (argv);
|
||
|
|
+ FREE_ARGV (argv);
|
||
|
|
goto next_command;
|
||
|
|
}
|
||
|
|
#endif /* !VMS && !_AMIGA */
|
||
|
|
@@ -1303,10 +1312,7 @@ start_job_command (struct child *child)
|
||
|
|
|
||
|
|
if (just_print_flag && !(flags & COMMANDS_RECURSE))
|
||
|
|
{
|
||
|
|
-#ifndef VMS
|
||
|
|
- free (argv[0]);
|
||
|
|
- free (argv);
|
||
|
|
-#endif
|
||
|
|
+ FREE_ARGV (argv);
|
||
|
|
goto next_command;
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -1373,11 +1379,7 @@ start_job_command (struct child *child)
|
||
|
|
|
||
|
|
#ifdef VMS
|
||
|
|
if (!child_execute_job (child, argv))
|
||
|
|
- {
|
||
|
|
- /* Fork failed! */
|
||
|
|
- perror_with_name ("fork", "");
|
||
|
|
- goto error;
|
||
|
|
- }
|
||
|
|
+ child->pid = -1;
|
||
|
|
|
||
|
|
#else
|
||
|
|
|
||
|
|
@@ -1385,18 +1387,11 @@ start_job_command (struct child *child)
|
||
|
|
|
||
|
|
jobserver_pre_child (flags & COMMANDS_RECURSE);
|
||
|
|
|
||
|
|
- child->pid = child_execute_job (&child->output, child->good_stdin, argv, child->environment);
|
||
|
|
+ child->pid = child_execute_job (&child->output, child->good_stdin,
|
||
|
|
+ argv, child->environment);
|
||
|
|
|
||
|
|
environ = parent_environ; /* Restore value child may have clobbered. */
|
||
|
|
jobserver_post_child (flags & COMMANDS_RECURSE);
|
||
|
|
-
|
||
|
|
- if (child->pid < 0)
|
||
|
|
- {
|
||
|
|
- /* Fork failed! */
|
||
|
|
- unblock_sigs ();
|
||
|
|
- perror_with_name ("fork", "");
|
||
|
|
- goto error;
|
||
|
|
- }
|
||
|
|
#endif /* !VMS */
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -1511,33 +1506,25 @@ start_job_command (struct child *child)
|
||
|
|
for (i = 0; argv[i]; i++)
|
||
|
|
fprintf (stderr, "%s ", argv[i]);
|
||
|
|
fprintf (stderr, _("\nCounted %d args in failed launch\n"), i);
|
||
|
|
- goto error;
|
||
|
|
+ child->pid = -1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif /* WINDOWS32 */
|
||
|
|
#endif /* __MSDOS__ or Amiga or WINDOWS32 */
|
||
|
|
|
||
|
|
/* Bump the number of jobs started in this second. */
|
||
|
|
- ++job_counter;
|
||
|
|
-
|
||
|
|
- /* We are the parent side. Set the state to
|
||
|
|
- say the commands are running and return. */
|
||
|
|
+ if (child->pid >= 0)
|
||
|
|
+ ++job_counter;
|
||
|
|
|
||
|
|
+ /* Set the state to running. */
|
||
|
|
set_command_state (child->file, cs_running);
|
||
|
|
|
||
|
|
/* Free the storage used by the child's argument list. */
|
||
|
|
-#ifndef VMS
|
||
|
|
- free (argv[0]);
|
||
|
|
- free (argv);
|
||
|
|
-#endif
|
||
|
|
+ FREE_ARGV (argv);
|
||
|
|
|
||
|
|
OUTPUT_UNSET();
|
||
|
|
- return;
|
||
|
|
|
||
|
|
- error:
|
||
|
|
- child->file->update_status = us_failed;
|
||
|
|
- notice_finished_file (child->file);
|
||
|
|
- OUTPUT_UNSET();
|
||
|
|
+#undef FREE_ARGV
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Try to start a child running.
|
||
|
|
@@ -1579,12 +1566,15 @@ start_waiting_job (struct child *c)
|
||
|
|
{
|
||
|
|
case cs_running:
|
||
|
|
c->next = children;
|
||
|
|
- DB (DB_JOBS, (_("Putting child %p (%s) PID %s%s on the chain.\n"),
|
||
|
|
- c, c->file->name, pid2str (c->pid),
|
||
|
|
- c->remote ? _(" (remote)") : ""));
|
||
|
|
+ if (c->pid > 0)
|
||
|
|
+ {
|
||
|
|
+ DB (DB_JOBS, (_("Putting child %p (%s) PID %s%s on the chain.\n"),
|
||
|
|
+ c, c->file->name, pid2str (c->pid),
|
||
|
|
+ c->remote ? _(" (remote)") : ""));
|
||
|
|
+ /* One more job slot is in use. */
|
||
|
|
+ ++job_slots_used;
|
||
|
|
+ }
|
||
|
|
children = c;
|
||
|
|
- /* One more job slot is in use. */
|
||
|
|
- ++job_slots_used;
|
||
|
|
unblock_sigs ();
|
||
|
|
break;
|
||
|
|
|
||
|
|
--- a/job.h 2019-04-10 22:50:51.319814695 -0400
|
||
|
|
+++ b/job.h 2019-04-10 23:46:53.284814695 -0400
|
||
|
|
@@ -95,6 +95,8 @@ struct child
|
||
|
|
char **command_lines; /* Array of variable-expanded cmd lines. */
|
||
|
|
char *command_ptr; /* Ptr into command_lines[command_line]. */
|
||
|
|
|
||
|
|
+ struct output output; /* Output for this child. */
|
||
|
|
+
|
||
|
|
#ifdef VMS
|
||
|
|
char *comname; /* Temporary command file name */
|
||
|
|
int efn; /* Completion event flag number */
|
||
|
|
@@ -103,7 +105,7 @@ struct child
|
||
|
|
#endif
|
||
|
|
|
||
|
|
unsigned int command_line; /* Index into command_lines. */
|
||
|
|
- struct output output; /* Output for this child. */
|
||
|
|
+
|
||
|
|
pid_t pid; /* Child process's ID number. */
|
||
|
|
unsigned int remote:1; /* Nonzero if executing remotely. */
|
||
|
|
unsigned int noerror:1; /* Nonzero if commands contained a '-'. */
|
||
|
|
@@ -131,7 +133,8 @@ int child_execute_job (struct child *chi
|
||
|
|
# define FD_STDIN (fileno (stdin))
|
||
|
|
# define FD_STDOUT (fileno (stdout))
|
||
|
|
# define FD_STDERR (fileno (stderr))
|
||
|
|
-pid_t child_execute_job (struct output *out, int good_stdin, char **argv, char **envp);
|
||
|
|
+pid_t child_execute_job (struct output *out, int good_stdin,
|
||
|
|
+ char **argv, char **envp);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifdef _AMIGA
|
||
|
|
--- a/vmsjobs.c 2019-04-10 22:50:51.318814695 -0400
|
||
|
|
+++ b/vmsjobs.c 2019-04-10 23:47:44.179814695 -0400
|
||
|
|
@@ -191,7 +191,8 @@ astYHandler (void)
|
||
|
|
{
|
||
|
|
struct child *c;
|
||
|
|
for (c = children; c != 0; c = c->next)
|
||
|
|
- sys$delprc (&c->pid, 0, 0);
|
||
|
|
+ if (c->pid > 0)
|
||
|
|
+ sys$delprc (&c->pid, 0, 0);
|
||
|
|
ctrlYPressed= 1;
|
||
|
|
kill (getpid(),SIGQUIT);
|
||
|
|
return SS$_NORMAL;
|