Marc,

thanks for this clarification and recommendations. Unfortunately, we are not simply exec()ing in the child which is why I need to carefully analyze the boundary conditions affecting the child. As a follow-up, I have two more questions:

1) Is there a competition between signalfd and a normal signal handler or can we reliably deactivate the former by installing the latter?

Explanation: I understand that by default, libev uses signalfd if supported by the system. I am trying to understand how the system behaves when libev has applied the signalfd mechanism to a certain signal type (e.g. SIGTERM) and I at some point after that call signal(SIGTERM, SIG_DFL) or install a custom signal handler via signal(SIGTERM, handler).

You were agreeing that using signal(SIGTERM, SIG_DFL) is enough to restore the default action / deactivate a signalfd-based libev signal watcher. Why are you sure about this? I was trying to find answers to these two questions, but failed: - Does signal(SIGTERM, SIG_DFL) actually modify the signal mask and unblock SIGTERM? - Does a signal handler (or the default action) *always* take precedence over a signalfd mechanism? - Once handled in a signal handler -- is there still a chance left that a signal triggers the signalfd mechanism?

The man pages are in my opinion too vague about these things -- what I found was

Normally, the set of signals to be received via the
file descriptor should be blocked using sigprocmask(2), to prevent
the signals being handled according to their default dispositions.

(http://man7.org/linux/man-pages/man2/signalfd.2.html)

What makes it more difficult for me to understand is that libev probably performs some signal blocking around using signalfd which adds further complexity.

So, is it safe to just install a new signal handler to reliably deactivate signalfd? I need to be sure about this, since Python 2.x has no interface to directly modify the signal mask (from the 2.x docs: "There is no way to “block” signals temporarily from critical sections (since this is not supported by all Unix flavors).")


2) You wrote that "when python has created a thread before, destroying the default loop results in undefined behaviour on POSIX systems". Could you give me some key words why this is the case?


Big thanks,

Jan-Philip


On 11/22/2013 06:00 PM, Marc Lehmann wrote:
On Fri, Nov 22, 2013 at 05:24:24PM +0100, Jan-Philip Gehrcke 
<[email protected]> 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
anymore.

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 :).



_______________________________________________
libev mailing list
[email protected]
http://lists.schmorp.de/cgi-bin/mailman/listinfo/libev

Reply via email to