diff options
author | Jari Aalto <jari.aalto@cante.net> | 2001-11-13 17:56:06 +0000 |
---|---|---|
committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:54 +0000 |
commit | f73dda092b33638d2d5e9c35375f687a607b5403 (patch) | |
tree | f21584e70a444d6a1ecba0fb5e2cf79e8cce91db /jobs.c | |
parent | 28ef6c316f1aff914bb95ac09787a3c83c1815fd (diff) | |
download | android_external_bash-f73dda092b33638d2d5e9c35375f687a607b5403.tar.gz android_external_bash-f73dda092b33638d2d5e9c35375f687a607b5403.tar.bz2 android_external_bash-f73dda092b33638d2d5e9c35375f687a607b5403.zip |
Imported from ../bash-2.05a.tar.gz.
Diffstat (limited to 'jobs.c')
-rw-r--r-- | jobs.c | 180 |
1 files changed, 111 insertions, 69 deletions
@@ -33,9 +33,7 @@ # include <unistd.h> #endif -#if defined (HAVE_SYS_TIME_H) -# include <sys/time.h> -#endif +#include "posixtime.h" #if defined (HAVE_SYS_RESOURCE_H) && defined (HAVE_WAIT3) && !defined (_POSIX_VERSION) && !defined (RLIMTYPE) # include <sys/resource.h> @@ -127,21 +125,28 @@ extern int errno; # define REINSTALL_SIGCHLD_HANDLER #endif /* !MUST_REINSTALL_SIGHANDLERS */ +/* Some systems let waitpid(2) tell callers about stopped children. */ +#if !defined (WCONTINUED) +# define WCONTINUED 0 +# define WIFCONTINUED(s) (0) +#endif + /* The number of additional slots to allocate when we run out. */ #define JOB_SLOTS 8 +typedef int sh_job_map_func_t __P((JOB *, int, int, int)); + #if defined (READLINE) extern void rl_set_screen_size __P((int, int)); #endif /* Variables used here but defined in other files. */ -extern int interactive, interactive_shell, asynchronous_notification; extern int startup_state, subshell_environment, line_number; -extern int posixly_correct, no_symbolic_links, shell_level; +extern int posixly_correct, shell_level; extern int interrupt_immediately, last_command_exit_value; extern int loop_level, breaking; extern int sourcelevel; -extern Function *this_shell_builtin; +extern sh_builtin_func_t *this_shell_builtin; extern char *shell_name, *this_command_name; extern sigset_t top_level_mask; extern procenv_t wait_intr_buf; @@ -151,10 +156,6 @@ extern WORD_LIST *subst_assign_varlist; static int *pstatuses; /* list of pipeline statuses */ static int statsize; #endif -static int set_job_status_and_cleanup (); -static void setjstatus (); -static void get_new_window_size (); -static void run_sigchld_trap (); /* The array of known jobs. */ JOB **jobs = (JOB **)NULL; @@ -210,23 +211,57 @@ int already_making_children = 0; int check_window_size; /* Functions local to this file. */ -static sighandler sigchld_handler (); -static int waitchld (); -static PROCESS *find_pipeline (); -static char *current_working_directory (); -static char *job_working_directory (); -static pid_t find_last_pid (), last_pid (); -static int set_new_line_discipline (), map_over_jobs (); -static int job_last_running (), job_last_stopped (); -static int most_recent_job_in_state (), find_job (); -static void notify_of_job_status (), cleanup_dead_jobs (), discard_pipeline (); -static void add_process (), set_current_job (), reset_current (); -static void print_pipeline (); -static void pretty_print_job (); -static void mark_all_jobs_as_dead (); -static void mark_dead_jobs_as_notified (); + +static void get_new_window_size __P((int)); + +static void run_sigchld_trap __P((int)); + +static sighandler wait_sigint_handler __P((int)); +static sighandler sigchld_handler __P((int)); +static sighandler sigwinch_sighandler __P((int)); +static sighandler sigcont_sighandler __P((int)); +static sighandler sigstop_sighandler __P((int)); + +static int waitchld __P((pid_t, int)); + +static PROCESS *find_pipeline __P((pid_t)); + +static char *current_working_directory __P((void)); +static char *job_working_directory __P((void)); +static char *printable_job_status __P((int, PROCESS *, int)); + +static pid_t find_last_pid __P((int)); +static pid_t last_pid __P((int)); + +static int set_new_line_discipline __P((int)); +static int map_over_jobs __P((sh_job_map_func_t *, int, int)); +static int job_last_stopped __P((int)); +static int job_last_running __P((int)); +static int most_recent_job_in_state __P((int, JOB_STATE)); +static int find_job __P((pid_t)); +static int print_job __P((JOB *, int, int, int)); +static int process_exit_status __P((WAIT)); +static int job_exit_status __P((int)); +static int set_job_status_and_cleanup __P((int)); + +static WAIT raw_job_exit_status __P((int)); + +static void notify_of_job_status __P((void)); +static void cleanup_dead_jobs __P((void)); +static void discard_pipeline __P((PROCESS *)); +static void add_process __P((char *, pid_t)); +static void print_pipeline __P((PROCESS *, int, int, FILE *)); +static void pretty_print_job __P((int, int, FILE *)); +static void set_current_job __P((int)); +static void reset_current __P((void)); +static void set_job_running __P((int)); +static void setjstatus __P((int)); +static void mark_all_jobs_as_dead __P((void)); +static void mark_dead_jobs_as_notified __P((int)); +static void restore_sigint_handler __P((void)); #if defined (PGRP_PIPE) -static void pipe_read (), pipe_close (); +static void pipe_read __P((int *)); +static void pipe_close __P((int *)); #endif /* Used to synchronize between wait_for and the SIGCHLD signal handler. */ @@ -243,9 +278,6 @@ static int saved_already_making_children; commands. */ static int jobs_list_frozen; -static sigset_t empty_sigset; -static sigset_t sigchld_sigset; - static char retcode_name_buffer[64]; #if !defined (_POSIX_VERSION) @@ -484,7 +516,7 @@ stop_pipeline (async, deferred) newjob->wd = job_working_directory (); newjob->deferred = deferred; - newjob->j_cleanup = (VFunction *)NULL; + newjob->j_cleanup = (sh_vptrfunc_t *)NULL; newjob->cleanarg = (PTR_T) NULL; jobs[i] = newjob; @@ -555,7 +587,7 @@ delete_job (job_index, warn_stopped) return; if (warn_stopped && subshell_environment == 0 && STOPPED (job_index)) - internal_warning ("deleting stopped job %d with process group %d", job_index+1, jobs[job_index]->pgrp); + 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 == current_job || job_index == previous_job) @@ -677,7 +709,7 @@ reverse_the_pipeline () and INDEX. */ static int map_over_jobs (func, arg1, arg2) - Function *func; + sh_job_map_func_t *func; int arg1, arg2; { register int i; @@ -847,9 +879,9 @@ describe_pid (pid) job = find_job (pid); if (job != NO_JOB) - printf ("[%d] %d\n", job + 1, (int)pid); + printf ("[%d] %ld\n", job + 1, (long)pid); else - programming_error ("describe_pid: %d: no such pid", (int)pid); + programming_error ("describe_pid: %ld: no such pid", (long)pid); UNBLOCK_CHILD (oset); } @@ -880,9 +912,9 @@ printable_job_status (j, p, format) else { if (WIFSTOPPED (p->status)) - temp = (char *)strsignal (WSTOPSIG (p->status)); + temp = strsignal (WSTOPSIG (p->status)); else if (WIFSIGNALED (p->status)) - temp = (char *)strsignal (WTERMSIG (p->status)); + temp = strsignal (WTERMSIG (p->status)); else if (WIFEXITED (p->status)) { temp = retcode_name_buffer; @@ -947,7 +979,7 @@ print_pipeline (p, job_index, format, stream) fprintf (stream, format ? " " : " |"); if (format != JLIST_STANDARD) - fprintf (stream, "%5d", (int)p->pid); + fprintf (stream, "%5ld", (long)p->pid); fprintf (stream, " "); @@ -979,7 +1011,9 @@ print_pipeline (p, job_index, format, stream) fprintf (stream, "%*s", name_padding, ""); - if ((WIFSTOPPED (show->status) == 0) && WIFCORED (show->status)) + if ((WIFSTOPPED (show->status) == 0) && + (WIFCONTINUED (show->status) == 0) && + WIFCORED (show->status)) fprintf (stream, "(core dumped) "); } } @@ -1035,7 +1069,7 @@ pretty_print_job (job_index, format, stream) /* Format only pid information about the process group leader? */ if (format == JLIST_PID_ONLY) { - fprintf (stream, "%d\n", (int)jobs[job_index]->pipe->pid); + fprintf (stream, "%ld\n", (long)jobs[job_index]->pipe->pid); UNBLOCK_CHILD (oset); return; } @@ -1198,7 +1232,7 @@ make_child (command, async_p) B.4.3.3, p. 237 also covers this, in the context of job control shells. */ if (setpgid (mypid, pipeline_pgrp) < 0) - sys_error ("child setpgid (%d to %d)", mypid, pipeline_pgrp); + sys_error ("child setpgid (%ld to %ld)", (long)mypid, (long)pipeline_pgrp); #if defined (PGRP_PIPE) if (pipeline_pgrp == mypid) { @@ -1382,7 +1416,7 @@ get_tty_state () /* Only print an error message if we're really interactive at this time. */ if (interactive) - sys_error ("[%d: %d] tcgetattr", getpid (), shell_level); + sys_error ("[%ld: %d] tcgetattr", (long)getpid (), shell_level); #endif return -1; } @@ -1421,7 +1455,7 @@ set_tty_state () /* Only print an error message if we're really interactive at this time. */ if (interactive) - sys_error ("[%d: %d] tcsetattr", getpid (), shell_level); + sys_error ("[%ld: %d] tcsetattr", (long)getpid (), shell_level); return -1; } #endif /* TERMIOS_TTY_DRIVER */ @@ -1478,7 +1512,7 @@ wait_for_single_pid (pid) if (child == 0) { - internal_error ("wait: pid %d is not a child of this shell", pid); + internal_error ("wait: pid %ld is not a child of this shell", (long)pid); return (127); } @@ -1616,6 +1650,7 @@ process_exit_status (status) This is the exit status of the entire job. */ static WAIT raw_job_exit_status (job) + int job; { register PROCESS *p; for (p = jobs[job]->pipe; p->next != jobs[job]->pipe; p = p->next) @@ -1626,7 +1661,7 @@ raw_job_exit_status (job) /* Return the exit status of job JOB. This is the exit status of the last (rightmost) process in the job's pipeline, modified if the job was killed by a signal or stopped. */ -static WAIT +static int job_exit_status (job) int job; { @@ -1641,7 +1676,7 @@ job_exit_status (job) { \ give_terminal_to (shell_pgrp, 0); \ UNBLOCK_CHILD (oset); \ - internal_error ("wait_for: No record of process %d", pid); \ + internal_error ("wait_for: No record of process %ld", (long)pid); \ restore_sigint_handler (); \ return (termination_state = 127); \ } \ @@ -1783,7 +1818,7 @@ wait_for (pid) */ #if 0 if (job == NO_JOB) - itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%d)", shell_pgrp); + itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%ld)", (long)shell_pgrp); #endif give_terminal_to (shell_pgrp, 0); @@ -2209,13 +2244,13 @@ kill_pid (pid, sig, group) int job, result; sigset_t set, oset; - BLOCK_CHILD (set, oset); - p = find_pipeline (pid); - job = find_job (pid); - result = EXECUTION_SUCCESS; if (group) { + BLOCK_CHILD (set, oset); + p = find_pipeline (pid); + job = find_job (pid); + if (job != NO_JOB) { jobs[job]->flags &= ~J_NOTIFIED; @@ -2251,11 +2286,12 @@ kill_pid (pid, sig, group) } else result = killpg (pid, sig); + + UNBLOCK_CHILD (oset); } else result = kill (pid, sig); - UNBLOCK_CHILD (oset); return (result); } @@ -2302,11 +2338,12 @@ waitchld (wpid, block) /* We don't want to be notified about jobs stopping if job control is not active. XXX - was interactive_shell instead of job_control */ waitpid_flags = (job_control && subshell_environment == 0) - ? WUNTRACED + ? (WUNTRACED|WCONTINUED) : 0; if (sigchld || block == 0) waitpid_flags |= WNOHANG; pid = WAITPID (-1, &status, waitpid_flags); + /* The check for WNOHANG is to make sure we decrement sigchld only if it was non-zero before we called waitpid. */ if (sigchld > 0 && (waitpid_flags & WNOHANG)) @@ -2327,7 +2364,10 @@ waitchld (wpid, block) if (pid <= 0) continue; /* jumps right to the test */ - children_exited++; + /* 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++; /* Locate our PROCESS for this pid. */ child = find_pipeline (pid); @@ -2342,9 +2382,9 @@ waitchld (wpid, block) while (child->pid != pid) child = child->next; - /* Remember status, and fact that process is not running. */ + /* Remember status, and whether or not the process is running. */ child->status = status; - child->running = 0; + child->running = WIFCONTINUED(status) ? 1 : 0; job = find_job (pid); @@ -2424,8 +2464,9 @@ set_job_status_and_cleanup (job) while (child != jobs[job]->pipe); /* If job_state != 0, the job is still running, so don't bother with - setting the process exit status and job state. */ - if (job_state != 0) + setting the process exit status and job state unless we're + transitioning from stopped to running. */ + if (job_state != 0 && JOBSTATE(job) != JSTOPPED) return 0; /* @@ -2442,6 +2483,11 @@ set_job_status_and_cleanup (job) if (any_tstped && loop_level) breaking = loop_level; } + else if (job_state != 0) /* was stopped, now running */ + { + jobs[job]->state = JRUNNING; + call_set_current++; + } else { jobs[job]->state = JDEAD; @@ -2456,7 +2502,7 @@ set_job_status_and_cleanup (job) if (jobs[job]->j_cleanup) { (*jobs[job]->j_cleanup) (jobs[job]->cleanarg); - jobs[job]->j_cleanup = (VFunction *)NULL; + jobs[job]->j_cleanup = (sh_vptrfunc_t *)NULL; } } @@ -2588,10 +2634,7 @@ run_sigchld_trap (nchild) begin_unwind_frame ("SIGCHLD trap"); unwind_protect_int (last_command_exit_value); - if (sizeof (pid_t) == sizeof (short)) - unwind_protect_short (last_made_pid); - else - unwind_protect_int (last_made_pid); + unwind_protect_var (last_made_pid); unwind_protect_int (interrupt_immediately); unwind_protect_int (jobs_list_frozen); unwind_protect_pointer (the_pipeline); @@ -2845,10 +2888,10 @@ initialize_job_control (force) void debug_print_pgrps () { - itrace("original_pgrp = %d shell_pgrp = %d terminal_pgrp = %d", - original_pgrp, shell_pgrp, terminal_pgrp); - itrace("tcgetpgrp(%d) -> %d, getpgid(0) -> %d", - shell_tty, tcgetpgrp (shell_tty), getpgid(0)); + itrace("original_pgrp = %ld shell_pgrp = %ld terminal_pgrp = %ld", + (long)original_pgrp, (long)shell_pgrp, (long)terminal_pgrp); + itrace("tcgetpgrp(%d) -> %ld, getpgid(0) -> %ld", + shell_tty, (long)tcgetpgrp (shell_tty), (long)getpgid(0)); } #endif @@ -2911,7 +2954,6 @@ set_new_line_discipline (tty) static SigHandler *old_tstp, *old_ttou, *old_ttin; static SigHandler *old_cont = (SigHandler *)SIG_DFL; -static sighandler sigstop_sighandler (), sigcont_sighandler (); #if defined (TIOCGWINSZ) && defined (SIGWINCH) static SigHandler *old_winch = (SigHandler *)SIG_DFL; @@ -3045,8 +3087,8 @@ give_terminal_to (pgrp, force) { /* Maybe we should print an error message? */ #if 0 - sys_error ("tcsetpgrp(%d) failed: pid %d to pgrp %d", - shell_tty, getpid(), pgrp); + sys_error ("tcsetpgrp(%d) failed: pid %ld to pgrp %ld", + shell_tty, (long)getpid(), (long)pgrp); #endif r = -1; } |