Formerly job.c.~59~

This commit is contained in:
Roland McGrath 1992-04-21 07:59:32 +00:00
parent a80e32c0fe
commit 75448c19f4

285
job.c
View file

@ -176,152 +176,34 @@ child_error (target_name, exit_code, exit_sig, coredump, ignored)
}
}
extern void block_remote_children (), unblock_remote_children ();
extern int fatal_signal_mask;
#ifdef USG
/* Set nonzero in the interval when it's possible that we may see a dead
child that's not in the `children' chain. */
static int unknown_children_possible = 0;
#endif
/* Block the child termination signal and fatal signals. */
static void
block_signals ()
{
#ifdef USG
/* Tell child_handler that it might see children that aren't yet
in the `children' chain. */
unknown_children_possible = 1;
/* Ignoring SIGCLD makes wait always return -1.
Using the default action does the right thing. */
(void) SIGNAL (SIGCLD, SIG_DFL);
#else /* Not USG. */
/* Block the signals. */
(void) sigblock (fatal_signal_mask | sigmask (SIGCHLD));
#endif
block_remote_children ();
}
/* Unblock the child termination signal and fatal signals. */
static void
unblock_signals ()
{
#ifdef USG
(void) SIGNAL (SIGCLD, child_handler);
/* It should no longer be possible for children not in the chain to die. */
unknown_children_possible = 0;
#else /* Not USG. */
/* Unblock the signals. */
(void) sigsetmask (sigblock (0) & ~(fatal_signal_mask | sigmask (SIGCHLD)));
#endif
unblock_remote_children ();
}
static char *signals_blocked_p_stack = 0;
static unsigned int signals_blocked_p_max;
static unsigned int signals_blocked_p_depth;
/* Make signals blocked in FLAG is nonzero, unblocked if FLAG is zero.
Push this setting on the signals_blocked_p_stack, so it can be
popped off by pop_signals_blocked_p. */
void
push_signals_blocked_p (flag)
int flag;
{
int blocked;
if (signals_blocked_p_stack == 0)
{
signals_blocked_p_max = 8;
signals_blocked_p_stack = (char *) xmalloc (8);
signals_blocked_p_depth = 1;
signals_blocked_p_stack[0] = flag;
blocked = 0;
}
else
{
if (signals_blocked_p_depth == signals_blocked_p_max)
{
signals_blocked_p_max += 8;
signals_blocked_p_stack
= (char *) xrealloc(signals_blocked_p_stack,
signals_blocked_p_max);
}
blocked = (signals_blocked_p_depth > 0
&& signals_blocked_p_stack[signals_blocked_p_depth - 1]);
signals_blocked_p_stack[++signals_blocked_p_depth - 1] = flag;
}
if (blocked && !flag)
unblock_signals ();
else if (flag && !blocked)
block_signals ();
}
/* Pop the signals_blocked_p setting from the stack
and block or unblock signals as appropriate. */
void
pop_signals_blocked_p ()
{
int blocked, block;
blocked = (signals_blocked_p_depth > 0
&& signals_blocked_p_stack[signals_blocked_p_depth-- - 1]);
block = (signals_blocked_p_depth > 0
&& signals_blocked_p_stack[signals_blocked_p_depth - 1]);
if (block && !blocked)
block_signals ();
else if (blocked && !block)
unblock_signals ();
}
extern int shell_function_pid, shell_function_completed;
/* Handle a child-termination signal (SIGCHLD, or SIGCLD for USG),
storing the returned status and the new command state (`cs_finished')
in the `file' member of the `struct child' for the dead child,
and removing the child from the chain.
If we were called as a signal handler, SIG should be SIGCHLD
(SIGCLD for USG). If instead it is zero, we were called explicitly
and should block waiting for running children.
If SIG is < 0, - SIG is the maximum number of children to bury (record
status of and remove from the chain). */
int child_died = 0;
/* Notice that a child died.
reap_children should be called when convenient. */
int
child_handler (sig)
int sig;
{
child_died = 1;
return 0;
}
extern int shell_function_pid, shell_function_completed;
/* Reap dead children, storing the returned status and the new command
state (`cs_finished') in the `file' member of the `struct child' for the
dead child, and removing the child from the chain. If BLOCK nonzero,
reap at least one child, waiting for it to die if necessary. If ERR is
nonzero, print an error message first. */
void
reap_children (block, err)
int block, err;
{
WAIT_T status;
unsigned int dead_children = 0;
if (sig > 0)
block_signals ();
while (1)
while ((children != 0 || shell_function_pid != 0) &&
(block || child_died))
{
int remote = 0;
register int pid;
@ -329,6 +211,14 @@ child_handler (sig)
register struct child *lastc, *c;
int child_failed;
if (err && !child_died)
{
fflush (stdout);
error ("*** Waiting for unfinished jobs....");
}
child_died = 0;
/* First, check for remote children. */
pid = remote_status (&exit_code, &exit_sig, &coredump, 0);
if (pid < 0)
@ -336,18 +226,11 @@ child_handler (sig)
/* No remote children. Check for local children. */
#ifdef WAIT_NOHANG
if (sig > 0)
if (!block)
pid = WAIT_NOHANG (&status);
else
#endif
pid = wait (&status);
#else /* USG and don't HAVE_SYS_WAIT. */
/* System V cannot do non-blocking waits, so we have two
choices if called as a signal handler: handle only one
child (there may be more if the signal was blocked),
or block waiting for more. The latter option makes
parallelism useless, so we must choose the former. */
pid = wait (&status);
#endif /* HAVE_SYS_WAIT or not USG. */
if (pid <= 0)
/* No local children. */
@ -372,17 +255,7 @@ child_handler (sig)
shell_function_completed = -1;
else
shell_function_completed = 1;
/* Check if we have reached our quota of children. */
++dead_children;
if (sig < 0 && dead_children == -sig)
break;
#if defined(USG) && !defined(HAVE_SYS_WAIT)
else if (sig > 0)
break;
#endif
else
continue;
break;
}
child_failed = exit_sig != 0 || exit_code != 0;
@ -396,20 +269,13 @@ child_handler (sig)
if (c == 0)
{
/* An unknown child died. */
#ifdef USG
if (!unknown_children_possible)
{
#endif
char buf[100];
sprintf (buf, "Unknown%s job %d", remote ? " remote" : "", pid);
if (child_failed)
child_error (buf, exit_code, exit_sig, coredump,
ignore_errors_flag);
else
error ("%s finished.", buf);
#ifdef USG
}
#endif
char buf[100];
sprintf (buf, "Unknown%s job %d", remote ? " remote" : "", pid);
if (child_failed)
child_error (buf, exit_code, exit_sig, coredump,
ignore_errors_flag);
else
error ("%s finished.", buf);
}
else
{
@ -436,8 +302,9 @@ child_handler (sig)
child_failed = 0;
}
/* If there are more commands to run, try to start them. */
start_job (c);
if (!err)
/* If there are more commands to run, try to start them. */
start_job (c);
switch (c->file->command_state)
{
@ -454,14 +321,15 @@ child_handler (sig)
break;
default:
error ("internal error: `%s' command_state \
%d in child_handler", c->file->name);
error ("internal error: `%s' has bogus command_state \
%d in reap_children",
c->file->name, c->file->command_state);
abort ();
break;
}
}
/* Set the state flag to say the commands have finished. */
/* Notice if the target of the commands has been changed. */
notice_finished_file (c->file);
/* Remove the child from the chain and free it. */
@ -477,52 +345,11 @@ child_handler (sig)
/* If the job failed, and the -k flag was not given, die. */
if (child_failed && !keep_going_flag)
die (1);
/* See if we have reached our quota for blocking. */
++dead_children;
if (sig < 0 && dead_children == -sig)
break;
#if defined(USG) && !defined(HAVE_SYS_WAIT)
else if (sig > 0)
break;
#endif
}
/* Only block for one child. */
block = 0;
}
#ifdef USG
if (sig > 0)
(void) SIGNAL (sig, child_handler);
#endif
if (sig > 0)
unblock_signals ();
return 0;
}
/* Wait for N children, blocking if necessary.
If N is zero, wait until we run out of children.
If ERR is nonzero and we have any children to wait for,
print a message on stderr. */
void
wait_for_children (n, err)
unsigned int n;
int err;
{
push_signals_blocked_p (1);
if (err && (children != 0 || shell_function_pid != 0))
{
fflush (stdout);
error ("*** Waiting for unfinished jobs....");
}
/* Call child_handler to do the work. */
(void) child_handler (- (int) n);
pop_signals_blocked_p ();
}
/* Free the storage allocated for CHILD. */
@ -754,13 +581,16 @@ new_job (file)
char **lines;
register unsigned int i;
/* Reap any children that might have finished recently. */
reap_children (0, 0);
/* Chop the commands up into lines if they aren't already. */
chop_commands (cmds);
if (job_slots != 0)
/* Wait for a job slot to be freed up. */
while (job_slots_used == job_slots)
wait_for_children (1, 0);
reap_children (1, 0);
/* Expand the command lines and store the results in LINES. */
lines = (char **) xmalloc (cmds->ncommand_lines * sizeof (char *));
@ -771,8 +601,6 @@ new_job (file)
/* Start the command sequence, record it in a new
`struct child', and add that to the chain. */
push_signals_blocked_p (1);
c = (struct child *) xmalloc (sizeof (struct child));
c->file = file;
c->command_lines = lines;
@ -801,14 +629,12 @@ new_job (file)
break;
}
pop_signals_blocked_p ();
if (job_slots == 1 && file->command_state == cs_running)
{
/* Since there is only one job slot, make things run linearly.
Wait for the child to finish, setting the state to `cs_finished'. */
while (file->command_state != cs_finished)
wait_for_children (1, 0);
reap_children (1, 0);
}
}
@ -834,9 +660,6 @@ child_execute_job (stdin_fd, stdout_fd, argv, envp)
(void) close (d);
}
/* Don't block signals for the new process. */
unblock_signals ();
/* Run the command. */
exec_command (argv, envp);
}