Live data from Hacker News

Signalfd is useless

ldpreload.com

21–30 of 44 posts

Re: Signalfd is useless

#21
post #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 useles…

As I mentioned in another comment, there are cases (like SIGWINCH) where the only interface the kernel gives you for general-purpose IPC is signals. In any case, if you restrict yourself to using signals for urgent respond-immediately events, then signalfd is still useless, since you want to handle those synchronously. :)

(That said, I would definitely agree that the kernel is misusing signals -- SIGWINCH should just be some form of metadata on the terminal fd, not a process-wide signal.)

Re: Signalfd is useless

#22
post #14
post #9

Earlier quoted context omitted.

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…

clonefd is a very limited solution. What we really need is the ability to open a file descriptor handle to any process. That ability solves all sorts of race conditions. Conveniently, we already have an interface to open file descriptors for processes: /proc. We just need to extend its semantics slightly.

Re: Signalfd is useless

#24
post #14

Earlier quoted context omitted.

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

clonefd is a very limited solution. What we really need is the ability to open a file descriptor handle to any process. That ability solves all sorts of race conditions. Conveniently, we already have an interface to open file descriptors for processes: /proc. We just need to extend its semantics slightly.

Maybe I'm misunderstanding, but wouldn't opening a file descriptor to a process via /proc have the same race condition issues with process id wraparound? After all, processes in /proc are opened by process ID (the only exception I can think of is /proc/self... maybe I missed some other exceptions?)

Overall, it seems easier to avoid process ID wraparound attacks via using the full 32-bit number space for PIDs. There may be a few programs that need to be changed because they did something silly like cast pid_t to short, but I think overall most programs would work just fine. As far as I can remember, the reason for using low numbers was because people didn't want to type longer ones at the shell. Internally the kernel and libraries store everything as 32-bit, at least on Linux.

Re: Signalfd is useless

#25
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…

> 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

The unfortunate terseness of the original "self-pipe trick" description makes the solution to this difficult to see. As far as I've figured out there are two things to notice:

1) You're supposed to set the pipe to be non-blocking. Presumably you also then don't check the return code of the write(2) call in the signal handler. While this solves the case of a signal handler blocking forever, it does mean you might have dropped writes that correspond to signal receptions. That leads us to:

2) The self-pipe trick specifically calls out handling SIGCHLD (probably because it's one signal that you don't want to ignore!) But given the chances of dropping a byte as described in 1) and the fact that SIGCHLD and fork are explicitly called out, I can only assume that the lesson here is: only have one pipe per signal you intend to handle. Since multiple signals sent to a process may result in a single signal being delivered, your real signal handling code (the stuff that's watching the other end of the pipe) already has to deal with this situation.

As for Capsicum, I can't wait til they implement pdwait(2)! Until then, at least pdfork(2) ensures that the parent process' death kills the child process...

[1] http://cr.yp.to/docs/selfpipe.html

Re: Signalfd is useless

#26
post #14

Earlier quoted context omitted.

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

clonefd is a very limited solution. What we really need is the ability to open a file descriptor handle to any process. That ability solves all sorts of race conditions. Conveniently, we already have an interface to open file descriptors for processes: /proc. We just need to extend its semantics slightly.

If you get a file descriptor that refers to a child process upon its creation, then that file descriptor should behave like other file descriptors.

That means you ought to be able to transfer it to other processes via file descriptor passing (the SCM_RIGHTS ancillary message; see man unix).

The identity of a process would thus be local to its parent or to a process with which the parent has agreed to share that identity. Not only does this avoid race conditions, it also enables a completely unrelated process to reap a child which can be terrifically useful.

This is exactly the approach the Capsicum sandboxing framework (mentioned elsewhere) is taking. The goal there, though, is to eliminate globally shared identifiers as much as possible -- which makes sense for sandboxing!

Re: Signalfd is useless

#27
post #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 useles…

Except you're left with cases for which there is no alternative but signals (you name one; a sibling mentions WINCH, and I'll add SIGCHILD.), and for which the only reliable way to handle the case is to use the self-pipe trick, or maybe a signalfd.

It's not a case of "misuse": the API is so truly atrociously bad that any programmers attempt is going to be wrong. I'm aware of the pitfalls, and I do not feel comfortable stating that I would get it right; someone who is not aware of the pitfalls is hopelessly screwed.

Re: Signalfd is useless

#28
If you're going to create a dedicated signal-handling thread as the author recommends (which is one of the best ways to handle signals in a pthreads application), you don't need to use signal handlers at all; you should just mask the signal(s) and have the signal-handling thread loop around sigwaitinfo().

To his broader point, the mistake is to assume you will be able to get one signal delivered per signal raised. That's just not how (classic) UNIX signals work (POSIX realtime signals are different, and are queued) - they fundamentally need to be treated as level-triggered, not edge-triggered. For the SIGCHLD example, when a SIGCHLD is recieved (no matter whether through signal handler, self-pipe trick, signalfd() or sigwaitinfo()) you need to loop around waitpid() with the WNOHANG flag until it stops returning child PID statuses.

Re: Signalfd is useless

#29
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…

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

Is this what libuv does? I'm pretty sure it reads signals using epoll on linux, so in theory - if it does it this way - this bug could be be underlying all of node.js.

Re: Signalfd is useless

#30
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.

>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 don't see how that's possible. You need to listen to at least SIGTERM, SIGINT and SIGHUP if you're going to gracefully stop.

Post reply on HN