mirror of
https://git.savannah.gnu.org/git/make.git
synced 2024-12-27 06:27:51 +00:00
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.
This commit is contained in:
parent
8bde7db16f
commit
3112c87993
6 changed files with 93 additions and 88 deletions
|
@ -539,7 +539,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);
|
||||
}
|
||||
|
||||
|
@ -560,7 +560,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)
|
||||
|
@ -661,7 +661,7 @@ delete_child_targets (struct child *child)
|
|||
{
|
||||
struct dep *d;
|
||||
|
||||
if (child->deleted)
|
||||
if (child->deleted || child->pid < 0)
|
||||
return;
|
||||
|
||||
/* Delete the target file if it changed. */
|
||||
|
|
|
@ -1698,7 +1698,7 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
|||
#ifdef __MSDOS__
|
||||
FILE *fpipe;
|
||||
#endif
|
||||
char **command_argv;
|
||||
char **command_argv = NULL;
|
||||
const char *error_prefix;
|
||||
char **envp;
|
||||
int pipedes[2];
|
||||
|
@ -1761,7 +1761,8 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
|||
if (pipedes[0] < 0)
|
||||
{
|
||||
perror_with_name (error_prefix, "pipe");
|
||||
return o;
|
||||
pid = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
#elif defined(WINDOWS32)
|
||||
|
@ -1774,14 +1775,16 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
|||
/* 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. */
|
||||
|
@ -1798,10 +1801,7 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
|||
}
|
||||
|
||||
if (pid < 0)
|
||||
{
|
||||
perror_with_name (error_prefix, "fork");
|
||||
return o;
|
||||
}
|
||||
goto done;
|
||||
#endif
|
||||
|
||||
{
|
||||
|
@ -1814,10 +1814,6 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
|||
#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. */
|
||||
|
@ -1892,6 +1888,14 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
|||
free (buffer);
|
||||
}
|
||||
|
||||
done:
|
||||
if (command_argv)
|
||||
{
|
||||
/* Free the storage only the child needed. */
|
||||
free (command_argv[0]);
|
||||
free (command_argv);
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
|
123
src/job.c
123
src/job.c
|
@ -684,10 +684,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)") : ""));
|
||||
|
@ -752,10 +764,6 @@ reap_children (int block, int err)
|
|||
exit_code = WEXITSTATUS (status);
|
||||
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
|
||||
{
|
||||
|
@ -883,6 +891,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)
|
||||
|
@ -892,11 +910,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;
|
||||
|
@ -1004,7 +1017,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)
|
||||
|
@ -1013,9 +1026,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
|
||||
|
@ -1023,9 +1033,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)
|
||||
|
@ -1110,8 +1126,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
|
||||
|
||||
|
@ -1229,10 +1247,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)
|
||||
|
@ -1250,13 +1265,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;
|
||||
}
|
||||
|
||||
|
@ -1332,8 +1341,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 */
|
||||
|
@ -1342,10 +1350,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;
|
||||
}
|
||||
|
||||
|
@ -1412,11 +1417,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
|
||||
|
||||
|
@ -1424,18 +1425,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 */
|
||||
}
|
||||
|
||||
|
@ -1550,33 +1544,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.
|
||||
|
@ -1618,12 +1604,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;
|
||||
|
||||
|
|
|
@ -25,10 +25,13 @@ struct child
|
|||
struct file *file; /* File being remade. */
|
||||
|
||||
char **environment; /* Environment for commands. */
|
||||
|
||||
char *sh_batch_file; /* Script file for shell commands */
|
||||
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 */
|
||||
|
@ -37,7 +40,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 '-'. */
|
||||
|
@ -62,7 +65,8 @@ char **construct_command_argv (char *line, char **restp, struct file *file,
|
|||
#ifdef VMS
|
||||
int child_execute_job (struct child *child, char *argv);
|
||||
#else
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -71,9 +71,16 @@ use FindBin;
|
|||
use lib "$FindBin::Bin";
|
||||
|
||||
require "test_driver.pl";
|
||||
if (! eval { require "config-flags.pm" }) {
|
||||
# Some target systems don't create config-flags.pm
|
||||
%CONFIG_FLAGS = ();
|
||||
|
||||
%CONFIG_FLAGS = ();
|
||||
|
||||
my $statnm = "$FindBin::Bin/../config.status";
|
||||
if (open(my $fh, '<', $statnm)) {
|
||||
while (my $line = <$fh>) {
|
||||
$line =~ m/^[SD]\["([^\"]+)"\]=" *(.*)"/ and $CONFIG_FLAGS{$1} = $2;
|
||||
}
|
||||
} else {
|
||||
warn "Failed to open $statnm: $!";
|
||||
}
|
||||
|
||||
# Some target systems might not have the POSIX module...
|
||||
|
|
Loading…
Reference in a new issue