diff options
author | Jari Aalto <jari.aalto@cante.net> | 1999-02-19 17:11:39 +0000 |
---|---|---|
committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:52 +0000 |
commit | b72432fdcc59300c6fe7c9d6c8a31ad3447933f5 (patch) | |
tree | b9899162338c2ff3fd83a8aef8831cb119e85cd7 /jobs.c | |
parent | bc4cd23ce958feda898c618215f94d8a4e8f4ffa (diff) | |
download | android_external_bash-b72432fdcc59300c6fe7c9d6c8a31ad3447933f5.tar.gz android_external_bash-b72432fdcc59300c6fe7c9d6c8a31ad3447933f5.tar.bz2 android_external_bash-b72432fdcc59300c6fe7c9d6c8a31ad3447933f5.zip |
Imported from ../bash-2.03.tar.gz.
Diffstat (limited to 'jobs.c')
-rw-r--r-- | jobs.c | 156 |
1 files changed, 99 insertions, 57 deletions
@@ -107,6 +107,10 @@ extern int errno; #endif /* !errno */ +#if !defined (CHILD_MAX) +# define CHILD_MAX 32 +#endif + /* 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 waitpid() function. */ @@ -543,12 +547,7 @@ cleanup_dead_jobs () BLOCK_CHILD (set, oset); for (i = 0; i < job_slots; i++) -#if 0 - if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i) && - (interactive_shell || (find_last_pid (i) != last_asynchronous_pid))) -#else if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i)) -#endif delete_job (i, 0); UNBLOCK_CHILD (oset); @@ -1150,9 +1149,9 @@ make_child (command, async_p) { /* In the child. Give this child the right process group, set the signals to the default state for a new process. */ - pid_t mine; + pid_t mypid; - mine = getpid (); + mypid = getpid (); #if defined (BUFFERED_INPUT) /* Close default_buffered_input if it's > 0. We don't close it if it's 0 because that's the file descriptor used when redirecting input, @@ -1169,7 +1168,7 @@ make_child (command, async_p) process group. */ if (pipeline_pgrp == 0) /* This is the first child. */ - pipeline_pgrp = mine; + pipeline_pgrp = mypid; /* Check for running command in backquotes. */ if (pipeline_pgrp == shell_pgrp) @@ -1185,12 +1184,18 @@ make_child (command, async_p) this would have for the first child) is an error. Section B.4.3.3, p. 237 also covers this, in the context of job control shells. */ - if (setpgid (mine, pipeline_pgrp) < 0) - sys_error ("child setpgid (%d to %d)", mine, pipeline_pgrp); + if (setpgid (mypid, pipeline_pgrp) < 0) + sys_error ("child setpgid (%d to %d)", mypid, pipeline_pgrp); #if defined (PGRP_PIPE) - if (pipeline_pgrp == mine) + if (pipeline_pgrp == mypid) { #endif + /* XXX - By convention (and assumption above), if + pipeline_pgrp == shell_pgrp, we are making a child for + command substitution. + In this case, we don't want to give the terminal to the + 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); @@ -1471,16 +1476,13 @@ wait_for_single_pid (pid) r = wait_for (pid); - /* POSIX.2: if we just waited for $!, we can remove the job from the - jobs table. */ - if (pid == last_asynchronous_pid) - { - BLOCK_CHILD (set, oset); - job = find_job (pid); - if (job != NO_JOB && jobs[job] && DEADJOB (job)) - jobs[job]->flags |= J_NOTIFIED; - UNBLOCK_CHILD (oset); - } + /* 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); + if (job != NO_JOB && jobs[job] && DEADJOB (job)) + jobs[job]->flags |= J_NOTIFIED; + UNBLOCK_CHILD (oset); return r; } @@ -1521,6 +1523,11 @@ wait_for_background_pids () break; } } + + /* POSIX.2 says the shell can discard the statuses of all completed jobs if + `wait' is called with no arguments. */ + mark_dead_jobs_as_notified (1); + cleanup_dead_jobs (); } /* Make OLD_SIGINT_HANDLER the SIGINT signal handler. */ @@ -1722,7 +1729,27 @@ wait_for (pid) termination_state = process_exit_status (child->status); if (job == NO_JOB || IS_JOBCONTROL (job)) - give_terminal_to (shell_pgrp); + { + /* XXX - under what circumstances is a job not present in the jobs + table (job == NO_JOB)? + 1. command substitution + + In the case of command substitution, at least, it's probably not + the right thing to give the terminal to the shell's process group, + even though there is code in subst.c:command_substitute to work + around it. + + Things that don't: + $PROMPT_COMMAND execution + process substitution + */ +#if 0 +if (job == NO_JOB) + itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%d)", shell_pgrp); +#endif + + give_terminal_to (shell_pgrp); + } /* If the command did not exit cleanly, or the job is just being stopped, then reset the tty state back to what it @@ -1775,13 +1802,7 @@ wait_for (pid) sure we turn on the notify bit so we don't get an unwanted message about the job's termination, and so delete_job really clears the slot in the jobs table. */ -#if 0 - if (DEADJOB (job)) - jobs[job]->flags |= J_NOTIFIED; - cleanup_dead_jobs (); -#else notify_and_cleanup (); -#endif } } @@ -1810,15 +1831,12 @@ wait_for_job (job) pid = last_pid (job); r = wait_for (pid); - /* POSIX.2: if we just waited for $!, we can remove the job from the - jobs table. */ - if (pid == last_asynchronous_pid) - { - BLOCK_CHILD (set, oset); - if (job != NO_JOB && jobs[job] && DEADJOB (job)) - jobs[job]->flags |= J_NOTIFIED; - UNBLOCK_CHILD (oset); - } + /* POSIX.2: we can remove the job from the jobs table if we just waited + for it. */ + BLOCK_CHILD (set, oset); + if (job != NO_JOB && jobs[job] && DEADJOB (job)) + jobs[job]->flags |= J_NOTIFIED; + UNBLOCK_CHILD (oset); return r; } @@ -1844,7 +1862,7 @@ notify_and_cleanup () void reap_dead_jobs () { - mark_dead_jobs_as_notified (); + mark_dead_jobs_as_notified (0); cleanup_dead_jobs (); } @@ -2488,23 +2506,25 @@ notify_of_job_status () s = jobs[job]->pipe->status; termsig = WTERMSIG (s); + /* POSIX.2 says we have to hang onto the statuses of at most the + last CHILD_MAX background processes if the shell is running a + script. If the shell is not interactive, don't print anything + unless the job was killed by a signal. */ + if (startup_state == 0 && WIFSIGNALED (s) == 0 && + ((DEADJOB (job) && IS_FOREGROUND (job) == 0) || STOPPED (job))) + continue; + /* If job control is disabled, don't print the status messages. Mark dead jobs as notified so that they get cleaned up. If startup_state == 2, we were started to run `-c command', so - don't print anything. If the shell is not interactive, don't - print anything unless the job was killed by a signal. */ - if ((job_control == 0 && interactive_shell) || startup_state == 2 || - (startup_state == 0 && WIFSIGNALED (s) == 0)) + don't print anything. */ + if ((job_control == 0 && interactive_shell) || startup_state == 2) { -#if 0 - if (DEADJOB (job)) -#else /* POSIX.2 compatibility: if the shell is not interactive, 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))) -#endif jobs[job]->flags |= J_NOTIFIED; continue; } @@ -2516,9 +2536,7 @@ notify_of_job_status () { case JDEAD: if (interactive_shell == 0 && termsig && WIFSIGNALED (s) && -#if 1 termsig != SIGINT && -#endif #if defined (DONT_REPORT_SIGPIPE) termsig != SIGPIPE && #endif @@ -2943,24 +2961,48 @@ nohup_all_jobs (running_only) } /* Mark all dead jobs as notified, so delete_job () cleans them out - of the job table properly. */ + of the job table properly. POSIX.2 says we need to save the + status of the last CHILD_MAX jobs, so we count the number of dead + jobs and mark only enough as notified to save CHILD_MAX statuses. */ static void -mark_dead_jobs_as_notified () +mark_dead_jobs_as_notified (force) + int force; { - register int i; + 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++; + } + + /* 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; + } + + /* 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 0 - if (jobs[i] && DEADJOB (i)) -#else - if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i) != last_asynchronous_pid))) -#endif - jobs[i]->flags |= J_NOTIFIED; + { + 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; + } + } UNBLOCK_CHILD (oset); } |