📄 job.texi
字号:
pid_t pid; do pid = waitpid (WAIT_ANY, &status, WUNTRACED|WNOHANG); while (!mark_process_status (pid, status));@}@end group@group/* @r{Check for processes that have status information available,} @r{blocking until all processes in the given job have reported.} */voidwait_for_job (job *j)@{ int status; pid_t pid; do pid = waitpid (WAIT_ANY, &status, WUNTRACED); while (!mark_process_status (pid, status) && !job_is_stopped (j) && !job_is_completed (j));@}@end group@group/* @r{Format information about job status for the user to look at.} */voidformat_job_info (job *j, const char *status)@{ fprintf (stderr, "%ld (%s): %s\n", (long)j->pgid, status, j->command);@}@end group@group/* @r{Notify the user about stopped or terminated jobs.} @r{Delete terminated jobs from the active job list.} */voiddo_job_notification (void)@{ job *j, *jlast, *jnext; process *p; /* @r{Update status information for child processes.} */ update_status (); jlast = NULL; for (j = first_job; j; j = jnext) @{ jnext = j->next; /* @r{If all processes have completed, tell the user the job has} @r{completed and delete it from the list of active jobs.} */ if (job_is_completed (j)) @{ format_job_info (j, "completed"); if (jlast) jlast->next = jnext; else first_job = jnext; free_job (j); @} /* @r{Notify the user about stopped jobs,} @r{marking them so that we won't do this more than once.} */ else if (job_is_stopped (j) && !j->notified) @{ format_job_info (j, "stopped"); j->notified = 1; jlast = j; @} /* @r{Don't say anything about jobs that are still running.} */ else jlast = j; @}@}@end group@end smallexample@node Continuing Stopped Jobs, Missing Pieces, Stopped and Terminated Jobs, Implementing a Shell@subsection Continuing Stopped Jobs@cindex stopped jobs, continuingThe shell can continue a stopped job by sending a @code{SIGCONT} signalto its process group. If the job is being continued in the foreground,the shell should first invoke @code{tcsetpgrp} to give the job access tothe terminal, and restore the saved terminal settings. After continuinga job in the foreground, the shell should wait for the job to stop orcomplete, as if the job had just been launched in the foreground.The sample shell program handles both newly created and continued jobswith the same pair of functions, @w{@code{put_job_in_foreground}} and@w{@code{put_job_in_background}}. The definitions of these functionswere given in @ref{Foreground and Background}. When continuing astopped job, a nonzero value is passed as the @var{cont} argument toensure that the @code{SIGCONT} signal is sent and the terminal modesreset, as appropriate.This leaves only a function for updating the shell's internal bookkeepingabout the job being continued:@smallexample@group/* @r{Mark a stopped job J as being running again.} */voidmark_job_as_running (job *j)@{ Process *p; for (p = j->first_process; p; p = p->next) p->stopped = 0; j->notified = 0;@}@end group@group/* @r{Continue the job J.} */voidcontinue_job (job *j, int foreground)@{ mark_job_as_running (j); if (foreground) put_job_in_foreground (j, 1); else put_job_in_background (j, 1);@}@end group@end smallexample@node Missing Pieces, , Continuing Stopped Jobs, Implementing a Shell@subsection The Missing PiecesThe code extracts for the sample shell included in this chapter are onlya part of the entire shell program. In particular, nothing at all hasbeen said about how @code{job} and @code{program} data structures areallocated and initialized.Most real shells provide a complex user interface that has support fora command language; variables; abbreviations, substitutions, and patternmatching on file names; and the like. All of this is far too complicatedto explain here! Instead, we have concentrated on showing how to implement the core process creation and job control functions that canbe called from such a shell.Here is a table summarizing the major entry points we have presented:@table @code@item void init_shell (void)Initialize the shell's internal state. @xref{Initializing theShell}.@item void launch_job (job *@var{j}, int @var{foreground})Launch the job @var{j} as either a foreground or background job.@xref{Launching Jobs}.@item void do_job_notification (void)Check for and report any jobs that have terminated or stopped. Can becalled synchronously or within a handler for @code{SIGCHLD} signals.@xref{Stopped and Terminated Jobs}.@item void continue_job (job *@var{j}, int @var{foreground})Continue the job @var{j}. @xref{Continuing Stopped Jobs}.@end tableOf course, a real shell would also want to provide other functions formanaging jobs. For example, it would be useful to have commands to listall active jobs or to send a signal (such as @code{SIGKILL}) to a job.@node Functions for Job Control, , Implementing a Shell, Job Control@section Functions for Job Control@cindex process group functions@cindex job control functionsThis section contains detailed descriptions of the functions relatingto job control.@menu* Identifying the Terminal:: Determining the controlling terminal's name.* Process Group Functions:: Functions for manipulating process groups.* Terminal Access Functions:: Functions for controlling terminal access.@end menu@node Identifying the Terminal, Process Group Functions, , Functions for Job Control@subsection Identifying the Controlling Terminal@cindex controlling terminal, determiningYou can use the @code{ctermid} function to get a file name that you canuse to open the controlling terminal. In the GNU library, it returnsthe same string all the time: @code{"/dev/tty"}. That is a special``magic'' file name that refers to the controlling terminal of thecurrent process (if it has one). To find the name of the specificterminal device, use @code{ttyname}; @pxref{Is It a Terminal}.The function @code{ctermid} is declared in the header file@file{stdio.h}.@pindex stdio.h@comment stdio.h@comment POSIX.1@deftypefun {char *} ctermid (char *@var{string})The @code{ctermid} function returns a string containing the file name ofthe controlling terminal for the current process. If @var{string} isnot a null pointer, it should be an array that can hold at least@code{L_ctermid} characters; the string is returned in this array.Otherwise, a pointer to a string in a static area is returned, whichmight get overwritten on subsequent calls to this function.An empty string is returned if the file name cannot be determined forany reason. Even if a file name is returned, access to the file itrepresents is not guaranteed.@end deftypefun@comment stdio.h@comment POSIX.1@deftypevr Macro int L_ctermidThe value of this macro is an integer constant expression thatrepresents the size of a string large enough to hold the file namereturned by @code{ctermid}.@end deftypevrSee also the @code{isatty} and @code{ttyname} functions, in @ref{Is It a Terminal}.@node Process Group Functions, Terminal Access Functions, Identifying the Terminal, Functions for Job Control@subsection Process Group FunctionsHere are descriptions of the functions for manipulating process groups.Your program should include the header files @file{sys/types.h} and@file{unistd.h} to use these functions.@pindex unistd.h@pindex sys/types.h@comment unistd.h@comment POSIX.1@deftypefun pid_t setsid (void)The @code{setsid} function creates a new session. The calling processbecomes the session leader, and is put in a new process group whoseprocess group ID is the same as the process ID of that process. Thereare initially no other processes in the new process group, and no otherprocess groups in the new session.This function also makes the calling process have no controlling terminal.The @code{setsid} function returns the new process group ID of thecalling process if successful. A return value of @code{-1} indicates anerror. The following @code{errno} error conditions are defined for thisfunction:@table @code@item EPERMThe calling process is already a process group leader, or there isalready another process group around that has the same process group ID.@end table@end deftypefunThe @code{getpgrp} function has two definitions: one derived from BSDUnix, and one from the POSIX.1 standard. The feature test macros youhave selected (@pxref{Feature Test Macros}) determine which definitionyou get. Specifically, you get the BSD version if you define@code{_BSD_SOURCE}; otherwise, you get the POSIX version if you define@code{_POSIX_SOURCE} or @code{_GNU_SOURCE}. Programs written for oldBSD systems will not include @file{unistd.h}, which defines@code{getpgrp} specially under @code{_BSD_SOURCE}. You must link suchprograms with the @code{-lbsd-compat} option to get the BSD definition.@refill@pindex -lbsd-compat@pindex bsd-compat@cindex BSD compatibility library@comment unistd.h@comment POSIX.1@deftypefn {POSIX.1 Function} pid_t getpgrp (void)The POSIX.1 definition of @code{getpgrp} returns the process group ID ofthe calling process.@end deftypefn@comment unistd.h@comment BSD@deftypefn {BSD Function} pid_t getpgrp (pid_t @var{pid})The BSD definition of @code{getpgrp} returns the process group ID of theprocess @var{pid}. You can supply a value of @code{0} for the @var{pid}argument to get information about the calling process.@end deftypefn@comment unistd.h@comment POSIX.1@deftypefun int setpgid (pid_t @var{pid}, pid_t @var{pgid})The @code{setpgid} function puts the process @var{pid} into the processgroup @var{pgid}. As a special case, either @var{pid} or @var{pgid} canbe zero to indicate the process ID of the calling process.This function fails on a system that does not support job control.@xref{Job Control is Optional}, for more information.If the operation is successful, @code{setpgid} returns zero. Otherwiseit returns @code{-1}. The following @code{errno} error conditions aredefined for this function:@table @code@item EACCESThe child process named by @var{pid} has executed an @code{exec}function since it was forked.@item EINVALThe value of the @var{pgid} is not valid.@item ENOSYSThe system doesn't support job control.@item EPERMThe process indicated by the @var{pid} argument is a session leader,or is not in the same session as the calling process, or the value ofthe @var{pgid} argument doesn't match a process group ID in the samesession as the calling process.@item ESRCHThe process indicated by the @var{pid} argument is not the callingprocess or a child of the calling process.@end table@end deftypefun@comment unistd.h@comment BSD@deftypefun int setpgrp (pid_t @var{pid}, pid_t @var{pgid})This is the BSD Unix name for @code{setpgid}. Both functions do exactlythe same thing.@end deftypefun@node Terminal Access Functions, , Process Group Functions, Functions for Job Control@subsection Functions for Controlling Terminal AccessThese are the functions for reading or setting the foregroundprocess group of a terminal. You should include the header files@file{sys/types.h} and @file{unistd.h} in your application to usethese functions.@pindex unistd.h@pindex sys/types.hAlthough these functions take a file descriptor argument to specifythe terminal device, the foreground job is associated with the terminalfile itself and not a particular open file descriptor.@comment unistd.h@comment POSIX.1@deftypefun pid_t tcgetpgrp (int @var{filedes})This function returns the process group ID of the foreground processgroup associated with the terminal open on descriptor @var{filedes}.If there is no foreground process group, the return value is a numbergreater than @code{1} that does not match the process group ID of anyexisting process group. This can happen if all of the processes in thejob that was formerly the foreground job have terminated, and no otherjob has yet been moved into the foreground.In case of an error, a value of @code{-1} is returned. Thefollowing @code{errno} error conditions are defined for this function:@table @code@item EBADFThe @var{filedes} argument is not a valid file descriptor.@item ENOSYSThe system doesn't support job control.@item ENOTTYThe terminal file associated with the @var{filedes} argument isn't thecontrolling terminal of the calling process.@end table@end deftypefun@comment unistd.h@comment POSIX.1@deftypefun int tcsetpgrp (int @var{filedes}, pid_t @var{pgid})This function is used to set a terminal's foreground process group ID.The argument @var{filedes} is a descriptor which specifies the terminal;@var{pgid} specifies the process group. The calling process must be amember of the same session as @var{pgid} and must have the samecontrolling terminal.For terminal access purposes, this function is treated as output. If itis called from a background process on its controlling terminal,normally all processes in the process group are sent a @code{SIGTTOU}signal. The exception is if the calling process itself is ignoring orblocking @code{SIGTTOU} signals, in which case the operation isperformed and no signal is sent.If successful, @code{tcsetpgrp} returns @code{0}. A return value of@code{-1} indicates an error. The following @code{errno} errorconditions are defined for this function:@table @code@item EBADFThe @var{filedes} argument is not a valid file descriptor.@item EINVALThe @var{pgid} argument is not valid.@item ENOSYSThe system doesn't support job control.@item ENOTTYThe @var{filedes} isn't the controlling terminal of the calling process.@item EPERMThe @var{pgid} isn't a process group in the same session as the callingprocess.@end table@end deftypefun
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -