aboutsummaryrefslogtreecommitdiffstats
path: root/jobs.c
diff options
context:
space:
mode:
authorJari Aalto <jari.aalto@cante.net>2002-07-17 14:10:11 +0000
committerJari Aalto <jari.aalto@cante.net>2009-09-12 16:46:55 +0000
commit7117c2d221b2aed4ede8600f6a36b7c1454b4f55 (patch)
treeb792f26ecca68813c51ed5ba2e381790758ef31b /jobs.c
parentf73dda092b33638d2d5e9c35375f687a607b5403 (diff)
downloadandroid_external_bash-7117c2d221b2aed4ede8600f6a36b7c1454b4f55.tar.gz
android_external_bash-7117c2d221b2aed4ede8600f6a36b7c1454b4f55.tar.bz2
android_external_bash-7117c2d221b2aed4ede8600f6a36b7c1454b4f55.zip
Imported from ../bash-2.05b.tar.gz.
Diffstat (limited to 'jobs.c')
-rw-r--r--jobs.c439
1 files changed, 281 insertions, 158 deletions
diff --git a/jobs.c b/jobs.c
index d50db68..2bcb3ac 100644
--- a/jobs.c
+++ b/jobs.c
@@ -83,9 +83,8 @@
extern int errno;
#endif /* !errno */
-#if !defined (CHILD_MAX)
-# define CHILD_MAX 32
-#endif
+#define DEFAULT_CHILD_MAX 32
+#define MAX_JOBS_IN_ARRAY 4096 /* testing */
/* Take care of system dependencies that must be handled when waiting for
children. The arguments to the WAITPID macro match those to the Posix.1
@@ -141,7 +140,7 @@ extern void rl_set_screen_size __P((int, int));
#endif
/* Variables used here but defined in other files. */
-extern int startup_state, subshell_environment, line_number;
+extern int subshell_environment, line_number;
extern int posixly_correct, shell_level;
extern int interrupt_immediately, last_command_exit_value;
extern int loop_level, breaking;
@@ -150,13 +149,9 @@ extern sh_builtin_func_t *this_shell_builtin;
extern char *shell_name, *this_command_name;
extern sigset_t top_level_mask;
extern procenv_t wait_intr_buf;
+extern int wait_signal_received;
extern WORD_LIST *subst_assign_varlist;
-#if defined (ARRAY_VARS)
-static int *pstatuses; /* list of pipeline statuses */
-static int statsize;
-#endif
-
/* The array of known jobs. */
JOB **jobs = (JOB **)NULL;
@@ -224,21 +219,20 @@ static sighandler sigstop_sighandler __P((int));
static int waitchld __P((pid_t, int));
-static PROCESS *find_pipeline __P((pid_t));
+static PROCESS *find_pipeline __P((pid_t, int, int *));
static char *current_working_directory __P((void));
static char *job_working_directory __P((void));
static char *printable_job_status __P((int, PROCESS *, int));
-static pid_t find_last_pid __P((int));
-static pid_t last_pid __P((int));
+static pid_t find_last_pid __P((int, int));
static int set_new_line_discipline __P((int));
static int map_over_jobs __P((sh_job_map_func_t *, int, int));
static int job_last_stopped __P((int));
static int job_last_running __P((int));
static int most_recent_job_in_state __P((int, JOB_STATE));
-static int find_job __P((pid_t));
+static int find_job __P((pid_t, int));
static int print_job __P((JOB *, int, int, int));
static int process_exit_status __P((WAIT));
static int job_exit_status __P((int));
@@ -248,6 +242,7 @@ static WAIT raw_job_exit_status __P((int));
static void notify_of_job_status __P((void));
static void cleanup_dead_jobs __P((void));
+static int compact_jobs_list __P((int));
static void discard_pipeline __P((PROCESS *));
static void add_process __P((char *, pid_t));
static void print_pipeline __P((PROCESS *, int, int, FILE *));
@@ -264,9 +259,31 @@ static void pipe_read __P((int *));
static void pipe_close __P((int *));
#endif
-/* Used to synchronize between wait_for and the SIGCHLD signal handler. */
+#if defined (ARRAY_VARS)
+static int *pstatuses; /* list of pipeline statuses */
+static int statsize;
+#endif
+
+/* Used to synchronize between wait_for and other functions and the SIGCHLD
+ signal handler. */
static int sigchld;
-static int waiting_for_job;
+static int queue_sigchld;
+
+#define QUEUE_SIGCHLD(os) (os) = sigchld, queue_sigchld++
+
+#define UNQUEUE_SIGCHLD(os) \
+ do { \
+ queue_sigchld--; \
+ if (queue_sigchld == 0 && os != sigchld) \
+ waitchld (-1, 0); \
+ } while (0)
+
+static SigHandler *old_tstp, *old_ttou, *old_ttin;
+static SigHandler *old_cont = (SigHandler *)SIG_DFL;
+
+#if defined (TIOCGWINSZ) && defined (SIGWINCH)
+static SigHandler *old_winch = (SigHandler *)SIG_DFL;
+#endif
/* A place to temporarily save the current pipeline. */
static PROCESS *saved_pipeline;
@@ -280,6 +297,8 @@ static int jobs_list_frozen;
static char retcode_name_buffer[64];
+static long child_max = -1L;
+
#if !defined (_POSIX_VERSION)
/* These are definitions to map POSIX 1003.1 functions onto existing BSD
@@ -466,6 +485,12 @@ stop_pipeline (async, deferred)
}
/* Do we need more room? */
+
+ /* First try compaction */
+ if (subshell_environment && interactive_shell && i == job_slots && job_slots >= MAX_JOBS_IN_ARRAY)
+ i = compact_jobs_list (0);
+
+ /* If we can't compact, reallocate */
if (i == job_slots)
{
job_slots += JOB_SLOTS;
@@ -561,18 +586,86 @@ static void
cleanup_dead_jobs ()
{
register int i;
- sigset_t set, oset;
+ int os;
if (job_slots == 0 || jobs_list_frozen)
return;
- BLOCK_CHILD (set, oset);
+ QUEUE_SIGCHLD(os);
for (i = 0; i < job_slots; i++)
if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i))
delete_job (i, 0);
+ UNQUEUE_SIGCHLD(os);
+}
+
+/* Compact the jobs list by removing dead jobs. Assumed that we have filled
+ the jobs array to some predefined maximum. Called when the shell is not
+ the foreground process (subshell_environment != 0). Returns the first
+ available slot in the compacted list. If that value is job_slots, then
+ the list needs to be reallocated. The jobs array is in new memory if
+ this returns > 0 and < job_slots. FLAGS is reserved for future use. */
+static int
+compact_jobs_list (flags)
+ int flags;
+{
+ sigset_t set, oset;
+ register int i, j;
+ int nremove, ndel;
+ JOB **newlist;
+
+ if (job_slots == 0 || jobs_list_frozen)
+ return job_slots;
+
+ if (child_max < 0)
+ child_max = getmaxchild ();
+
+ /* Take out at most a quarter of the jobs in the jobs array, but leave at
+ least child_max */
+ nremove = job_slots >> 2;
+ if ((job_slots - nremove) < child_max)
+ nremove = job_slots - child_max;
+
+ /* need to increase jobs list to at least CHILD_MAX entries */
+ if (nremove < 0)
+ return job_slots;
+
+ BLOCK_CHILD (set, oset);
+
+ for (ndel = i = 0; i < job_slots; i++)
+ if (jobs[i])
+ {
+ if (DEADJOB (i) && (find_last_pid (i, 0) != last_asynchronous_pid))
+ {
+ delete_job (i, 0);
+ ndel++;
+ if (ndel == nremove)
+ break;
+ }
+ }
+
+ if (ndel == 0)
+ {
+ UNBLOCK_CHILD (oset);
+ return job_slots;
+ }
+
+ newlist = (JOB **)xmalloc ((1 + job_slots) * sizeof (JOB *));
+ for (i = j = 0; i < job_slots; i++)
+ if (jobs[i])
+ newlist[j++] = jobs[i];
+
+ ndel = j;
+ for ( ; j < job_slots; j++)
+ newlist[j] = (JOB *)NULL;
+
+ free (jobs);
+ jobs = newlist;
+
UNBLOCK_CHILD (oset);
+
+ return ndel;
}
/* Delete the job at INDEX from the job list. Must be called
@@ -650,7 +743,7 @@ add_process (name, pid)
t->next = the_pipeline;
t->pid = pid;
WSTATUS (t->status) = 0;
- t->running = 1;
+ t->running = PS_RUNNING;
t->command = name;
the_pipeline = t;
@@ -792,13 +885,17 @@ kill_current_pipeline ()
/* Return the pipeline that PID belongs to. Note that the pipeline
doesn't have to belong to a job. Must be called with SIGCHLD blocked. */
static PROCESS *
-find_pipeline (pid)
+find_pipeline (pid, running_only, jobp)
pid_t pid;
+ int running_only;
+ int *jobp; /* index into jobs list or NO_JOB */
{
int job;
register PROCESS *p;
/* See if this process is in the pipeline that we are building. */
+ if (jobp)
+ *jobp = NO_JOB;
if (the_pipeline)
{
p = the_pipeline;
@@ -806,23 +903,28 @@ find_pipeline (pid)
{
/* Return it if we found it. */
if (p->pid == pid)
- return (p);
+ {
+ if ((running_only && PRUNNING(p)) || (running_only == 0))
+ return (p);
+ }
p = p->next;
}
while (p != the_pipeline);
}
- job = find_job (pid);
-
+ job = find_job (pid, running_only);
+ if (jobp)
+ *jobp = job;
return (job == NO_JOB) ? (PROCESS *)NULL : jobs[job]->pipe;
}
/* Return the job index that PID belongs to, or NO_JOB if it doesn't
belong to any job. Must be called with SIGCHLD blocked. */
static int
-find_job (pid)
+find_job (pid, running_only)
pid_t pid;
+ int running_only;
{
register int i;
register PROCESS *p;
@@ -836,7 +938,10 @@ find_job (pid)
do
{
if (p->pid == pid)
- return (i);
+ {
+ if ((running_only && PRUNNING(p)) || (running_only == 0))
+ return (i);
+ }
p = p->next;
}
@@ -859,7 +964,9 @@ get_job_by_pid (pid, block)
if (block)
BLOCK_CHILD (set, oset);
- job = find_job (pid);
+
+ job = find_job (pid, 0);
+
if (block)
UNBLOCK_CHILD (oset);
@@ -876,7 +983,7 @@ describe_pid (pid)
BLOCK_CHILD (set, oset);
- job = find_job (pid);
+ job = find_job (pid, 0);
if (job != NO_JOB)
printf ("[%d] %ld\n", job + 1, (long)pid);
@@ -1056,31 +1163,26 @@ print_pipeline (p, job_index, format, stream)
fflush (stream);
}
+/* Print information to STREAM about jobs[JOB_INDEX] according to FORMAT.
+ Must be called with SIGCHLD blocked or queued with queue_sigchld */
static void
pretty_print_job (job_index, format, stream)
int job_index, format;
FILE *stream;
{
register PROCESS *p;
- sigset_t set, oset;
-
- BLOCK_CHILD (set, oset);
/* Format only pid information about the process group leader? */
if (format == JLIST_PID_ONLY)
{
fprintf (stream, "%ld\n", (long)jobs[job_index]->pipe->pid);
- UNBLOCK_CHILD (oset);
return;
}
if (format == JLIST_CHANGED_ONLY)
{
if (IS_NOTIFIED (job_index))
- {
- UNBLOCK_CHILD (oset);
- return;
- }
+ return;
format = JLIST_STANDARD;
}
@@ -1099,8 +1201,6 @@ pretty_print_job (job_index, format, stream)
/* We have printed information about this job. When the job's
status changes, waitchld () sets the notification flag to 0. */
jobs[job_index]->flags |= J_NOTIFIED;
-
- UNBLOCK_CHILD (oset);
}
static int
@@ -1118,7 +1218,7 @@ list_one_job (job, format, ignore, job_index)
JOB *job;
int format, ignore, job_index;
{
- print_job (job, format, -1, job_index);
+ pretty_print_job (job_index, format, stdout);
}
void
@@ -1317,6 +1417,7 @@ make_child (command, async_p)
return (pid);
}
+/* These two functions are called only in child processes. */
void
ignore_tty_job_signals ()
{
@@ -1465,38 +1566,32 @@ set_tty_state ()
/* Given an index into the jobs array JOB, return the pid of the last
process in that job's pipeline. This is the one whose exit status
- counts. */
+ counts. Must be called with SIGCHLD blocked or queued. */
static pid_t
-find_last_pid (job)
+find_last_pid (job, block)
int job;
+ int block;
{
register PROCESS *p;
+ sigset_t set, oset;
+
+ if (block)
+ BLOCK_CHILD (set, oset);
p = jobs[job]->pipe;
while (p->next != jobs[job]->pipe)
p = p->next;
- return (p->pid);
-}
-
-static pid_t
-last_pid (job)
- int job;
-{
- pid_t pid;
- sigset_t set, oset;
-
- BLOCK_CHILD (set, oset);
- pid = find_last_pid (job);
- UNBLOCK_CHILD (oset);
+ if (block)
+ UNBLOCK_CHILD (oset);
- return (pid);
+ return (p->pid);
}
/* Wait for a particular child of the shell to finish executing.
This low-level function prints an error message if PID is not
- a child of this shell. It returns -1 if it fails, or 0 if not
- (whatever wait_for returns). If the child is not found in the
+ a child of this shell. It returns -1 if it fails, or whatever
+ wait_for returns otherwise. If the child is not found in the
jobs table, it returns 127. */
int
wait_for_single_pid (pid)
@@ -1507,7 +1602,7 @@ wait_for_single_pid (pid)
int r, job;
BLOCK_CHILD (set, oset);
- child = find_pipeline (pid);
+ child = find_pipeline (pid, 0, (int *)NULL);
UNBLOCK_CHILD (oset);
if (child == 0)
@@ -1521,7 +1616,7 @@ wait_for_single_pid (pid)
/* POSIX.2: if we just waited for a job, we can remove it from the jobs
table. */
BLOCK_CHILD (set, oset);
- job = find_job (pid);
+ job = find_job (pid, 0);
if (job != NO_JOB && jobs[job] && DEADJOB (job))
jobs[job]->flags |= J_NOTIFIED;
UNBLOCK_CHILD (oset);
@@ -1533,7 +1628,7 @@ wait_for_single_pid (pid)
void
wait_for_background_pids ()
{
- register int i, count, r, waited_for;
+ register int i, r, waited_for;
sigset_t set, oset;
pid_t pid;
@@ -1541,37 +1636,31 @@ wait_for_background_pids ()
{
BLOCK_CHILD (set, oset);
- count = 0;
+ /* find first running job; if none running in foreground, break */
for (i = 0; i < job_slots; i++)
if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0)
- {
- count++;
- break;
- }
+ break;
- if (count == 0)
+ if (i == job_slots)
{
UNBLOCK_CHILD (oset);
break;
}
- for (i = 0; i < job_slots; i++)
- if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0)
- {
- pid = last_pid (i);
- UNBLOCK_CHILD (oset);
- QUIT;
- errno = 0; /* XXX */
- r = wait_for_single_pid (pid);
- if (r == -1)
- {
- if (errno == ECHILD)
- mark_all_jobs_as_dead ();
- }
- else
- waited_for++;
- break;
- }
+ /* now wait for the last pid in that job. */
+ pid = find_last_pid (i, 0);
+ UNBLOCK_CHILD (oset);
+ QUIT;
+ errno = 0; /* XXX */
+ r = wait_for_single_pid (pid);
+ if (r == -1)
+ {
+ /* If we're mistaken about job state, compensate. */
+ if (errno == ECHILD)
+ mark_all_jobs_as_dead ();
+ }
+ else
+ waited_for++;
}
/* POSIX.2 says the shell can discard the statuses of all completed jobs if
@@ -1618,6 +1707,7 @@ wait_sigint_handler (sig)
{
interrupt_immediately = 0;
trap_handler (SIGINT); /* set pending_traps[SIGINT] */
+ wait_signal_received = SIGINT;
longjmp (wait_intr_buf, 1);
}
@@ -1671,7 +1761,7 @@ job_exit_status (job)
#define FIND_CHILD(pid, child) \
do \
{ \
- child = find_pipeline (pid); \
+ child = find_pipeline (pid, 0, (int *)NULL); \
if (child == 0) \
{ \
give_terminal_to (shell_pgrp, 0); \
@@ -1731,7 +1821,7 @@ wait_for (pid)
We check for JDEAD in case the job state has been set by waitchld
after receipt of a SIGCHLD. */
if (job == NO_JOB)
- job = find_job (pid);
+ job = find_job (pid, 0);
/* waitchld() takes care of setting the state of the job. If the job
has already exited before this is called, sigchld_handler will have
@@ -1757,13 +1847,13 @@ wait_for (pid)
act.sa_flags = 0;
sigaction (SIGCHLD, &act, &oact);
# endif
- waiting_for_job = 1;
+ queue_sigchld = 1;
r = waitchld (pid, 1);
# if defined (MUST_UNBLOCK_CHLD)
sigaction (SIGCHLD, &oact, (struct sigaction *)NULL);
sigprocmask (SIG_SETMASK, &chldset, (sigset_t *)NULL);
# endif
- waiting_for_job = 0;
+ queue_sigchld = 0;
if (r == -1 && errno == ECHILD && this_shell_builtin == wait_builtin)
{
termination_state = -1;
@@ -1776,8 +1866,8 @@ wait_for (pid)
if it exists, as JDEAD. */
if (r == -1 && errno == ECHILD)
{
- child->running = 0;
- child->status = 0; /* XXX */
+ child->running = PS_DONE;
+ child->status = 0; /* XXX -- can't find true status */
if (job != NO_JOB)
jobs[job]->state = JDEAD;
}
@@ -1886,6 +1976,11 @@ if (job == NO_JOB)
}
}
+ /* Moved here from set_job_status_and_cleanup, which is in the SIGCHLD
+ signal handler path */
+ if (DEADJOB (job) && IS_FOREGROUND (job) /*&& subshell_environment == 0*/)
+ setjstatus (job);
+
/* If this job is dead, notify the user of the status. If the shell
is interactive, this will display a message on the terminal. If
the shell is not interactive, make sure we turn on the notify bit
@@ -1918,9 +2013,9 @@ wait_for_job (job)
BLOCK_CHILD(set, oset);
if (JOBSTATE (job) == JSTOPPED)
internal_warning ("wait_for_job: job %d is stopped", job+1);
- UNBLOCK_CHILD(oset);
- pid = last_pid (job);
+ pid = find_last_pid (job, 0);
+ UNBLOCK_CHILD(oset);
r = wait_for (pid);
/* POSIX.2: we can remove the job from the jobs table if we just waited
@@ -1970,6 +2065,7 @@ most_recent_job_in_state (job, state)
sigset_t set, oset;
BLOCK_CHILD (set, oset);
+
for (result = NO_JOB, i = job - 1; i >= 0; i--)
{
if (jobs[i] && (JOBSTATE (i) == state))
@@ -1978,6 +2074,7 @@ most_recent_job_in_state (job, state)
break;
}
}
+
UNBLOCK_CHILD (oset);
return (result);
@@ -2110,7 +2207,7 @@ set_job_running (job)
do
{
if (WIFSTOPPED (p->status))
- p->running = 1;
+ p->running = PS_RUNNING; /* XXX - could be PS_STOPPED */
p = p->next;
}
while (p != jobs[job]->pipe);
@@ -2209,14 +2306,13 @@ start_job (job, foreground)
killpg (jobs[job]->pgrp, SIGCONT);
}
- UNBLOCK_CHILD (oset);
-
if (foreground)
{
pid_t pid;
int s;
- pid = last_pid (job);
+ pid = find_last_pid (job, 0);
+ UNBLOCK_CHILD (oset);
s = wait_for (pid);
shell_tty_info = save_stty;
set_tty_state ();
@@ -2224,7 +2320,6 @@ start_job (job, foreground)
}
else
{
- BLOCK_CHILD (set, oset);
reset_current ();
UNBLOCK_CHILD (oset);
return (0);
@@ -2248,8 +2343,7 @@ kill_pid (pid, sig, group)
if (group)
{
BLOCK_CHILD (set, oset);
- p = find_pipeline (pid);
- job = find_job (pid);
+ p = find_pipeline (pid, 0, &job);
if (job != NO_JOB)
{
@@ -2263,7 +2357,7 @@ kill_pid (pid, sig, group)
do
{
kill (p->pid, sig);
- if (p->running == 0 && (sig == SIGTERM || sig == SIGHUP))
+ if (p->running == PS_DONE && (sig == SIGTERM || sig == SIGHUP))
kill (p->pid, SIGCONT);
p = p->next;
}
@@ -2307,7 +2401,7 @@ sigchld_handler (sig)
REINSTALL_SIGCHLD_HANDLER;
sigchld++;
n = 0;
- if (waiting_for_job == 0)
+ if (queue_sigchld == 0)
n = waitchld (-1, 0);
errno = oerrno;
SIGRETURN (n);
@@ -2370,7 +2464,7 @@ waitchld (wpid, block)
children_exited++;
/* Locate our PROCESS for this pid. */
- child = find_pipeline (pid);
+ child = find_pipeline (pid, 1, &job); /* want running procs only */
/* It is not an error to have a child terminate that we did
not have a record of. This child could have been part of
@@ -2384,10 +2478,8 @@ waitchld (wpid, block)
/* Remember status, and whether or not the process is running. */
child->status = status;
- child->running = WIFCONTINUED(status) ? 1 : 0;
+ child->running = WIFCONTINUED(status) ? PS_RUNNING : PS_DONE;
- job = find_job (pid);
-
if (job == NO_JOB)
continue;
@@ -2453,7 +2545,7 @@ set_job_status_and_cleanup (job)
do
{
job_state |= child->running;
- if (child->running == 0 && (WIFSTOPPED (child->status)))
+ if (child->running == PS_DONE && (WIFSTOPPED (child->status)))
{
any_stopped = 1;
any_tstped |= interactive && job_control &&
@@ -2492,8 +2584,10 @@ set_job_status_and_cleanup (job)
{
jobs[job]->state = JDEAD;
+#if 0
if (IS_FOREGROUND (job))
setjstatus (job);
+#endif
/* If this job has a cleanup function associated with it, call it
with `cleanarg' as the single argument, then set the function
@@ -2523,12 +2617,14 @@ set_job_status_and_cleanup (job)
WIFSIGNALED (child->status) == 0 && IS_FOREGROUND (job) &&
signal_is_trapped (SIGINT))
{
+ int old_frozen;
wait_sigint_received = 0;
last_command_exit_value = process_exit_status (child->status);
+ old_frozen = jobs_list_frozen;
jobs_list_frozen = 1;
tstatus = maybe_call_trap_handler (SIGINT);
- jobs_list_frozen = 0;
+ jobs_list_frozen = old_frozen;
}
/* If the foreground job is killed by SIGINT when job control is not
@@ -2543,6 +2639,8 @@ set_job_status_and_cleanup (job)
else if (wait_sigint_received && (WTERMSIG (child->status) == SIGINT) &&
IS_FOREGROUND (job) && IS_JOBCONTROL (job) == 0)
{
+ int old_frozen;
+
wait_sigint_received = 0;
/* If SIGINT is trapped, set the exit status so that the trap
@@ -2555,9 +2653,10 @@ set_job_status_and_cleanup (job)
maybe_call_trap_handler() may cause dead jobs to be removed from
the job table because of a call to execute_command. We work
around this by setting JOBS_LIST_FROZEN. */
+ old_frozen = jobs_list_frozen;
jobs_list_frozen = 1;
tstatus = maybe_call_trap_handler (SIGINT);
- jobs_list_frozen = 0;
+ jobs_list_frozen = old_frozen;
if (tstatus == 0 && old_sigint_handler != INVALID_SIGNAL_HANDLER)
{
/* wait_sigint_handler () has already seen SIGINT and
@@ -2600,7 +2699,7 @@ setjstatus (j)
for (i = 1, p = jobs[j]->pipe; p->next != jobs[j]->pipe; p = p->next, i++)
;
i++;
- if (statsize <= i)
+ if (statsize < i)
{
pstatuses = (int *)xrealloc (pstatuses, i * sizeof (int));
statsize = i;
@@ -2615,7 +2714,7 @@ setjstatus (j)
while (p != jobs[j]->pipe);
pstatuses[i] = -1; /* sentinel */
- set_pipestatus_array (pstatuses);
+ set_pipestatus_array (pstatuses, i);
#endif
}
@@ -2675,11 +2774,16 @@ notify_of_job_status ()
if (jobs == 0 || job_slots == 0)
return;
- sigemptyset (&set);
- sigaddset (&set, SIGCHLD);
- sigaddset (&set, SIGTTOU);
- sigemptyset (&oset);
- sigprocmask (SIG_BLOCK, &set, &oset);
+ if (old_ttou != 0)
+ {
+ sigemptyset (&set);
+ sigaddset (&set, SIGCHLD);
+ sigaddset (&set, SIGTTOU);
+ sigemptyset (&oset);
+ sigprocmask (SIG_BLOCK, &set, &oset);
+ }
+ else
+ queue_sigchld++;
for (job = 0, dir = (char *)NULL; job < job_slots; job++)
{
@@ -2706,7 +2810,7 @@ notify_of_job_status ()
hang onto the job corresponding to the last asynchronous
pid until the user has been notified of its status or does
a `wait'. */
- if (DEADJOB (job) && (interactive_shell || (find_last_pid (job) != last_asynchronous_pid)))
+ if (DEADJOB (job) && (interactive_shell || (find_last_pid (job, 0) != last_asynchronous_pid)))
jobs[job]->flags |= J_NOTIFIED;
continue;
}
@@ -2776,7 +2880,10 @@ notify_of_job_status ()
}
}
}
- sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
+ if (old_ttou != 0)
+ sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
+ else
+ queue_sigchld--;
}
/* Initialize the job control mechanism, and set up the tty stuff. */
@@ -2821,11 +2928,11 @@ initialize_job_control (force)
{
if (shell_pgrp != terminal_pgrp)
{
- SigHandler *old_ttin;
+ SigHandler *ottin;
- old_ttin = set_signal_handler(SIGTTIN, SIG_DFL);
+ ottin = set_signal_handler(SIGTTIN, SIG_DFL);
kill (0, SIGTTIN);
- set_signal_handler (SIGTTIN, old_ttin);
+ set_signal_handler (SIGTTIN, ottin);
continue;
}
break;
@@ -2952,12 +3059,7 @@ set_new_line_discipline (tty)
#endif
}
-static SigHandler *old_tstp, *old_ttou, *old_ttin;
-static SigHandler *old_cont = (SigHandler *)SIG_DFL;
-
#if defined (TIOCGWINSZ) && defined (SIGWINCH)
-static SigHandler *old_winch = (SigHandler *)SIG_DFL;
-
static void
get_new_window_size (from_sig)
int from_sig;
@@ -3026,8 +3128,8 @@ initialize_job_signals ()
else if (job_control)
{
old_tstp = set_signal_handler (SIGTSTP, sigstop_sighandler);
- old_ttou = set_signal_handler (SIGTTOU, sigstop_sighandler);
old_ttin = set_signal_handler (SIGTTIN, sigstop_sighandler);
+ old_ttou = set_signal_handler (SIGTTOU, sigstop_sighandler);
}
/* Leave these things alone for non-interactive shells without job
control. */
@@ -3173,16 +3275,16 @@ mark_all_jobs_as_dead ()
register int i;
sigset_t set, oset;
- if (job_slots)
- {
- BLOCK_CHILD (set, oset);
+ if (job_slots == 0)
+ return;
- for (i = 0; i < job_slots; i++)
- if (jobs[i])
- jobs[i]->state = JDEAD;
+ BLOCK_CHILD (set, oset);
- UNBLOCK_CHILD (oset);
- }
+ for (i = 0; i < job_slots; i++)
+ if (jobs[i])
+ jobs[i]->state = JDEAD;
+
+ UNBLOCK_CHILD (oset);
}
/* Mark all dead jobs as notified, so delete_job () cleans them out
@@ -3196,41 +3298,62 @@ mark_dead_jobs_as_notified (force)
register int i, ndead;
sigset_t set, oset;
- if (job_slots)
- {
- BLOCK_CHILD (set, oset);
-
- /* Count the number of dead jobs */
- for (i = ndead = 0; force == 0 && i < job_slots; i++)
- {
- if (jobs[i] && DEADJOB (i))
- ndead++;
- }
+ if (job_slots == 0)
+ return;
- /* Don't do anything if the number of jobs is less than CHILD_MAX and
- we're not forcing a cleanup. */
- if (force == 0 && ndead <= CHILD_MAX)
- {
- UNBLOCK_CHILD (oset);
- return;
- }
+ BLOCK_CHILD (set, oset);
- /* Mark enough dead jobs as notified that we keep CHILD_MAX jobs in
- the list. This isn't exactly right yet; changes need to be made
- to stop_pipeline so we don't mark the newer jobs after we've
- created CHILD_MAX slots in the jobs array. */
+ /* If FORCE is non-zero, we don't have to keep CHILD_MAX statuses
+ around; just run through the array. */
+ if (force)
+ {
for (i = 0; i < job_slots; i++)
{
- if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i) != last_asynchronous_pid)))
- {
- jobs[i]->flags |= J_NOTIFIED;
- if (force == 0 && --ndead <= CHILD_MAX)
- break;
- }
+ if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid)))
+ jobs[i]->flags |= J_NOTIFIED;
}
+ UNBLOCK_CHILD (oset);
+ return;
+ }
+
+ /* Mark enough dead jobs as notified to keep CHILD_MAX jobs left in the
+ array not marked as notified. */
+
+ /* Count the number of dead jobs */
+ for (i = ndead = 0; i < job_slots; i++)
+ {
+ if (jobs[i] && DEADJOB (i))
+ ndead++;
+ }
+
+ if (child_max < 0)
+ child_max = getmaxchild ();
+ if (child_max < 0)
+ child_max = DEFAULT_CHILD_MAX;
+ /* Don't do anything if the number of dead jobs is less than CHILD_MAX and
+ we're not forcing a cleanup. */
+ if (ndead <= child_max)
+ {
UNBLOCK_CHILD (oset);
+ return;
}
+
+ /* Mark enough dead jobs as notified that we keep CHILD_MAX jobs in
+ the list. This isn't exactly right yet; changes need to be made
+ to stop_pipeline so we don't mark the newer jobs after we've
+ created CHILD_MAX slots in the jobs array. */
+ for (i = 0; i < job_slots; i++)
+ {
+ if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid)))
+ {
+ jobs[i]->flags |= J_NOTIFIED;
+ if (--ndead <= child_max)
+ break;
+ }
+ }
+
+ UNBLOCK_CHILD (oset);
}
/* Here to allow other parts of the shell (like the trap stuff) to