Why is a signal watcher active after default loop destruction and re-creation?

Marc Lehmann schmorp at schmorp.de
Fri Nov 22 18:00:12 CET 2013

On Fri, Nov 22, 2013 at 05:24:24PM +0100, Jan-Philip Gehrcke <jgehrcke at googlemail.com> wrote:
> I am working on gevent/gipc and need to figure out why a libev signal
> watcher is still 'active' after destroying its originally assigned
> event loop. In the example code at the bottom of this mail, I

The simple answer is: you never stopped it. Relying on a watcher to do
something defined after its loop was destroyed is outside the scope of
guaranteed libev behaviour :)

> - in the child, the signal watcher object is magically connected to
> the new loop
> The latter surprises me.

Well, the signal watcher is not connected to the new loop. What you see is
undefined behaviour, which looks as if it were connected, but it isn't.

> I went through the libev docs again and could not really find an
> explanation.

There is no explanation in the docs because this is not defined, nor
documented, behaviour.

> What I indeed want is to "orphan" everything in the child related to
> the default loop created in the parent.

That's what is happening - orphaning isn't the same as stopping a watcher.

> However, it looks like signal watchers don't need to be re-registered,
> at least not for my test system.

Looks can be deceiving, even for your test ystem, signal watchers need to
be reregistered. Note that you probably also need to block signals until
you did so, to avoid races.

> I want to understand: why is that signal watcher still active?

There is no answer to that question, because the watcher is _not_ active

> And yes, an obvious solution would be `signal(SIGTERM, SIG_DFL);` in
> the child -- but what would the general approach be to make sure that
> previously installed watchers are not active anymore when their
> corresponding loop has been destroyed?

If overriding the signal handler isn't generic enough, the only other way
is to stop the signal watchers.

A different question is why you think you need to destroy the loop
- if you are simply going to exec() something, it would merely be
counterproductive, and there is little else you can do after fork on
modern systems (e.g. when python has created a thread before, destroying
the default loop results in undefined behaviour on POSIX systems. And when
not, you still have to take care of file descriptors that are open in your
child that can confuse your parent and lead to errors. Controlling all
this is impossible in general, and orphaned watchers are going to be the
leats of your problems :).

                The choice of a       Deliantra, the free code+content MORPG
      -----==-     _GNU_              http://www.deliantra.net
      ----==-- _       generation
      ---==---(_)__  __ ____  __      Marc Lehmann
      --==---/ / _ \/ // /\ \/ /      schmorp at schmorp.de
      -=====/_/_//_/\_,_/ /_/\_\

More information about the libev mailing list