blob: 8a39351bb06df942ce99d45445c247b6355f40c8 [file] [log] [blame]
<html lang="en">
<head>
<title>Stopped and Terminated Jobs - The GNU C Library</title>
<meta http-equiv="Content-Type" content="text/html">
<meta name="description" content="The GNU C Library">
<meta name="generator" content="makeinfo 4.13">
<link title="Top" rel="start" href="index.html#Top">
<link rel="up" href="Implementing-a-Shell.html#Implementing-a-Shell" title="Implementing a Shell">
<link rel="prev" href="Foreground-and-Background.html#Foreground-and-Background" title="Foreground and Background">
<link rel="next" href="Continuing-Stopped-Jobs.html#Continuing-Stopped-Jobs" title="Continuing Stopped Jobs">
<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
<!--
This file documents the GNU C library.
This is Edition 0.12, last updated 2007-10-27,
of `The GNU C Library Reference Manual', for version
2.8 (Sourcery G++ Lite 2011.03-41).
Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002,
2003, 2007, 2008, 2010 Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; with the
Invariant Sections being ``Free Software Needs Free Documentation''
and ``GNU Lesser General Public License'', the Front-Cover texts being
``A GNU Manual'', and with the Back-Cover Texts as in (a) below. A
copy of the license is included in the section entitled "GNU Free
Documentation License".
(a) The FSF's Back-Cover Text is: ``You have the freedom to
copy and modify this GNU manual. Buying copies from the FSF
supports it in developing GNU and promoting software freedom.''-->
<meta http-equiv="Content-Style-Type" content="text/css">
<style type="text/css"><!--
pre.display { font-family:inherit }
pre.format { font-family:inherit }
pre.smalldisplay { font-family:inherit; font-size:smaller }
pre.smallformat { font-family:inherit; font-size:smaller }
pre.smallexample { font-size:smaller }
pre.smalllisp { font-size:smaller }
span.sc { font-variant:small-caps }
span.roman { font-family:serif; font-weight:normal; }
span.sansserif { font-family:sans-serif; font-weight:normal; }
--></style>
<link rel="stylesheet" type="text/css" href="../cs.css">
</head>
<body>
<div class="node">
<a name="Stopped-and-Terminated-Jobs"></a>
<p>
Next:&nbsp;<a rel="next" accesskey="n" href="Continuing-Stopped-Jobs.html#Continuing-Stopped-Jobs">Continuing Stopped Jobs</a>,
Previous:&nbsp;<a rel="previous" accesskey="p" href="Foreground-and-Background.html#Foreground-and-Background">Foreground and Background</a>,
Up:&nbsp;<a rel="up" accesskey="u" href="Implementing-a-Shell.html#Implementing-a-Shell">Implementing a Shell</a>
<hr>
</div>
<h4 class="subsection">27.6.5 Stopped and Terminated Jobs</h4>
<p><a name="index-stopped-jobs_002c-detecting-3222"></a><a name="index-terminated-jobs_002c-detecting-3223"></a>When a foreground process is launched, the shell must block until all of
the processes in that job have either terminated or stopped. It can do
this by calling the <code>waitpid</code> function; see <a href="Process-Completion.html#Process-Completion">Process Completion</a>. Use the <code>WUNTRACED</code> option so that status is reported
for processes that stop as well as processes that terminate.
<p>The shell must also check on the status of background jobs so that it
can report terminated and stopped jobs to the user; this can be done by
calling <code>waitpid</code> with the <code>WNOHANG</code> option. A good place to
put a such a check for terminated and stopped jobs is just before
prompting for a new command.
<p><a name="index-g_t_0040code_007bSIGCHLD_007d_002c-handling-of-3224"></a>The shell can also receive asynchronous notification that there is
status information available for a child process by establishing a
handler for <code>SIGCHLD</code> signals. See <a href="Signal-Handling.html#Signal-Handling">Signal Handling</a>.
<p>In the sample shell program, the <code>SIGCHLD</code> signal is normally
ignored. This is to avoid reentrancy problems involving the global data
structures the shell manipulates. But at specific times when the shell
is not using these data structures&mdash;such as when it is waiting for
input on the terminal&mdash;it makes sense to enable a handler for
<code>SIGCHLD</code>. The same function that is used to do the synchronous
status checks (<code>do_job_notification</code>, in this case) can also be
called from within this handler.
<p>Here are the parts of the sample shell program that deal with checking
the status of jobs and reporting the information to the user.
<pre class="smallexample"> /* <span class="roman">Store the status of the process </span><var>pid</var><span class="roman"> that was returned by waitpid.</span>
<span class="roman">Return 0 if all went well, nonzero otherwise.</span> */
int
mark_process_status (pid_t pid, int status)
{
job *j;
process *p;
if (pid &gt; 0)
{
/* <span class="roman">Update the record for the process.</span> */
for (j = first_job; j; j = j-&gt;next)
for (p = j-&gt;first_process; p; p = p-&gt;next)
if (p-&gt;pid == pid)
{
p-&gt;status = status;
if (WIFSTOPPED (status))
p-&gt;stopped = 1;
else
{
p-&gt;completed = 1;
if (WIFSIGNALED (status))
fprintf (stderr, "%d: Terminated by signal %d.\n",
(int) pid, WTERMSIG (p-&gt;status));
}
return 0;
}
fprintf (stderr, "No child process %d.\n", pid);
return -1;
}
else if (pid == 0 || errno == ECHILD)
/* <span class="roman">No processes ready to report.</span> */
return -1;
else {
/* <span class="roman">Other weird errors.</span> */
perror ("waitpid");
return -1;
}
}
/* <span class="roman">Check for processes that have status information available,</span>
<span class="roman">without blocking.</span> */
void
update_status (void)
{
int status;
pid_t pid;
do
pid = waitpid (WAIT_ANY, &amp;status, WUNTRACED|WNOHANG);
while (!mark_process_status (pid, status));
}
/* <span class="roman">Check for processes that have status information available,</span>
<span class="roman">blocking until all processes in the given job have reported.</span> */
void
wait_for_job (job *j)
{
int status;
pid_t pid;
do
pid = waitpid (WAIT_ANY, &amp;status, WUNTRACED);
while (!mark_process_status (pid, status)
&amp;&amp; !job_is_stopped (j)
&amp;&amp; !job_is_completed (j));
}
/* <span class="roman">Format information about job status for the user to look at.</span> */
void
format_job_info (job *j, const char *status)
{
fprintf (stderr, "%ld (%s): %s\n", (long)j-&gt;pgid, status, j-&gt;command);
}
/* <span class="roman">Notify the user about stopped or terminated jobs.</span>
<span class="roman">Delete terminated jobs from the active job list.</span> */
void
do_job_notification (void)
{
job *j, *jlast, *jnext;
process *p;
/* <span class="roman">Update status information for child processes.</span> */
update_status ();
jlast = NULL;
for (j = first_job; j; j = jnext)
{
jnext = j-&gt;next;
/* <span class="roman">If all processes have completed, tell the user the job has</span>
<span class="roman">completed and delete it from the list of active jobs.</span> */
if (job_is_completed (j)) {
format_job_info (j, "completed");
if (jlast)
jlast-&gt;next = jnext;
else
first_job = jnext;
free_job (j);
}
/* <span class="roman">Notify the user about stopped jobs,</span>
<span class="roman">marking them so that we won't do this more than once.</span> */
else if (job_is_stopped (j) &amp;&amp; !j-&gt;notified) {
format_job_info (j, "stopped");
j-&gt;notified = 1;
jlast = j;
}
/* <span class="roman">Don't say anything about jobs that are still running.</span> */
else
jlast = j;
}
}
</pre>
</body></html>