Imported from ../bash-2.05a.tar.gz.

This commit is contained in:
Jari Aalto 2001-11-13 17:56:06 +00:00
commit f73dda092b
303 changed files with 37069 additions and 28812 deletions

180
jobs.c
View file

@ -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;
}