Files
bash/jobs.c.diff
T
2011-12-07 09:05:27 -05:00

522 lines
15 KiB
Diff

*** ../bash-3.1/jobs.c Fri Nov 11 23:13:27 2005
--- jobs.c Wed Feb 1 13:55:38 2006
***************
*** 4,8 ****
control. */
! /* Copyright (C) 1989-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
--- 4,8 ----
control. */
! /* Copyright (C) 1989-2006 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
***************
*** 78,82 ****
#define DEFAULT_CHILD_MAX 32
! #define MAX_JOBS_IN_ARRAY 4096 /* testing */
/* Take care of system dependencies that must be handled when waiting for
--- 78,90 ----
#define DEFAULT_CHILD_MAX 32
! #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
***************
*** 308,311 ****
--- 316,323 ----
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)
***************
*** 329,337 ****
#endif /* !_POSIX_VERSION */
! /* Initialize the global job stats structure. */
void
init_job_stats ()
{
js = zerojs;
}
--- 341,351 ----
#endif /* !_POSIX_VERSION */
! /* Initialize the global job stats structure and other bookkeeping variables */
void
init_job_stats ()
{
js = zerojs;
+ first_pid = NO_PID;
+ pid_wrap = -1;
}
***************
*** 620,625 ****
* the parent gives it away.
*
*/
! if (job_control && newjob->pgrp)
give_terminal_to (newjob->pgrp, 0);
}
--- 634,642 ----
* the parent gives it away.
*
+ * Don't give the terminal away if this shell is an asynchronous
+ * subshell.
+ *
*/
! if (job_control && newjob->pgrp && (subshell_environment&SUBSHELL_ASYNC) == 0)
give_terminal_to (newjob->pgrp, 0);
}
***************
*** 806,810 ****
QUEUE_SIGCHLD(os);
! /* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
--- 823,827 ----
QUEUE_SIGCHLD(os);
! /* XXX could use js.j_firstj and js.j_lastj here */
for (i = 0; i < js.j_jobslots; i++)
{
***************
*** 812,815 ****
--- 829,834 ----
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
***************
*** 838,841 ****
--- 857,884 ----
}
+ 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
***************
*** 845,851 ****
{
sigset_t set, oset;
! int nsize, i, j;
JOB **nlist;
nsize = ((js.j_njobs + JOB_SLOTS - 1) / JOB_SLOTS);
nsize *= JOB_SLOTS;
--- 888,895 ----
{
sigset_t set, oset;
! int nsize, i, j, ncur, nprev;
JOB **nlist;
+ ncur = nprev = NO_JOB;
nsize = ((js.j_njobs + JOB_SLOTS - 1) / JOB_SLOTS);
nsize *= JOB_SLOTS;
***************
*** 855,869 ****
BLOCK_CHILD (set, oset);
! nlist = (JOB **) xmalloc (nsize * sizeof (JOB *));
for (i = j = 0; i < js.j_jobslots; i++)
if (jobs[i])
! nlist[j++] = jobs[i];
js.j_firstj = 0;
! js.j_lastj = (j > 0) ? j - 1: 0;
js.j_jobslots = nsize;
! free (jobs);
! jobs = nlist;
UNBLOCK_CHILD (oset);
--- 899,947 ----
BLOCK_CHILD (set, oset);
! nlist = (js.j_jobslots == nsize) ? jobs : (JOB **) xmalloc (nsize * sizeof (JOB *));
!
for (i = j = 0; i < js.j_jobslots; i++)
if (jobs[i])
! {
! if (i == js.j_current)
! ncur = j;
! if (i == js.j_previous)
! nprev = j;
! nlist[j++] = jobs[i];
! }
!
! #if defined (DEBUG)
! itrace ("realloc_jobs_list: resize jobs list from %d to %d", js.j_jobslots, nsize);
! itrace ("realloc_jobs_list: j_lastj changed from %d to %d", js.j_lastj, (j > 0) ? j - 1 : 0);
! itrace ("realloc_jobs_list: j_njobs changed from %d to %d", js.j_njobs, (j > 0) ? j - 1 : 0);
! #endif
js.j_firstj = 0;
! js.j_lastj = (j > 0) ? j - 1 : 0;
! js.j_njobs = j;
js.j_jobslots = nsize;
! /* Zero out remaining slots in new jobs list */
! for ( ; j < nsize; j++)
! nlist[j] = (JOB *)NULL;
!
! if (jobs != nlist)
! {
! free (jobs);
! jobs = nlist;
! }
!
! if (ncur != NO_JOB)
! js.j_current = ncur;
! if (nprev != NO_JOB)
! js.j_previous = nprev;
!
! /* Need to reset these */
! if (js.j_current == NO_JOB || js.j_previous == NO_JOB || js.j_current > js.j_lastj || js.j_previous > js.j_lastj)
! reset_current ();
!
! #ifdef DEBUG
! itrace ("realloc_jobs_list: reset js.j_current (%d) and js.j_previous (%d)", js.j_current, js.j_previous);
! #endif
UNBLOCK_CHILD (oset);
***************
*** 874,878 ****
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
this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */
static int
--- 952,956 ----
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 may be in new memory if
this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */
static int
***************
*** 892,897 ****
with SIGCHLD blocked. */
void
! delete_job (job_index, warn_stopped)
! int job_index, warn_stopped;
{
register JOB *temp;
--- 970,975 ----
with SIGCHLD blocked. */
void
! delete_job (job_index, dflags)
! int job_index, dflags;
{
register JOB *temp;
***************
*** 903,918 ****
return;
! if (warn_stopped && 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 (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));
jobs[job_index] = (JOB *)NULL;
-
if (temp == js.j_lastmade)
js.j_lastmade = 0;
--- 981,1001 ----
return;
! 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 ();
! 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;
***************
*** 1092,1095 ****
--- 1175,1180 ----
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])
***************
*** 1224,1228 ****
PROCESS *p;
! /* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
--- 1309,1313 ----
PROCESS *p;
! /* XXX could use js.j_firstj here, and should check js.j_lastj */
for (i = 0; i < js.j_jobslots; i++)
{
***************
*** 1230,1233 ****
--- 1315,1320 ----
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])
***************
*** 1656,1660 ****
shell's process group (we could be in the middle of a
pipeline, for example). */
! if (async_p == 0 && pipeline_pgrp != shell_pgrp)
give_terminal_to (pipeline_pgrp, 0);
--- 1743,1747 ----
shell's process group (we could be in the middle of a
pipeline, for example). */
! if (async_p == 0 && pipeline_pgrp != shell_pgrp && ((subshell_environment&SUBSHELL_ASYNC) == 0))
give_terminal_to (pipeline_pgrp, 0);
***************
*** 1698,1701 ****
--- 1785,1795 ----
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)
{
***************
*** 1731,1734 ****
--- 1825,1831 ----
#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
***************
*** 1915,1919 ****
p = jobs[job]->pipe;
! while (p->next != jobs[job]->pipe)
p = p->next;
--- 2012,2016 ----
p = jobs[job]->pipe;
! while (p && p->next != jobs[job]->pipe)
p = p->next;
***************
*** 1999,2003 ****
/* find first running job; if none running in foreground, break */
! /* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
--- 2096,2100 ----
/* find first running job; if none running in foreground, break */
! /* XXX could use js.j_firstj and js.j_lastj here */
for (i = 0; i < js.j_jobslots; i++)
{
***************
*** 2005,2008 ****
--- 2102,2107 ----
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)
***************
*** 2199,2203 ****
wait_sigint_received = 0;
if (job_control == 0)
! old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler);
termination_state = last_command_exit_value;
--- 2298,2306 ----
wait_sigint_received = 0;
if (job_control == 0)
! {
! old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler);
! if (old_sigint_handler == SIG_IGN)
! set_signal_handler (SIGINT, old_sigint_handler);
! }
termination_state = last_command_exit_value;
***************
*** 2266,2269 ****
--- 2369,2373 ----
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)
{
***************
*** 2317,2321 ****
itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%ld)", (long)shell_pgrp);
#endif
-
give_terminal_to (shell_pgrp, 0);
}
--- 2421,2424 ----
***************
*** 2866,2869 ****
--- 2969,2973 ----
if (sigchld || block == 0)
waitpid_flags |= WNOHANG;
+ CHECK_TERMSIG;
pid = WAITPID (-1, &status, waitpid_flags);
***************
*** 2892,2895 ****
--- 2996,3000 ----
/* 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 */
***************
*** 2898,2902 ****
run the trap if a process is just being continued. */
if (WIFCONTINUED(status) == 0)
! children_exited++;
/* Locate our PROCESS for this pid. */
--- 3003,3010 ----
run the trap if a process is just being continued. */
if (WIFCONTINUED(status) == 0)
! {
! children_exited++;
! js.c_living--;
! }
/* Locate our PROCESS for this pid. */
***************
*** 3123,3127 ****
restore_sigint_handler ();
if (temp_handler == SIG_DFL)
! termination_unwind_protect (SIGINT);
else if (temp_handler != SIG_IGN)
(*temp_handler) (SIGINT);
--- 3231,3235 ----
restore_sigint_handler ();
if (temp_handler == SIG_DFL)
! termsig_handler (SIGINT);
else if (temp_handler != SIG_IGN)
(*temp_handler) (SIGINT);
***************
*** 3638,3644 ****
if (i < js.j_firstj && jobs[i])
itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
#endif
if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i))))
! delete_job (i, 1);
}
if (running_only == 0)
--- 3746,3754 ----
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, DEL_WARNSTOPPED);
}
if (running_only == 0)
***************
*** 3692,3695 ****
--- 3802,3807 ----
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)
***************
*** 3765,3768 ****
--- 3877,3882 ----
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))
***************
*** 3816,3819 ****
--- 3930,3935 ----
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