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

Marc Lehmann schmorp at schmorp.de
Wed Nov 27 05:54:12 CET 2013

On Tue, Nov 26, 2013 at 06:59:41PM +0100, Jan-Philip Gehrcke <jgehrcke at googlemail.com> wrote:
> 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.

That's what I pointed out in my previous mail - there is pretty little
you can do after fork that doesn't more or less directly involve exec
(for example, in general you cannot call malloc after fork), so you might
wonder whether what you are trying to accomplish evenc an be accomplished.

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

I am not sure what you mesan with that, but that should be documented in
the signalfd manpage. I don't think there is any competition going on,
both mechanisms continue to work. They certainly don't deactivate each
other though.

> Explanation: I understand that by default, libev uses signalfd if

Actually, it uses sigaction.

> You were agreeing that using signal(SIGTERM, SIG_DFL) is enough to
> restore the default action / deactivate a signalfd-based libev signal
> watcher.

Again, I am not sure what you mean with activate/deactivate - signalfd
doesn't need to be activated in the kernel. In general, when you ask libev
to use signalfd, libev blocks the signals you register.

> Why are you sure about this? I was trying to find answers to
> these two questions, but failed:

signal(SIGTERM, SIG_DFL) will always restore the default action, whether
the signal is blocked or not.

> - Does signal(SIGTERM, SIG_DFL) actually modify the signal mask and
> unblock SIGTERM?

It mustn't.

> - Does a signal handler (or the default action) *always* take
> precedence over a signalfd mechanism?

The concept of precedence is the wrong concept to apply. Signals delivered
to a thread will use the first mechanism that handles them.

> - Once handled in a signal handler -- is there still a chance left
> that a signal triggers the signalfd mechanism?

You'd have to ask the linux developers on that. I would hope not so, but
experience with similar mechanisms such as epoll shows that there are high
chances to run into a lot of bugs.

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

I tend to agree :)

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

Well, it simply blocks those signals it is told to handle when using
signalfd. It also unblocks signals it is told to handle when not using
signalfd, unless you configure the loop with EVFLAG_NOSIGMASK.

> So, is it safe to just install a new signal handler to reliably
> deactivate signalfd?

Since signalfd is not activated, yes. If you use signalfd and the signals
are blocked, though, then you need to unblock them.

> 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?

libev might want to allocate memory (and usually uss malloc), which isn't
an async-signal-safe function, the only functions safe to be called after
fork in this case. In general, libev itself isn't async-signal-safe (with
the exception of ev_async_send).

That's just one of the many thread-related problems (in general, you
cannot use mutexes after fork either).

There are many non-thread-related issues as well (keeping fd's open that
should be closed for example - if you run a webserver in the parent it
might malfunction on fork for example, threads or not), and there is no
way to reliably close those fds - exec is your closest bet, because it
closes both the unneeeded fdds and makes sure nothing relies on them any

libev is likely going to be your smallest problem - depending on what you are
trying to accomplish in the child, you are attwempting to go with your head
through the wall, and libev is likely your smallest problem then.

                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