⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jobs.c

📁 android-w.song.android.widget
💻 C
📖 第 1 页 / 共 5 页
字号:
/* jobs.c - functions that make children, remember them, and handle their termination. *//* This file works with both POSIX and BSD systems.  It implements job   control. *//* Copyright (C) 1989-2010 Free Software Foundation, Inc.   This file is part of GNU Bash, the Bourne Again SHell.   Bash is free software: you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation, either version 3 of the License, or   (at your option) any later version.   Bash is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.   You should have received a copy of the GNU General Public License   along with Bash.  If not, see <http://www.gnu.org/licenses/>.*/#include "config.h"#include "bashtypes.h"#include "trap.h"#include <stdio.h>#include <signal.h>#include <errno.h>#if defined (HAVE_UNISTD_H)#  include <unistd.h>#endif#include "posixtime.h"#if defined (HAVE_SYS_RESOURCE_H) && defined (HAVE_WAIT3) && !defined (_POSIX_VERSION) && !defined (RLIMTYPE)#  include <sys/resource.h>#endif /* !_POSIX_VERSION && HAVE_SYS_RESOURCE_H && HAVE_WAIT3 && !RLIMTYPE */#if defined (HAVE_SYS_FILE_H)#  include <sys/file.h>#endif#include "filecntl.h"#include <sys/ioctl.h>#include <sys/param.h>#if defined (BUFFERED_INPUT)#  include "input.h"#endif/* Need to include this up here for *_TTY_DRIVER definitions. */#include "shtty.h"/* Define this if your output is getting swallowed.  It's a no-op on   machines with the termio or termios tty drivers. *//* #define DRAIN_OUTPUT *//* For the TIOCGPGRP and TIOCSPGRP ioctl parameters on HP-UX */#if defined (hpux) && !defined (TERMIOS_TTY_DRIVER)#  include <bsdtty.h>#endif /* hpux && !TERMIOS_TTY_DRIVER */#include "bashansi.h"#include "bashintl.h"#include "shell.h"#include "jobs.h"#include "execute_cmd.h"#include "flags.h"#include "builtins/builtext.h"#include "builtins/common.h"#if !defined (errno)extern int errno;#endif /* !errno */#if !defined (HAVE_KILLPG)extern int killpg __P((pid_t, int));#endif#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   children.  The arguments to the WAITPID macro match those to the Posix.1   waitpid() function. */#if defined (ultrix) && defined (mips) && defined (_POSIX_VERSION)#  define WAITPID(pid, statusp, options) \	wait3 ((union wait *)statusp, options, (struct rusage *)0)#else#  if defined (_POSIX_VERSION) || defined (HAVE_WAITPID)#    define WAITPID(pid, statusp, options) \	waitpid ((pid_t)pid, statusp, options)#  else#    if defined (HAVE_WAIT3)#      define WAITPID(pid, statusp, options) \	wait3 (statusp, options, (struct rusage *)0)#    else#      define WAITPID(pid, statusp, options) \	wait3 (statusp, options, (int *)0)#    endif /* HAVE_WAIT3 */#  endif /* !_POSIX_VERSION && !HAVE_WAITPID*/#endif /* !(Ultrix && mips && _POSIX_VERSION) *//* getpgrp () varies between systems.  Even systems that claim to be   Posix.1 compatible lie sometimes (Ultrix, SunOS4, apollo). */#if defined (GETPGRP_VOID)#  define getpgid(p) getpgrp ()#else#  define getpgid(p) getpgrp (p)#endif /* !GETPGRP_VOID *//* If the system needs it, REINSTALL_SIGCHLD_HANDLER will reinstall the   handler for SIGCHLD. */#if defined (MUST_REINSTALL_SIGHANDLERS)#  define REINSTALL_SIGCHLD_HANDLER signal (SIGCHLD, sigchld_handler)#else#  define REINSTALL_SIGCHLD_HANDLER#endif /* !MUST_REINSTALL_SIGHANDLERS *//* Some systems let waitpid(2) tell callers about stopped children. */#if !defined (WCONTINUED) || defined (WCONTINUED_BROKEN)#  undef WCONTINUED#  define WCONTINUED 0#endif#if !defined (WIFCONTINUED)#  define WIFCONTINUED(s)	(0)#endif/* The number of additional slots to allocate when we run out. */#define JOB_SLOTS 8typedef int sh_job_map_func_t __P((JOB *, int, int, int));/* Variables used here but defined in other files. */extern int subshell_environment, line_number;extern int posixly_correct, shell_level;extern int last_command_exit_value, last_command_exit_signal;extern int loop_level, breaking;extern int executing_list;extern int sourcelevel;extern int running_trap;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;extern int wait_signal_received;extern WORD_LIST *subst_assign_varlist;static struct jobstats zerojs = { -1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NO_JOB, NO_JOB, 0, 0 };struct jobstats js = { -1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NO_JOB, NO_JOB, 0, 0 };struct bgpids bgpids = { 0, 0, 0 };/* The array of known jobs. */JOB **jobs = (JOB **)NULL;#if 0/* The number of slots currently allocated to JOBS. */int job_slots = 0;#endif/* The controlling tty for this shell. */int shell_tty = -1;/* The shell's process group. */pid_t shell_pgrp = NO_PID;/* The terminal's process group. */pid_t terminal_pgrp = NO_PID;/* The process group of the shell's parent. */pid_t original_pgrp = NO_PID;/* The process group of the pipeline currently being made. */pid_t pipeline_pgrp = (pid_t)0;#if defined (PGRP_PIPE)/* Pipes which each shell uses to communicate with the process group leader   until all of the processes in a pipeline have been started.  Then the   process leader is allowed to continue. */int pgrp_pipe[2] = { -1, -1 };#endif#if 0/* The job which is current; i.e. the one that `%+' stands for. */int current_job = NO_JOB;/* The previous job; i.e. the one that `%-' stands for. */int previous_job = NO_JOB;#endif/* Last child made by the shell.  */pid_t last_made_pid = NO_PID;/* Pid of the last asynchronous child. */pid_t last_asynchronous_pid = NO_PID;/* The pipeline currently being built. */PROCESS *the_pipeline = (PROCESS *)NULL;/* If this is non-zero, do job control. */int job_control = 1;/* Call this when you start making children. */int already_making_children = 0;/* If this is non-zero, $LINES and $COLUMNS are reset after every process   exits from get_tty_state(). */int check_window_size;/* Functions local to this file. */static sighandler wait_sigint_handler __P((int));static sighandler sigchld_handler __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, int, int *));static PROCESS *find_process __P((pid_t, int, int *));static char *current_working_directory __P((void));static char *job_working_directory __P((void));static char *j_strsignal __P((int));static char *printable_job_status __P((int, PROCESS *, int));static PROCESS *find_last_proc __P((int, int));static pid_t find_last_pid __P((int, 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, int, PROCESS **));static int print_job __P((JOB *, int, int, int));static int process_exit_status __P((WAIT));static int process_exit_signal __P((WAIT));static int set_job_status_and_cleanup __P((int));static WAIT job_signal_status __P((int));static WAIT raw_job_exit_status __P((int));static void notify_of_job_status __P((void));static void reset_job_indices __P((void));static void cleanup_dead_jobs __P((void));static int processes_in_job __P((int));static void realloc_jobs_list __P((void));static int compact_jobs_list __P((int));static int 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 int maybe_give_terminal_to __P((pid_t, pid_t, 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 __P((int *));#endifstatic struct pidstat *bgp_alloc __P((pid_t, int));static struct pidstat *bgp_add __P((pid_t, int));static int bgp_delete __P((pid_t));static void bgp_clear __P((void));static int bgp_search __P((pid_t));static void bgp_prune __P((void));#if defined (ARRAY_VARS)static int *pstatuses;		/* list of pipeline statuses */static int statsize;#endif/* Used to synchronize between wait_for and other functions and the SIGCHLD   signal handler. */static int sigchld;static int queue_sigchld;#define QUEUE_SIGCHLD(os)	(os) = sigchld, queue_sigchld++#define UNQUEUE_SIGCHLD(os) \	do { \	  queue_sigchld--; \	  if (queue_sigchld == 0 && os != sigchld) \	    waitchld (-1, 0); \	} while (0)static SigHandler *old_tstp, *old_ttou, *old_ttin;static SigHandler *old_cont = (SigHandler *)SIG_DFL;/* A place to temporarily save the current pipeline. */static PROCESS *saved_pipeline;static int saved_already_making_children;/* Set this to non-zero whenever you don't want the jobs list to change at   all: no jobs deleted and no status change notifications.  This is used,   for example, when executing SIGCHLD traps, which may run arbitrary   commands. */static int jobs_list_frozen;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)/* These are definitions to map POSIX 1003.1 functions onto existing BSD   library functions and system calls. */#define setpgid(pid, pgrp)	setpgrp (pid, pgrp)#define tcsetpgrp(fd, pgrp)	ioctl ((fd), TIOCSPGRP, &(pgrp))pid_ttcgetpgrp (fd)     int fd;{  pid_t pgrp;  /* ioctl will handle setting errno correctly. */  if (ioctl (fd, TIOCGPGRP, &pgrp) < 0)    return (-1);  return (pgrp);}#endif /* !_POSIX_VERSION *//* Initialize the global job stats structure and other bookkeeping variables */voidinit_job_stats (){  js = zerojs;  first_pid = NO_PID;  pid_wrap = -1;}/* Return the working directory for the current process.  Unlike   job_working_directory, this does not call malloc (), nor do any   of the functions it calls.  This is so that it can safely be called   from a signal handler. */static char *current_working_directory (){  char *dir;  static char d[PATH_MAX];  dir = get_string_value ("PWD");  if (dir == 0 && the_current_working_directory && no_symbolic_links)    dir = the_current_working_directory;  if (dir == 0)    {      dir = getcwd (d, sizeof(d));      if (dir)	dir = d;    }  return (dir == 0) ? "<unknown>" : dir;}/* Return the working directory for the current process. */static char *job_working_directory (){  char *dir;  dir = get_string_value ("PWD");  if (dir)    return (savestring (dir));  dir = get_working_directory ("job-working-directory");  if (dir)    return (dir);  return (savestring ("<unknown>"));}voidmaking_children (){  if (already_making_children)    return;  already_making_children = 1;  start_pipeline ();}voidstop_making_children (){  already_making_children = 0;}voidcleanup_the_pipeline (){  PROCESS *disposer;  sigset_t set, oset;  BLOCK_CHILD (set, oset);  disposer = the_pipeline;  the_pipeline = (PROCESS *)NULL;  UNBLOCK_CHILD (oset);  if (disposer)    discard_pipeline (disposer);}voidsave_pipeline (clear)     int clear;{  saved_pipeline = the_pipeline;  if (clear)    the_pipeline = (PROCESS *)NULL;  saved_already_making_children = already_making_children;}voidrestore_pipeline (discard)     int discard;{  PROCESS *old_pipeline;  old_pipeline = the_pipeline;  the_pipeline = saved_pipeline;  already_making_children = saved_already_making_children;  if (discard && old_pipeline)    discard_pipeline (old_pipeline);}/* Start building a pipeline.  */voidstart_pipeline (){  if (the_pipeline)    {      cleanup_the_pipeline ();      pipeline_pgrp = 0;#if defined (PGRP_PIPE)      sh_closepipe (pgrp_pipe);#endif    }#if defined (PGRP_PIPE)  if (job_control)    {      if (pipe (pgrp_pipe) == -1)	sys_error (_("start_pipeline: pgrp pipe"));    }#endif}/* Stop building a pipeline.  Install the process list in the job array.   This returns the index of the newly installed job.   DEFERRED is a command structure to be executed upon satisfactory   execution exit of this pipeline. */intstop_pipeline (async, deferred)     int async;     COMMAND *deferred;{  register int i, j;  JOB *newjob;  sigset_t set, oset;  BLOCK_CHILD (set, oset);#if defined (PGRP_PIPE)  /* The parent closes the process group synchronization pipe. */  sh_closepipe (pgrp_pipe);#endif  cleanup_dead_jobs ();  if (js.j_jobslots == 0)    {      js.j_jobslots = JOB_SLOTS;      jobs = (JOB **)xmalloc (js.j_jobslots * sizeof (JOB *));      /* Now blank out these new entries. */      for (i = 0; i < js.j_jobslots; i++)	jobs[i] = (JOB *)NULL;      js.j_firstj = js.j_lastj = js.j_njobs = 0;    }  /* Scan from the last slot backward, looking for the next free one. */  /* XXX - revisit this interactive assumption */  /* XXX - this way for now */  if (interactive)    {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -