*** ../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