Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<h3>Theory</h3> <p><a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04" rel="nofollow">POSIX</a> says about <code>SIG_IGN</code> (strictly under the XSI extension note):</p> <blockquote> <p>If the action for the SIGCHLD signal is set to SIG_IGN, child processes of the calling processes shall not be transformed into zombie processes when they terminate. If the calling process subsequently waits for its children, and the process has no unwaited-for children that were transformed into zombie processes, it shall block until all of its children terminate, and wait(), waitid(), and waitpid() shall fail and set errno to [ECHILD].</p> </blockquote> <p>And in the description of <a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html" rel="nofollow"><code>&lt;signal.h&gt;</code></a> says that the default signal disposition for <code>SIGCHLD</code> is <s><code>SIG_IGN</code></s> 'ignore' (code 'I'). However, it is the <code>SIG_DFL</code> behaviour is to 'ignore' the signal; the signal is never generated. This is different from the <code>SIG_IGN</code> behaviour.</p> <p>So, you don't have to set a signal handler, but you shouldn't get information about the process back — you should just get an error once there are no children left.</p> <h3>Demonstration Code</h3> <pre><code>#include &lt;errno.h&gt; #include &lt;signal.h&gt; #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;string.h&gt; #include &lt;unistd.h&gt; static siginfo_t sig_info; static volatile sig_atomic_t sig_num; static void *sig_ctxt; static void catcher(int signum, siginfo_t *info, void *vp) { sig_num = signum; sig_info = *info; sig_ctxt = vp; } static void set_handler(int signum) { struct sigaction sa; sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = catcher; sigemptyset(&amp;sa.sa_mask); if (sigaction(signum, &amp;sa, 0) != 0) { int errnum = errno; fprintf(stderr, "Failed to set signal handler (%d: %s)\n", errnum, strerror(errnum)); exit(1); } } static void prt_interrupt(FILE *fp) { if (sig_num != 0) { fprintf(fp, "Signal %d from PID %d\n", sig_info.si_signo, (int)sig_info.si_pid); sig_num = 0; } } static void five_kids(void) { for (int i = 0; i &lt; 5; i++) { pid_t pid = fork(); if (pid &lt; 0) break; else if (pid == 0) { printf("PID %d - exiting with status %d\n", (int)getpid(), i); exit(i); } else { int status = 0; pid_t corpse = wait(&amp;status); printf("Child: %d; Corpse: %d; Status = 0x%.4X\n", pid, corpse, (status &amp; 0xFFFF)); prt_interrupt(stdout); fflush(0); } } } int main(void) { printf("SIGCHLD set to SIG_IGN\n"); signal(SIGCHLD, SIG_IGN); five_kids(); printf("SIGCHLD set to catcher()\n"); set_handler(SIGCHLD); five_kids(); return(0); } </code></pre> <p>The <code>fflush(0);</code> call ensures standard output (in particular) is flushed, which matters if the output of the sample program is piped to another program.</p> <h3>Example Output</h3> <p>The output from the example code agrees with the theory — but requires a little interpretation.</p> <pre><code>SIGCHLD set to SIG_IGN PID 4186 - exiting with status 0 SIGCHLD set to SIG_IGN Child: 4186; Corpse: -1; Status = 0x0000 PID 4187 - exiting with status 1 Child: 4187; Corpse: -1; Status = 0x0000 PID 4188 - exiting with status 2 Child: 4188; Corpse: -1; Status = 0x0000 PID 4189 - exiting with status 3 Child: 4189; Corpse: -1; Status = 0x0000 PID 4190 - exiting with status 4 Child: 4190; Corpse: -1; Status = 0x0000 SIGCHLD set to catcher() PID 4191 - exiting with status 0 SIGCHLD set to catcher() Child: 4191; Corpse: -1; Status = 0x0000 Signal 20 from PID 4191 Child: 4192; Corpse: 4191; Status = 0x0000 PID 4192 - exiting with status 1 Child: 4193; Corpse: 4192; Status = 0x0100 Signal 20 from PID 4192 PID 4193 - exiting with status 2 Child: 4194; Corpse: 4193; Status = 0x0200 Signal 20 from PID 4193 PID 4194 - exiting with status 3 Child: 4195; Corpse: 4194; Status = 0x0300 Signal 20 from PID 4194 PID 4195 - exiting with status 4 </code></pre> <p>The first section of the output agrees exactly with the theory; the calling code gets no information about the dead children except that there are no dead children (left) to wait for.</p> <p>The second section of the output agrees with the theory too, but it appears that the children aren't executing before the parent, so the first <code>wait()</code> from the parent has no dead children to wait for, and it returns -1. Subsequent calls get the various children, but one escapes unwaited for (but the corpse will be cleaned up by the system). If the code used <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/waitpid.html" rel="nofollow"><code>waitpid()</code></a> such as: <code>pid_t corpse = waitpid(pid, &amp;status, 0);</code>, it would wait for each child in turn.</p> <p><sup>Some of this commentary may need revision in the light of the modified comments about 'ignore' above. TBD &mdash; out of time right now.</sup></p> <p>Mac OS X 10.8.4 on 3 GHz Intel Core 2 Duo, GCC 4.6.0, 64-bit compilation:</p> <pre><code>gcc -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \ -Wold-style-definition sigchld.c -o sigchld </code></pre> <p>This was a quick adaptation of some existing code to test the behaviour of <code>SIGINT</code> and <code>pause()</code>. It may have some superfluous material in it. You do not have to call <code>wait()</code> or one of its relatives in the signal handler; you may do so if you wish, though.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload