On Thu, Aug 06, 2020 at 03:10:55AM +0200, Michał Mirosław wrote:
> On Thu, Aug 06, 2020 at 02:39:42AM +0200, Michał Mirosław wrote:
> > On Thu, Aug 06, 2020 at 03:16:35AM +0300, Peter Pentchev wrote:
> > > On Thu, Aug 06, 2020 at 12:48:10AM +0200, Michał Mirosław wrote:
> > > > On Thu, Aug 06, 2020 at 12:29:36AM +0300, Peter Pentchev wrote:
> > > > > On Wed, Aug 05, 2020 at 10:52:31PM +0200, Michał Mirosław wrote:
> > > > [...]
> > > > > > Using print-debugging, I see that it stops at wait_for_child line 
> > > > > > just
> > > > > > after printing the version. It seems that something is reaping the 
> > > > > > child
> > > > > > before the main thread has a chance to wait for it.
> > > > > 
> > > > > OK, so the only thing that comes to my mind now is that you may be
> > > > > hitting a crazy, crazy race between register_child() and 
> > > > > child_reaper(),
> > > > > and I say "a crazy, crazy race", because the test has to (apparently
> > > > > reproducibly) receive the CHLD signal exactly between the check and
> > > > > the creation in register_child()'s first "$children{...} //= ...cv"
> > > > > statement.
> > > > 
> > > > Well, there is nothing that prevents SIGCHLD arriving between fork() and
> > > > register_child(). You could test this with more confidence (though not
> > > > 100%-reliably) by putting 'exit 1' just at the start of ($pid == 0) 
> > > > branch.
> > > 
> > > Nah, the problem is not just "between fork() and register_child()".
> > > It really must arrive at a very specific moment in time, because
> > > the //= operations for setting $children{$pid}{cv} try to make sure that
> > > a new value is not set (that is, a new condition variable is not
> > > created) if there already is such an element in the array. So the race
> > > is indeed between the //= in register_child() and the //= in
> > > child_reaper() - that is, child_reaper() must be invoked (SIGCHLD must
> > > arrive) *during* the execution of the //= in register_child().
> > > 
> > > Unless I'm missing something, which is not at all out of the question :)
> > 
> > The assignment seems not to be at fault (see last strace). I don't know 
> > perl's
> > internals enough to say if this statement can be interrupted visibly by a 
> > signal
> > handler (I would guess not a perl handler, though). There are two wait4() 
> > calls
> > even before child_reaper has a chance to run.
> 
> Another data point: this happens only with anyevent + libev and not with
> anyevent + libevent. The first is preferred and installed by default with
> libanyevent-perl, though.
> 
> $ dpkg -l libanyevent-perl libev-perl | cat
> Desired=Unknown/Install/Remove/Purge/Hold
> | Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
> |/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
> ||/ Name             Version      Architecture Description
> +++-================-============-============-========================================================
> ii  libanyevent-perl 7.140-3      amd64        event loop framework with 
> multiple implementations
> ii  libev-perl       4.25-1       amd64        Perl interface to libev, the 
> high performance event loop

AnyEvent's doc [1] mentions that the framework installs (or just might?) it's
own SIGCHLD handler. Maybe there are just too many handlers for SIGCHLD?

[1] https://metacpan.org/pod/AnyEvent#SIGNALS

Best Regards,
Michał Mirosław

Reply via email to