summaryrefslogtreecommitdiff
path: root/jobs.c
diff options
context:
space:
mode:
authorStephen Hemminger <stephen.hemminger@vyatta.com>2010-04-09 16:13:32 -0700
committerStephen Hemminger <stephen.hemminger@vyatta.com>2010-04-09 16:15:01 -0700
commit2d698b6e42d8dca191ac795ef5dba3bf62496eec (patch)
treeac5e0b67043c50f49160e9fe407435706cf30444 /jobs.c
parentf1250933e4a2ac09a3d0b25b3877068e12f44da5 (diff)
downloadvyatta-bash-2d698b6e42d8dca191ac795ef5dba3bf62496eec.tar.gz
vyatta-bash-2d698b6e42d8dca191ac795ef5dba3bf62496eec.zip
Integrate bash 3.2 version
This is merge of current Debian stable (Lenny) version of Bash with Vyatta changes.
Diffstat (limited to 'jobs.c')
-rw-r--r--jobs.c130
1 files changed, 102 insertions, 28 deletions
diff --git a/jobs.c b/jobs.c
index d30a427..5e4b1f6 100644
--- a/jobs.c
+++ b/jobs.c
@@ -3,7 +3,7 @@
/* This file works with both POSIX and BSD systems. It implements job
control. */
-/* Copyright (C) 1989-2005 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2006 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -77,7 +77,15 @@ extern int errno;
#endif /* !errno */
#define DEFAULT_CHILD_MAX 32
-#define MAX_JOBS_IN_ARRAY 4096 /* testing */
+#if !defined (DEBUG)
+#define MAX_JOBS_IN_ARRAY 4096 /* production */
+#else
+#define MAX_JOBS_IN_ARRAY 128 /* testing */
+#endif
+
+/* Flag values for second argument to delete_job */
+#define DEL_WARNSTOPPED 1 /* warn about deleting stopped jobs */
+#define DEL_NOBGPID 2 /* don't add pgrp leader to bgpids */
/* 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
@@ -134,10 +142,10 @@ typedef int sh_job_map_func_t __P((JOB *, int, int, int));
/* Variables used here but defined in other files. */
extern int subshell_environment, line_number;
extern int posixly_correct, shell_level;
-extern int interrupt_immediately;
extern int last_command_exit_value, last_command_exit_signal;
extern int loop_level, breaking;
extern int sourcelevel;
+extern int running_trap;
extern sh_builtin_func_t *this_shell_builtin;
extern char *shell_name, *this_command_name;
extern sigset_t top_level_mask;
@@ -307,6 +315,10 @@ static int jobs_list_frozen;
static char retcode_name_buffer[64];
+/* flags to detect pid wraparound */
+static pid_t first_pid = NO_PID;
+static int pid_wrap = -1;
+
#if !defined (_POSIX_VERSION)
/* These are definitions to map POSIX 1003.1 functions onto existing BSD
@@ -328,11 +340,13 @@ tcgetpgrp (fd)
#endif /* !_POSIX_VERSION */
-/* Initialize the global job stats structure. */
+/* Initialize the global job stats structure and other bookkeeping variables */
void
init_job_stats ()
{
js = zerojs;
+ first_pid = NO_PID;
+ pid_wrap = -1;
}
/* Return the working directory for the current process. Unlike
@@ -746,7 +760,7 @@ bgp_search (pid)
static void
bgp_prune ()
{
- struct pidstat *ps, *p;
+ struct pidstat *ps;
while (bgpids.npid > js.c_childmax)
{
@@ -808,12 +822,14 @@ cleanup_dead_jobs ()
QUEUE_SIGCHLD(os);
- /* XXX could use js.j_firstj here */
+ /* XXX could use js.j_firstj and js.j_lastj here */
for (i = 0; i < js.j_jobslots; i++)
{
#if defined (DEBUG)
if (i < js.j_firstj && jobs[i])
itrace("cleanup_dead_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+ if (i > js.j_lastj && jobs[i])
+ itrace("cleanup_dead_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
#endif
if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i))
@@ -840,6 +856,30 @@ processes_in_job (job)
return nproc;
}
+static void
+delete_old_job (pid)
+ pid_t pid;
+{
+ PROCESS *p;
+ int job;
+
+ job = find_job (pid, 0, &p);
+ if (job != NO_JOB)
+ {
+#ifdef DEBUG
+ itrace ("delete_old_job: found pid %d in job %d with state %d", pid, job, jobs[job]->state);
+#endif
+ if (JOBSTATE (job) == JDEAD)
+ delete_job (job, DEL_NOBGPID);
+ else
+ {
+ internal_warning (_("forked pid %d appears in running job %d"), pid, job);
+ if (p)
+ p->pid = 0;
+ }
+ }
+}
+
/* Reallocate and compress the jobs list. This returns with a jobs array
whose size is a multiple of JOB_SLOTS and can hold the current number of
jobs. Heuristics are used to minimize the number of new reallocs. */
@@ -911,7 +951,7 @@ realloc_jobs_list ()
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 js.j_jobslots, then
- the list needs to be reallocated. The jobs array is in new memory if
+ the list needs to be reallocated. The jobs array may be in new memory if
this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */
static int
compact_jobs_list (flags)
@@ -929,29 +969,33 @@ compact_jobs_list (flags)
/* Delete the job at INDEX from the job list. Must be called
with SIGCHLD blocked. */
void
-delete_job (job_index, warn_stopped)
- int job_index, warn_stopped;
+delete_job (job_index, dflags)
+ int job_index, dflags;
{
register JOB *temp;
PROCESS *proc;
- int ndel, status;
- pid_t pid;
+ int ndel;
if (js.j_jobslots == 0 || jobs_list_frozen)
return;
- if (warn_stopped && subshell_environment == 0 && STOPPED (job_index))
+ if ((dflags & DEL_WARNSTOPPED) && subshell_environment == 0 && STOPPED (job_index))
internal_warning (_("deleting stopped job %d with process group %ld"), job_index+1, (long)jobs[job_index]->pgrp);
temp = jobs[job_index];
+ if (temp == 0)
+ return;
if (job_index == js.j_current || job_index == js.j_previous)
reset_current ();
- proc = find_last_proc (job_index, 0);
- /* Could do this just for J_ASYNC jobs, but we save all. */
- bgp_add (proc->pid, process_exit_status (proc->status));
+ if ((dflags & DEL_NOBGPID) == 0)
+ {
+ proc = find_last_proc (job_index, 0);
+ /* Could do this just for J_ASYNC jobs, but we save all. */
+ if (proc)
+ bgp_add (proc->pid, process_exit_status (proc->status));
+ }
jobs[job_index] = (JOB *)NULL;
-
if (temp == js.j_lastmade)
js.j_lastmade = 0;
else if (temp == js.j_lastasync)
@@ -1129,6 +1173,8 @@ map_over_jobs (func, arg1, arg2)
#if defined (DEBUG)
if (i < js.j_firstj && jobs[i])
itrace("map_over_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+ if (i > js.j_lastj && jobs[i])
+ itrace("map_over_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
#endif
if (jobs[i])
{
@@ -1183,8 +1229,9 @@ hangup_all_jobs ()
{
if (jobs[i])
{
- if ((jobs[i]->flags & J_NOHUP) == 0)
- killpg (jobs[i]->pgrp, SIGHUP);
+ if (jobs[i]->flags & J_NOHUP)
+ continue;
+ killpg (jobs[i]->pgrp, SIGHUP);
if (STOPPED (i))
killpg (jobs[i]->pgrp, SIGCONT);
}
@@ -1261,12 +1308,14 @@ find_job (pid, alive_only, procp)
register int i;
PROCESS *p;
- /* XXX could use js.j_firstj here */
+ /* XXX could use js.j_firstj here, and should check js.j_lastj */
for (i = 0; i < js.j_jobslots; i++)
{
#if defined (DEBUG)
if (i < js.j_firstj && jobs[i])
itrace("find_job: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+ if (i > js.j_lastj && jobs[i])
+ itrace("find_job: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
#endif
if (jobs[i])
{
@@ -1735,6 +1784,13 @@ make_child (command, async_p)
/* In the parent. Remember the pid of the child just created
as the proper pgrp if this is the first child. */
+ if (first_pid == NO_PID)
+ first_pid = pid;
+ else if (pid_wrap == -1 && pid < first_pid)
+ pid_wrap = 0;
+ else if (pid_wrap == 0 && pid >= first_pid)
+ pid_wrap = 1;
+
if (job_control)
{
if (pipeline_pgrp == 0)
@@ -1768,6 +1824,9 @@ make_child (command, async_p)
last_asynchronous_pid = 1;
#endif
+ if (pid_wrap > 0)
+ delete_old_job (pid);
+
#if !defined (RECYCLES_PIDS)
/* Only check for saved status if we've saved more than CHILD_MAX
statuses, unless the system recycles pids. */
@@ -1952,7 +2011,7 @@ find_last_proc (job, block)
BLOCK_CHILD (set, oset);
p = jobs[job]->pipe;
- while (p->next != jobs[job]->pipe)
+ while (p && p->next != jobs[job]->pipe)
p = p->next;
if (block)
@@ -2036,12 +2095,14 @@ wait_for_background_pids ()
BLOCK_CHILD (set, oset);
/* find first running job; if none running in foreground, break */
- /* XXX could use js.j_firstj here */
+ /* XXX could use js.j_firstj and js.j_lastj here */
for (i = 0; i < js.j_jobslots; i++)
{
#if defined (DEBUG)
if (i < js.j_firstj && jobs[i])
itrace("wait_for_background_pids: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+ if (i > js.j_lastj && jobs[i])
+ itrace("wait_for_background_pids: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
#endif
if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0)
break;
@@ -2307,6 +2368,7 @@ wait_for (pid)
{
child->running = PS_DONE;
child->status = 0; /* XXX -- can't find true status */
+ js.c_living = 0; /* no living child processes */
if (job != NO_JOB)
{
jobs[job]->state = JDEAD;
@@ -2358,7 +2420,6 @@ wait_for (pid)
if (job == NO_JOB)
itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%ld)", (long)shell_pgrp);
#endif
-
give_terminal_to (shell_pgrp, 0);
}
@@ -2764,14 +2825,14 @@ start_job (job, foreground)
if (foreground)
{
pid_t pid;
- int s;
+ int st;
pid = find_last_pid (job, 0);
UNBLOCK_CHILD (oset);
- s = wait_for (pid);
+ st = wait_for (pid);
shell_tty_info = save_stty;
set_tty_state ();
- return (s);
+ return (st);
}
else
{
@@ -2907,6 +2968,7 @@ waitchld (wpid, block)
: 0;
if (sigchld || block == 0)
waitpid_flags |= WNOHANG;
+ CHECK_TERMSIG;
pid = WAITPID (-1, &status, waitpid_flags);
/* WCONTINUED may be rejected by waitpid as invalid even when defined */
@@ -2933,13 +2995,17 @@ waitchld (wpid, block)
/* If waitpid returns 0, there are running children. If it returns -1,
the only other error POSIX says it can return is EINTR. */
+ CHECK_TERMSIG;
if (pid <= 0)
continue; /* jumps right to the test */
/* children_exited is used to run traps on SIGCHLD. We don't want to
run the trap if a process is just being continued. */
if (WIFCONTINUED(status) == 0)
- children_exited++;
+ {
+ children_exited++;
+ js.c_living--;
+ }
/* Locate our PROCESS for this pid. */
child = find_process (pid, 1, &job); /* want living procs only */
@@ -3164,7 +3230,7 @@ set_job_status_and_cleanup (job)
temp_handler = trap_to_sighandler (SIGINT);
restore_sigint_handler ();
if (temp_handler == SIG_DFL)
- termination_unwind_protect (SIGINT);
+ termsig_handler (SIGINT);
else if (temp_handler != SIG_IGN)
(*temp_handler) (SIGINT);
}
@@ -3679,9 +3745,11 @@ delete_all_jobs (running_only)
#if defined (DEBUG)
if (i < js.j_firstj && jobs[i])
itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+ if (i > js.j_lastj && jobs[i])
+ itrace("delete_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
#endif
if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i))))
- delete_job (i, 1);
+ delete_job (i, DEL_WARNSTOPPED);
}
if (running_only == 0)
{
@@ -3733,6 +3801,8 @@ count_all_jobs ()
#if defined (DEBUG)
if (i < js.j_firstj && jobs[i])
itrace("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+ if (i > js.j_lastj && jobs[i])
+ itrace("count_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
#endif
if (jobs[i] && DEADJOB(i) == 0)
n++;
@@ -3806,6 +3876,8 @@ mark_dead_jobs_as_notified (force)
#if defined (DEBUG)
if (i < js.j_firstj && jobs[i])
itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+ if (i > js.j_lastj && jobs[i])
+ itrace("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
#endif
if (jobs[i] && DEADJOB (i))
{
@@ -3857,6 +3929,8 @@ itrace("mark_dead_jobs_as_notified: child_max = %d ndead = %d ndeadproc = %d", j
#if defined (DEBUG)
if (i < js.j_firstj && jobs[i])
itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+ if (i > js.j_lastj && jobs[i])
+ itrace("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
#endif
/* If marking this job as notified would drop us down below
child_max, don't mark it so we can keep at least child_max