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

📄 library_24.html

📁 Linux程序员的工作手册
💻 HTML
📖 第 1 页 / 共 4 页
字号:
  for (p = j-&#62;first_process; p; p = p-&#62;next)    if (!p-&#62;completed &#38;&#38; !p-&#62;stopped)      return 0;  return 1;}/* Return true if all processes in the job have completed.  */intjob_is_completed (job *j){  process *p;    for (p = j-&#62;first_process; p; p = p-&#62;next)    if (!p-&#62;completed)      return 0;  return 1;}</PRE><P><A NAME="IDX1746"></A><A NAME="IDX1747"></A><H3><A NAME="SEC419" HREF="library_toc.html#SEC419" tppabs="http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_toc.html#SEC419">Initializing the Shell</A></H3><P>When a shell program that normally performs job control is started, ithas to be careful in case it has been invoked from another shell that isalready doing its own job control.  <P>A subshell that runs interactively has to ensure that it has been placedin the foreground by its parent shell before it can enable job controlitself.  It does this by getting its initial process group ID with the<CODE>getpgrp</CODE> function, and comparing it to the process group ID of thecurrent foreground job associated with its controlling terminal (whichcan be retrieved using the <CODE>tcgetpgrp</CODE> function).<P>If the subshell is not running as a foreground job, it must stop itselfby sending a <CODE>SIGTTIN</CODE> signal to its own process group.  It may notarbitrarily put itself into the foreground; it must wait for the user totell the parent shell to do this.  If the subshell is continued again,it should repeat the check and stop itself again if it is still not inthe foreground.<A NAME="IDX1748"></A><P>Once the subshell has been placed into the foreground by its parentshell, it can enable its own job control.  It does this by calling<CODE>setpgid</CODE> to put itself into its own process group, and thencalling <CODE>tcsetpgrp</CODE> to place this process group into theforeground.<P>When a shell enables job control, it should set itself to ignore all thejob control stop signals so that it doesn't accidentally stop itself.You can do this by setting the action for all the stop signals to<CODE>SIG_IGN</CODE>.<P>A subshell that runs non-interactively cannot and should not support jobcontrol.  It must leave all processes it creates in the same processgroup as the shell itself; this allows the non-interactive shell and itschild processes to be treated as a single job by the parent shell.  Thisis easy to do--just don't use any of the job control primitives--butyou must remember to make the shell do it.<P>Here is the initialization code for the sample shell that shows how todo all of this.<P><PRE>/* Keep track of attributes of the shell.  */#include &#60;sys/types.h&#62;#include &#60;termios.h&#62;#include &#60;unistd.h&#62;pid_t shell_pgid;struct termios shell_tmodes;int shell_terminal;int shell_is_interactive;/* Make sure the shell is running interactively as the foreground job   before proceeding. */voidinit_shell (){    /* See if we are running interactively.  */  shell_terminal = STDIN_FILENO;  shell_is_interactive = isatty (shell_terminal);  if (shell_is_interactive)    {      /* Loop until we are in the foreground.  */      while (tcgetpgrp (shell_terminal) != (shell_pgid = getpgrp ()))        kill (- shell_pgid, SIGTTIN);      /* Ignore interactive and job-control signals.  */      signal (SIGINT, SIG_IGN);      signal (SIGQUIT, SIG_IGN);      signal (SIGTSTP, SIG_IGN);      signal (SIGTTIN, SIG_IGN);      signal (SIGTTOU, SIG_IGN);      signal (SIGCHLD, SIG_IGN);      /* Put ourselves in our own process group.  */      shell_pgid = getpid ();      if (setpgid (shell_pgid, shell_pgid) &#60; 0)        {          perror ("Couldn't put the shell in its own process group");          exit (1);        }      /* Grab control of the terminal.  */      tcsetpgrp (shell_terminal, shell_pgid);      /* Save default terminal attributes for shell.  */      tcgetattr (shell_terminal, &#38;shell_tmodes);    }}</PRE><P><A NAME="IDX1749"></A><H3><A NAME="SEC420" HREF="library_toc.html#SEC420" tppabs="http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_toc.html#SEC420">Launching Jobs</A></H3><P>Once the shell has taken responsibility for performing job control onits controlling terminal, it can launch jobs in response to commandstyped by the user.<P>To create the processes in a process group, you use the same <CODE>fork</CODE>and <CODE>exec</CODE> functions described in section <A HREF="library_23.html#SEC403" tppabs="http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_23.html#SEC403">Process Creation Concepts</A>.Since there are multiple child processes involved, though, things are alittle more complicated and you must be careful to do things in theright order.  Otherwise, nasty race conditions can result.<P>You have two choices for how to structure the tree of parent-childrelationships among the processes.  You can either make all theprocesses in the process group be children of the shell process, or youcan make one process in group be the ancestor of all the other processesin that group.  The sample shell program presented in this chapter usesthe first approach because it makes bookkeeping somewhat simpler.<A NAME="IDX1750"></A><A NAME="IDX1751"></A><P>As each process is forked, it should put itself in the new process groupby calling <CODE>setpgid</CODE>; see section <A HREF="library_24.html#SEC427" tppabs="http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_24.html#SEC427">Process Group Functions</A>.  The firstprocess in the new group becomes its <DFN>process group leader</DFN>, and itsprocess ID becomes the <DFN>process group ID</DFN> for the group.<A NAME="IDX1752"></A><P>The shell should also call <CODE>setpgid</CODE> to put each of its childprocesses into the new process group.  This is because there is apotential timing problem: each child process must be put in the processgroup before it begins executing a new program, and the shell depends onhaving all the child processes in the group before it continuesexecuting.  If both the child processes and the shell call<CODE>setpgid</CODE>, this ensures that the right things happen no matter whichprocess gets to it first.<P>If the job is being launched as a foreground job, the new process groupalso needs to be put into the foreground on the controlling terminalusing <CODE>tcsetpgrp</CODE>.  Again, this should be done by the shell as wellas by each of its child processes, to avoid race conditions.<P>The next thing each child process should do is to reset its signalactions.<P>During initialization, the shell process set itself to ignore jobcontrol signals; see section <A HREF="library_24.html#SEC419" tppabs="http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_24.html#SEC419">Initializing the Shell</A>.  As a result, any childprocesses it creates also ignore these signals by inheritance.  This isdefinitely undesirable, so each child process should explicitly set theactions for these signals back to <CODE>SIG_DFL</CODE> just after it is forked.<P>Since shells follow this convention, applications can assume that theyinherit the correct handling of these signals from the parent process.But every application has a responsibility not to mess up the handlingof stop signals.  Applications that disable the normal interpretation ofthe SUSP character should provide some other mechanism for the user tostop the job.  When the user invokes this mechanism, the program shouldsend a <CODE>SIGTSTP</CODE> signal to the process group of the process, notjust to the process itself.  See section <A HREF="library_21.html#SEC365" tppabs="http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_21.html#SEC365">Signaling Another Process</A>.<P>Finally, each child process should call <CODE>exec</CODE> in the normal way.This is also the point at which redirection of the standard input and output channels should be handled.  See section <A HREF="library_12.html#SEC182" tppabs="http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_12.html#SEC182">Duplicating Descriptors</A>,for an explanation of how to do this.<P>Here is the function from the sample shell program that is responsiblefor launching a program.  The function is executed by each child processimmediately after it has been forked by the shell, and never returns.<P><PRE>voidlaunch_process (process *p, pid_t pgid,                int infile, int outfile, int errfile,                int foreground){  pid_t pid;  if (shell_is_interactive)    {      /* Put the process into the process group and give the process group         the terminal, if appropriate.         This has to be done both by the shell and in the individual         child processes because of potential race conditions.  */      pid = getpid ();      if (pgid == 0) pgid = pid;      setpgid (pid, pgid);      if (foreground)        tcsetpgrp (shell_terminal, pgid);      /* Set the handling for job control signals back to the default.  */      signal (SIGINT, SIG_DFL);      signal (SIGQUIT, SIG_DFL);      signal (SIGTSTP, SIG_DFL);      signal (SIGTTIN, SIG_DFL);      signal (SIGTTOU, SIG_DFL);      signal (SIGCHLD, SIG_DFL);    }  /* Set the standard input/output channels of the new process.  */  if (infile != STDIN_FILENO)    {      dup2 (infile, STDIN_FILENO);      close (infile);    }  if (outfile != STDOUT_FILENO)    {      dup2 (outfile, STDOUT_FILENO);      close (outfile);    }  if (errfile != STDERR_FILENO)    {      dup2 (errfile, STDERR_FILENO);      close (errfile);    }        /* Exec the new process.  Make sure we exit.  */   execvp (p-&#62;argv[0], p-&#62;argv);  perror ("execvp");  exit (1);}</PRE><P>If the shell is not running interactively, this function does not doanything with process groups or signals.  Remember that a shell notperforming job control must keep all of its subprocesses in the sameprocess group as the shell itself.<P>Next, here is the function that actually launches a complete job.After creating the child processes, this function calls some otherfunctions to put the newly created job into the foreground or background;these are discussed in section <A HREF="library_24.html#SEC421" tppabs="http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_24.html#SEC421">Foreground and Background</A>.<P><PRE>voidlaunch_job (job *j, int foreground){  process *p;  pid_t pid;  int mypipe[2], infile, outfile;    infile = j-&#62;stdin;  for (p = j-&#62;first_process; p; p = p-&#62;next)    {      /* Set up pipes, if necessary.  */      if (p-&#62;next)        {          if (pipe (mypipe) &#60; 0)            {              perror ("pipe");              exit (1);            }          outfile = mypipe[1];        }      else        outfile = j-&#62;stdout;      /* Fork the child processes.  */      pid = fork ();      if (pid == 0)        /* This is the child process.  */        launch_process (p, j-&#62;pgid, infile, outfile, j-&#62;stderr, foreground);      else if (pid &#60; 0)        {          /* The fork failed.  */          perror ("fork");

⌨️ 快捷键说明

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