SIGCHLD not received

Denis Bilenko denis.bilenko at gmail.com
Thu May 31 20:32:56 CEST 2012


On Thu, May 31, 2012 at 9:13 PM, Marc Lehmann <schmorp at schmorp.de> wrote:
>> The SIGCHLD is received, of course, but then libev fails to notify the
>> child watcher in a timely manner. Instead, it delays the notification
>> by 60 seconds (MAX_BLOCKTIME).
>
> I'll have a look, however, from looking at it, the test will always fail
> if the system is busy enough, and libev doesn't lose the signal, so
> behaviour is essentially correct. I'll see if this case can be optimised
> without drawback for other cases.

Cool, thanks.

There's another issue, in which libev does lose the signal forever. To
reproduce it, remove sleep(1) from the latest test program.

The source of the issue is a race condition between ev_feed_signal and
loop_fork(). If I block signals at the beginning of loop_fork() and
unblock them at the end I have it fixed.

Here's what I do:

diff -u -r1.442 ev.c
--- ev.c	31 May 2012 15:47:59 -0000	1.442
+++ ev.c	31 May 2012 18:22:12 -0000
@@ -467,7 +467,9 @@
 /*#define MIN_INTERVAL  0.00000095367431640625 /* 1/2**20, good till 2200 */

 #define MIN_TIMEJUMP  1. /* minimum timejump that gets detected (if
monotonic clock available) */
+#ifndef MAX_BLOCKTIME
 #define MAX_BLOCKTIME 59.743 /* never wait longer than this time (to
detect time jumps) */
+#endif

 #define EV_TV_SET(tv,t) do { tv.tv_sec = (long)t; tv.tv_usec =
(long)((t - tv.tv_sec) * 1e6); } while (0)
 #define EV_TS_SET(ts,t) do { ts.tv_sec = (long)t; ts.tv_nsec =
(long)((t - ts.tv_sec) * 1e9); } while (0)
@@ -2519,6 +2521,10 @@
 inline_size void
 loop_fork (EV_P)
 {
+  sigset_t mask, oldmask;
+  sigfillset(&mask);
+  int sigmask_error = sigprocmask(SIG_BLOCK, &mask, &oldmask);
+
 #if EV_USE_PORT
   if (backend == EVBACKEND_PORT  ) port_fork   (EV_A);
 #endif
@@ -2558,6 +2564,7 @@
     }

   postfork = 0;
+  if (!sigmask_error) sigprocmask(SIG_SETMASK, &oldmask, NULL);
 }

 #if EV_MULTIPLICITY


$ gcc -DMAX_BLOCKTIME=1 -DEV_STANDALONE=1 testsigchld4.c -o testsigchld4
$ ./testsigchld4

Setting MAX_BLOCKTIME to 1 is needed to suppress the first issue - the
two are unrelated.

Now if I run testsigchld4 it sometimes pauses for 1 second but never fails.



More information about the libev mailing list