Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Signals do not interact gracefully with the rest of libc or the kernel, let alone concurrency. Signals can come in and interrupt kernel system calls--this is what EINTR is there for. When in the signal handler itself, the list of libc functions it is safe to call is small; the Single UNIX specification only guarantees less than 120 functions. V7 signals are not reliable and so it is dangerous to be in the signal handler for an extended period of time; but even BSD and SysV reliable signals have a list of caveats as long as my arm. The synchronous (think SIGFPE or SIGSEGV)/asynchronous (think SIGINT) distinction is an additional complication that the interface needed like it needed an additional head. And I haven't even gotten into the interactions between signals and process groups. Basically signals are a primitive, crude and dangerous form of IPC that one is nonetheless obligated to pay attention to.

As a rule of thumb I generally prefer to use signal handlers to set a small amount of global data and nothing else, and have the main interrupt loop notice and deal with the condition. It's possible to use weird siglongjmp things to get to the main loop if you are not there already, but (like longjmp in general) it is kind of weird and bizarre.



The best thing to do in a signal handler is often to write() a single byte to a pipe.

Your main loop can then notice that the other end of the pipe is readable (the main loop is normally watching file descriptors for activity anyway).


I believe this is referred to as the 'self pipe' trick. Dan Bernstein says he came up with it in 1990.

http://cr.yp.to/docs/selfpipe.html


That's a good point, and what I actually did last time this came up. signalfd on Linux just codifies this convention, but it is (particularly in evented code) an excellent idea.


I've actually done some quite intensive work with signals, but the reason I asked the question was just to make sure I wasn't missing something. Yes, it's very complicated, and if one doesn't have a complete understanding, problems can arise.

When in the signal handler itself, the list of libc functions it is safe to call is small; the Single UNIX specification only guarantees less than 120 functions.

I don't think this is precisely accurate. I think it's safe to call libc functions anywhere, but the point is that you have to ensure that non-reentrant functions are not called simultaneously by the same thread.

One way to do that is to never call those functions in a signal handler, but if you really know what you're doing (i.e., you know the signal hanlder is not interrupting the function you want to call), you can call it in the signal handler.

Does this sound right? I'm not being pedantic; I'm actually trying to make sure I have it right in my head.


The problem is that you don't know what other functions the libc function you want to call itself calls under the hood.

For example, take the classic case of printf() - sure, you might be able to guarantee that your signal handler can never interrupt an ongoing printf() call elsewhere, but what if printf() calls malloc() internally, and your signal handler has interrupted a malloc()?

That's why there's a (short) list of async-signal-safe functions in POSIX (see http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2...)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: