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

📄 jobs.c

📁 android-w.song.android.widget
💻 C
📖 第 1 页 / 共 5 页
字号:
#  if defined (DRAIN_OUTPUT)      draino (tty, shell_tty_info.sg_ospeed);#  endif /* DRAIN_OUTPUT */      ioctl (tty, TIOCSETN, &shell_tty_info);      ioctl (tty, TIOCSETC, &shell_tchars);      ioctl (tty, TIOCSLTC, &shell_ltchars);#endif /* NEW_TTY_DRIVER */#if defined (TERMIO_TTY_DRIVER)      ioctl (tty, TCSETAW, &shell_tty_info);#endif /* TERMIO_TTY_DRIVER */#if defined (TERMIOS_TTY_DRIVER)      if (tcsetattr (tty, TCSADRAIN, &shell_tty_info) < 0)	{	  /* Only print an error message if we're really interactive at	     this time. */	  if (interactive)	    sys_error ("[%ld: %d (%d)] tcsetattr", (long)getpid (), shell_level, tty);	  return -1;	}#endif /* TERMIOS_TTY_DRIVER */    }  return 0;}/* Given an index into the jobs array JOB, return the PROCESS struct of the last   process in that job's pipeline.  This is the one whose exit status   counts.  Must be called with SIGCHLD blocked or queued. */static PROCESS *find_last_proc (job, block)     int job;     int block;{  register PROCESS *p;  sigset_t set, oset;  if (block)    BLOCK_CHILD (set, oset);  p = jobs[job]->pipe;  while (p && p->next != jobs[job]->pipe)    p = p->next;  if (block)    UNBLOCK_CHILD (oset);  return (p);}static pid_tfind_last_pid (job, block)     int job;     int block;{  PROCESS *p;  p = find_last_proc (job, block);  /* Possible race condition here. */  return p->pid;}     /* Wait for a particular child of the shell to finish executing.   This low-level function prints an error message if PID is not   a child of this shell.  It returns -1 if it fails, or whatever   wait_for returns otherwise.  If the child is not found in the   jobs table, it returns 127. */intwait_for_single_pid (pid)     pid_t pid;{  register PROCESS *child;  sigset_t set, oset;  int r, job;  BLOCK_CHILD (set, oset);  child = find_pipeline (pid, 0, (int *)NULL);  UNBLOCK_CHILD (oset);  if (child == 0)    {      r = bgp_search (pid);      if (r >= 0)	return r;    }  if (child == 0)    {      internal_error (_("wait: pid %ld is not a child of this shell"), (long)pid);      return (127);    }  r = wait_for (pid);  /* 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, 0, NULL);  if (job != NO_JOB && jobs[job] && DEADJOB (job))    jobs[job]->flags |= J_NOTIFIED;  UNBLOCK_CHILD (oset);  /* If running in posix mode, remove the job from the jobs table immediately */  if (posixly_correct)    {      cleanup_dead_jobs ();      bgp_delete (pid);    }  return r;}/* Wait for all of the background processes started by this shell to finish. */voidwait_for_background_pids (){  register int i, r, waited_for;  sigset_t set, oset;  pid_t pid;  for (waited_for = 0;;)    {      BLOCK_CHILD (set, oset);      /* 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++)	{#if defined (DEBUG)	  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)	    break;	}      if (i == js.j_jobslots)	{	  UNBLOCK_CHILD (oset);	  break;	}      /* now wait for the last pid in that job. */      pid = find_last_pid (i, 0);      UNBLOCK_CHILD (oset);      QUIT;      errno = 0;		/* XXX */      r = wait_for_single_pid (pid);      if (r == -1)	{	  /* If we're mistaken about job state, compensate. */	  if (errno == ECHILD)	    mark_all_jobs_as_dead ();	}      else	waited_for++;    }  /* 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 ();  bgp_clear ();}/* Make OLD_SIGINT_HANDLER the SIGINT signal handler. */#define INVALID_SIGNAL_HANDLER (SigHandler *)wait_for_background_pidsstatic SigHandler *old_sigint_handler = INVALID_SIGNAL_HANDLER;static voidrestore_sigint_handler (){  if (old_sigint_handler != INVALID_SIGNAL_HANDLER)    {      set_signal_handler (SIGINT, old_sigint_handler);      old_sigint_handler = INVALID_SIGNAL_HANDLER;    }}static int wait_sigint_received;/* Handle SIGINT while we are waiting for children in a script to exit.   The `wait' builtin should be interruptible, but all others should be   effectively ignored (i.e. not cause the shell to exit). */static sighandlerwait_sigint_handler (sig)     int sig;{  SigHandler *sigint_handler;  if (interrupt_immediately ||      (this_shell_builtin && this_shell_builtin == wait_builtin))    {      last_command_exit_value = EXECUTION_FAILURE;      restore_sigint_handler ();      /* If we got a SIGINT while in `wait', and SIGINT is trapped, do	 what POSIX.2 says (see builtins/wait.def for more info). */      if (this_shell_builtin && this_shell_builtin == wait_builtin &&	  signal_is_trapped (SIGINT) &&	  ((sigint_handler = trap_to_sighandler (SIGINT)) == trap_handler))	{	  interrupt_immediately = 0;	  trap_handler (SIGINT);	/* set pending_traps[SIGINT] */	  wait_signal_received = SIGINT;	  longjmp (wait_intr_buf, 1);	}            ADDINTERRUPT;      QUIT;    }  /* XXX - should this be interrupt_state?  If it is, the shell will act     as if it got the SIGINT interrupt. */  wait_sigint_received = 1;  /* Otherwise effectively ignore the SIGINT and allow the running job to     be killed. */  SIGRETURN (0);}static intprocess_exit_signal (status)     WAIT status;{  return (WIFSIGNALED (status) ? WTERMSIG (status) : 0);}static intprocess_exit_status (status)     WAIT status;{  if (WIFSIGNALED (status))    return (128 + WTERMSIG (status));  else if (WIFSTOPPED (status) == 0)    return (WEXITSTATUS (status));  else    return (EXECUTION_SUCCESS);}static WAITjob_signal_status (job)     int job;{  register PROCESS *p;  WAIT s;  p = jobs[job]->pipe;  do    {      s = p->status;      if (WIFSIGNALED(s) || WIFSTOPPED(s))	break;      p = p->next;    }  while (p != jobs[job]->pipe);  return s;}  /* Return the exit status of the last process in the pipeline for job JOB.   This is the exit status of the entire job. */static WAITraw_job_exit_status (job)     int job;{  register PROCESS *p;  int fail;  WAIT ret;  if (pipefail_opt)    {      fail = 0;      p = jobs[job]->pipe;      do	{	  if (WSTATUS (p->status) != EXECUTION_SUCCESS)	    fail = WSTATUS(p->status);	  p = p->next;	}      while (p != jobs[job]->pipe);      WSTATUS (ret) = fail;      return ret;    }  for (p = jobs[job]->pipe; p->next != jobs[job]->pipe; p = p->next)    ;  return (p->status);}/* 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. */intjob_exit_status (job)     int job;{  return (process_exit_status (raw_job_exit_status (job)));}intjob_exit_signal (job)     int job;{  return (process_exit_signal (raw_job_exit_status (job)));}#define FIND_CHILD(pid, child) \  do \    { \      child = find_pipeline (pid, 0, (int *)NULL); \      if (child == 0) \	{ \	  give_terminal_to (shell_pgrp, 0); \	  UNBLOCK_CHILD (oset); \	  internal_error (_("wait_for: No record of process %ld"), (long)pid); \	  restore_sigint_handler (); \	  return (termination_state = 127); \	} \    } \  while (0)/* Wait for pid (one of our children) to terminate, then   return the termination state.  Returns 127 if PID is not found in   the jobs table.  Returns -1 if waitchld() returns -1, indicating   that there are no unwaited-for child processes. */intwait_for (pid)     pid_t pid;{  int job, termination_state, r;  WAIT s;  register PROCESS *child;  sigset_t set, oset;  /* In the case that this code is interrupted, and we longjmp () out of it,     we are relying on the code in throw_to_top_level () to restore the     top-level signal mask. */  BLOCK_CHILD (set, oset);  /* Ignore interrupts while waiting for a job run without job control     to finish.  We don't want the shell to exit if an interrupt is     received, only if one of the jobs run is killed via SIGINT.  If     job control is not set, the job will be run in the same pgrp as     the shell, and the shell will see any signals the job gets.  In     fact, we want this set every time the waiting shell and the waited-     for process are in the same process group, including command     substitution. */  /* This is possibly a race condition -- should it go in stop_pipeline? */  wait_sigint_received = 0;  if (job_control == 0 || (subshell_environment&SUBSHELL_COMSUB))    {      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;  if (interactive && job_control == 0)    QUIT;  /* Check for terminating signals and exit the shell if we receive one */  CHECK_TERMSIG;  /* If we say wait_for (), then we have a record of this child somewhere.     If it and none of its peers are running, don't call waitchld(). */  job = NO_JOB;  do    {      FIND_CHILD (pid, child);      /* If this child is part of a job, then we are really waiting for the	 job to finish.  Otherwise, we are waiting for the child to finish.	 We check for JDEAD in case the job state has been set by waitchld	 after receipt of a SIGCHLD. */      if (job == NO_JOB)	job = find_job (pid, 0, NULL);      /* waitchld() takes care of setting the state of the job.  If the job	 has already exited before this is called, sigchld_handler will have	 called waitchld and the state will be set to JDEAD. */      if (PRUNNING(child) || (job != NO_JOB && RUNNING (job)))	{#if defined (WAITPID_BROKEN)    /* SCOv4 */	  sigset_t suspend_set;	  sigemptyset (&suspend_set);	  sigsuspend (&suspend_set);#else /* !WAITPID_BROKEN */#  if defined (MUST_UNBLOCK_CHLD)	  struct sigaction act, oact;	  sigset_t nullset, chldset;	  sigemptyset (&nullset);	  sigemptyset (&chldset);	  sigprocmask (SIG_SETMASK, &nullset, &chldset);	  act.sa_handler = SIG_DFL;	  sigemptyset (&act.sa_mask);	  sigemptyset (&oact.sa_mask);	  act.sa_flags = 0;	  sigaction (SIGCHLD, &act, &oact);#  endif	  queue_sigchld = 1;	  r = waitchld (pid, 1);#  if defined (MUST_UNBLOCK_CHLD)	  sigaction (SIGCHLD, &oact, (struct sigaction *)NULL);	  sigprocmask (SIG_SETMASK, &chldset, (sigset_t *)NULL);#  endif	  queue_sigchld = 0;	  if (r == -1 && errno == ECHILD && this_shell_builtin == wait_builtin)	    {	      termination_state = -1;	      goto wait_for_return;	    }	  /* If child is marked as running, but waitpid() returns -1/ECHILD,	     there is something wrong.  Somewhere, wait should have returned	     that child's pid.  Mark the child as not running and the job,	     if it exists, as JDEAD. */	  if (r == -1 && errno == ECHILD)	    {	      child->running = PS_DONE;	      WSTATUS (child->status) = 0;	/* XXX -- can't find true status */	      js.c_living = 0;		/* no living child processes */	      if (job != NO_JOB)		{		  jobs[job]->state = JDEAD;		  js.c_reaped++;		  js.j_ndead++;		}	    }#endif /* WAITPID_BROKEN */	}      /* If the shell is interactive, and job control is disabled, see	 if the foreground process has died due to SIGINT and jump out	 of the wait loop if it has.  waitchld has already restored the	 old SIGINT signal handler. */      if (interactive && job_control == 0)	QUIT;      /* Check for terminating signals and exit the shell if we receive one */      CHECK_TERMSIG;    }  while (PRUNNING (child) || (job != NO_JOB && RUNNING (job)));  /* The exit state of the command is either the termination state of the     child, or the termination state of the job.  If a job, the status     of the last child in the pipeline is the significant one.  If the command     or job was terminated by a signal, note that value also. */  termination_state = (job != NO_JOB) ? job_exit_status (job)				      : process_exit_status (child->status);  last_command_exit_signal = (job != NO_JOB) ? job_exit_signal (job)					     : process_exit_signal (child->status);  /* XXX */  if ((job != NO_JOB && JOBSTATE (job) == JSTOPPED) || WIFSTOPPED (child->status))    termination_state = 128 + WSTOPSIG (child->status);  if (job == NO_JOB || IS_JOBCONTROL (job))    {      /* 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 0if (job == NO_JOB)  itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%ld)", (long)shell_pgrp);#endif      give_terminal_to (shell_pgrp, 0);    }  /* If the command did not exit cleanly, or the job is just     being stopped, then reset the tty state back to what it     was before this command.  Reset the tty state and notify     the user of the job termination only if the shell is     interactive.  Clean up any dead jobs in either case. */  if (job != NO_JOB)    {      if (interactive_shell && subshell_environment == 0)	{	  /* This used to use `child->status'.  That's wrong, however, for	     pipelines.  `child' is the first process in the pipeline.  It's	     likely that the process we want to check for abnormal termination	     or stopping is the last process in the pipeline, especially if	     it's long-lived and the first process is short-lived.  Since we	     know we have a job here, we can check all the processes in this	     job's pipeline and see if one of them stopped or terminated due	     to a signal.  We might want to change this later to just check	     the last process in the pipeline.  If no process exits due to a	     signal, S is left as the status of the last job in the pipeline. */	  s = job_signal_status (job);	  if (WIFSIGNALED (s) || WIFSTOPPED (s))	    {	      set_tty_state ();	      /* If the current job was stopped or killed by a signal, and		 the user has requested it, get a possibly new window size */	  

⌨️ 快捷键说明

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