Live data from Hacker News

Signalfd is useless

ldpreload.com

11–20 of 44 posts

Re: Signalfd is useless

#11
post #5
post #4

Earlier quoted context omitted.

Yup. A lot of people, myself included, were under the impression that signalfd takes over from the normal signal-handling pathway: it doesn't. It's particularly bad because the only way to get notified on a child exiting, in an event-handling architecture, is to wait for SIGCHLD notifications. (You can't call wait/waitpid because that's blocking; at best you can call it in a separate thread.) So even if all you're tr…

Both wait() and waitpid() have a non-blocking mode (WNOHANG). So use SIGCHLD to decide when to check the status of the child processes, and waitpid() to actually do it.

There is a not-so-nice but very effective trick: Send the process you wish to check for a signal of '0' (using kill(pid, 0)), if that fails the process no longer exists.

This is kind of nasty in case your pids tick over very fast so you'd have to do this with a fairly high frequency to make sure you don't hit the same pid twice.

Fortunately this is hardly ever a problem but it is something worth thinking about when using the trick.

See also:

http://unixhelp.ed.ac.uk/CGI/man-cgi?kill+2

No actual signal is sent, it's just asking the kernel to check if the signal could have been sent.

Re: Signalfd is useless

#12
Another weirdness about signalfd: read() from a signalfd returns signals for the calling process, regardless of what process created the signalfd (e.g. it could have been inherited through fork()). That's arguably usually what you want, but is inconsistent with usual file descriptor semantics, which say that it doesn't matter who read()s.

One place where the inconsistency gets weird is when you use signalfd with epoll. The epoll will flag events on the signalfd based on the process where the signalfd was registered with epoll, not the process where the epoll is being used. One case where this can be surprising is if you set up a signalfd and an epoll and then fork() for the purpose of daemonizing -- now you will find that your epoll mysteriously doesn't deliver any events for the signalfd despite the signalfd otherwise appearing to function as expected. That took me a day or two to debug. :(

With all that said, at the end of the day I disagree with Geoff. I would rather use signalfd than signal handlers. The "self-pipe trick" is ugly, involves a lot of unnecessary overhead, and runs the risk of deadlocking if you receive enough signals to fill the pipe buffer before you read them back (which can be solved with additional synchronization, but ick). In fact, in my own code, on systems that don't have signalfd or any similar mechanism, I tend to block signals except when I'm about to call poll(), and then siglongjmp() out of the signal handler to avoid the usual race condition. (See pselect(2) for discussion of said race condition.)

I think it's just a fact of life that you need to clear your signal mask between fork() and exec(), and yeah no one does this, whoops.

BTW, for the specific problem of dealing with child processes, I really hope Linux adopts the Capsicum interface as FreeBSD has:

https://www.freebsd.org/cgi/man.cgi?query=pdfork&sektion=2

Until then, you simply can't expect to reap children via signals. You use the signal to let you know that it's time to call wait().

Re: Signalfd is useless

#13
post #7

Question from someone not knowing much about low-level programming and dealing with signals: If signals are so problematic, why rely on them? Is the functionality useful for other things other than dealing with 'emergencies'? One thing I can see that is useful, is that it allows a program to gracefully deal with a kill, but many applications seem to have a 'graceful stop' mechanism that doesn't need signals.

I think geofft's answer is a good one, but I wanted to add a different point: you can't not deal with signals. They're going to happen, and even if you block or ignore them, that doesn't change the fact that something happened that may be important to your process. That's just the rules of the game.

Re: Signalfd is useless

#14
post #9
post #7

Question from someone not knowing much about low-level programming and dealing with signals: If signals are so problematic, why rely on them? Is the functionality useful for other things other than dealing with 'emergencies'? One thing I can see that is useful, is that it allows a program to gracefully deal with a kill, but many applications seem to have a 'graceful stop' mechanism that doesn't need signals.

A lot of functionality is only available via signals. For instance, there's no way other than SIGCHLD to be asynchronously notified when a process exits (unless you want to dedicate a thread to running wait()). There's no way other than SIGWINCH to be notified when your terminal gets resized. You could certainly imagine some kernel extensions that take all of this useful functionality and make it available in ways ot…

> You could certainly imagine some kernel extensions that take all of this useful functionality and make it available in ways other than signals, leaving just signals for things you have to deal with immediately like SIGSEGV (so you can print a nice error message before quitting), but they don't exist yet.

In the SIGCHLD case, there's a proposed CLONE_FD flag to clone which would return a file descriptor instead of a PID. This fd could be read poll'd on and read from, which is much nicer than dealing with SIGCHLD. See http://lwn.net/Articles/638613/

So those kernel extensions are happening :)

Re: Signalfd is useless

#15
post #12

