diff options
author | Jari Aalto <jari.aalto@cante.net> | 2002-07-17 14:10:11 +0000 |
---|---|---|
committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:55 +0000 |
commit | 7117c2d221b2aed4ede8600f6a36b7c1454b4f55 (patch) | |
tree | b792f26ecca68813c51ed5ba2e381790758ef31b /jobs.c | |
parent | f73dda092b33638d2d5e9c35375f687a607b5403 (diff) | |
download | android_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.c | 439 |
1 files changed, 281 insertions, 158 deletions
@@ -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 |