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