mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-22 21:37:58 +02:00
522 lines
15 KiB
Diff
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
|