Another weirdness about signalfd: read() from a signalfd returns signals for the calling process, regardless of what process created the signalfd (e.g. it could have been inherited through fork()). That's arguably usually what you want, but is inconsistent with usual file descriptor semantics, which say that it doesn't matter who read()s. One place where the inconsistency gets weird is when you use signalfd with epol…

> BTW, for the specific problem of dealing with child processes, I really hope Linux adopts the Capsicum interface as FreeBSD has:

> https://www.freebsd.org/cgi/man.cgi?query=pdfork&sektion=2

Whoops, I mentioned this in another comment and missed this, but see http://lwn.net/Articles/638613/

Re: Signalfd is useless

#16
post #12

Another weirdness about signalfd: read() from a signalfd returns signals for the calling process, regardless of what process created the signalfd (e.g. it could have been inherited through fork()). That's arguably usually what you want, but is inconsistent with usual file descriptor semantics, which say that it doesn't matter who read()s. One place where the inconsistency gets weird is when you use signalfd with epol…

Does running the self-pipe trick on a separate thread solve that issue? It seems like it's basically equivalent to signalfd (neither worse nor better, unless you're worried about platform-specific thread bugs): you end up with a signal mask on your main thread, but you also avoid EINTR on your main thread. Any possible pipe lockup just happens on the signal-handling thread, so the mainloop can keep running and eventually dequeue signals.

Re: Signalfd is useless

#17
post #16
post #12

Another weirdness about signalfd: read() from a signalfd returns signals for the calling process, regardless of what process created the signalfd (e.g. it could have been inherited through fork()). That's arguably usually what you want, but is inconsistent with usual file descriptor semantics, which say that it doesn't matter who read()s. One place where the inconsistency gets weird is when you use signalfd with epol…

Does running the self-pipe trick on a separate thread solve that issue? It seems like it's basically equivalent to signalfd (neither worse nor better, unless you're worried about platform-specific thread bugs): you end up with a signal mask on your main thread, but you also avoid EINTR on your main thread. Any possible pipe lockup just happens on the signal-handling thread, so the mainloop can keep running and eventu…

> Does running the self-pipe trick on a separate thread solve that issue?

Perhaps but then you're mixing signals and threads and you're in for a whole new world of hurt. :)

E.g. I've found that OSX does not always behave correctly when delivering signals to a process where one thread has blocked the signal but another hasn't, though I cannot remember the exact details. And of course on any system there is such a thing as signals addressed to a specific thread rather than a whole process (ptherad_kill()).

Re: Signalfd is useless

#18
post #17
post #16

Earlier quoted context omitted.

Does running the self-pipe trick on a separate thread solve that issue? It seems like it's basically equivalent to signalfd (neither worse nor better, unless you're worried about platform-specific thread bugs): you end up with a signal mask on your main thread, but you also avoid EINTR on your main thread. Any possible pipe lockup just happens on the signal-handling thread, so the mainloop can keep running and eventu…

> Does running the self-pipe trick on a separate thread solve that issue? Perhaps but then you're mixing signals and threads and you're in for a whole new world of hurt. :) E.g. I've found that OSX does not always behave correctly when delivering signals to a process where one thread has blocked the signal but another hasn't, though I cannot remember the exact details. And of course on any system there is such a thin…

I've heard claims of badness with signals and threads, but I've failed to track down concrete problems -- I would really like to know what they are. Meanwhile I've heard of people successfully using dedicated signal-handling threads in production, at least on Linux.

I'm not really sure that thread-directed signals are in scope for the sorts of things where you must use signals (SIGINT, SIGTSTP, etc. from a terminal, SIGCHLD from child termination, etc.) Those should all be process-directed. If you design your own API that involves signals, then sure, but that's a problem of your own making.

Re: Signalfd is useless

#19
post #4
post #2

Money quote seems to be: > So you have to be very careful to reset any masked signals before starting a child process I don't see what this has to do with signalfd. That statement is true generically. Non-default Unix signal handling and subprocess management have never cooperated cleanly. The point to signalfd is to provide a simpler mechanism to integrate signals (which are a legacy API in almost all cases) with ex…

Yup. A lot of people, myself included, were under the impression that signalfd takes over from the normal signal-handling pathway: it doesn't. It's particularly bad because the only way to get notified on a child exiting, in an event-handling architecture, is to wait for SIGCHLD notifications. (You can't call wait/waitpid because that's blocking; at best you can call it in a separate thread.) So even if all you're tr…

I'm now wondering how it would be if we just gave up on the whole thing and stole the Windows WaitForMultipleObjects() semantics.

Re: Signalfd is useless

#20
If you misuse signals.

I am rusty on low level programming but I have done enough to know that this poster is whining a bit too much.

Signals should only be used in the general case for exceptional circumstances, like killing a programme. A signal handler's job is to deal with the crisis, e.g., gracefully exit.

In lower level cases signals mean there is an urgent event, something that must be done now or it is useless to bother.

If you try to use signals for general purpose IPC then you get what you deserve - chaos.

Post reply on HN