5 ms·
Signal handlers don't have to be process-wide. See my detailed proposal for fixing the situation here: https://www.facebook.com/notes/daniel-colascione/toward-s
by quotemstr 9y ago
Signal handlers don't have to be process-wide. See my detailed proposal for fixing the situation here: https://www.facebook.com/notes/daniel-colascione/toward-shareable-posix-signals/10157129032641102/ https://www.facebook.com/notes/daniel-colascione/toward-shar...
The trouble is that nobody is actually interested in fixing the core API. When I've raised the issue (and my proposal) with libc maintainers, the response has been a bizarre insistence that signals are somehow illegitimate, that the things people do with signals are wrong, and that everyone should just stop with signals despite there being no viable replacement mechanism.
As a result of this head-in-the-sand attitude, we're left with an awful decades old signals API and an absolute mess of ad-hoc libraries (which conflict with each other) to work around the worst of the problems.
This is how good systems ossify and eventually die.
- carterschonwald 9y agoMy limited knowledge on this topic seems to indicate that some signals are per thread in terms of handler registration rather than process wide. At least if you register the handler in that thread. Am I incorrect ?
- quotemstr 9y agoSignals are process wide. There is no confusion on this subject; people who claim there is are probably thinking of the delivery of process-directed signals, which is an entirely different subject. There is no current system for which sigaction acts per thread.
- cryptonector 9y agoPOSIX is not clear on this. They are generally process-wide, but on Linux it depends on the pthread library. EDIT: What would be nice is a way to set signal disposition on a process-wide basis as a "default" that could be overridden on a per-thread basis. But there is no flag for distinguishing "the process" from "this thread" in sigaction(2). Another detail to address is what happens when you pthread_create() a new thread from a thread with signal disposition "overrides": does the new thread inherit these, or not? Another detail: on fork(), should the calling thread's disposition "overrides" become the process-wide dispositions for the new process?
- cryptonector 9y agoSignals are the weakest part of Unix/POSIX. The only sane way to portably handle signals in programs is to write(2) a byte to a "self-pipe" in the handler, which pipe is waited for in a main I/O event loop, thus turning the signal into a standard I/O event. There is no sane way to handle signals in libraries. You just have to avoid generating SIGPIPE (there are several not-very-portable ways) or hope the program ignores it. A library can risk installing a SIGPIPE handler or ignoring it, but... it is risky. What we really need to do is standardize file descriptor flags and I/O system calls that allow writing without fear of SIGPIPE, and other things which allow libraries to never have to care about signals. There's not much need to further improve signals themselves because the self-pipe trick is plenty good enough.
- quotemstr 9y agoPeople are unreasonable scared of doing things in signal handlers. It's very much not the case that the only sane thing to do is writing to a pipe --- for starters, there's an AF_UNIX socket. Or longjmp. There's a lot of bad advice floating around about what is and is not "portable" based on half-remembered bugs in old systems nobody uses anymore. Examine the situation from first principles based on the world today, not dubious advice from an irrelevant era.
- wahern 9y agoWhat people often don't understand is that a signal handler never has to return, and indeed as far as the kernel is concerned (traditionally speaking) never does return. To deliver a signal all the kernel really does is reset the program counter. Okay, that's not the whole truth--first it sets up a trampoline so that if the handler does return the program counter and stack pointer is restored, plus potentially some other magic. But the important thing is that a signal is fundamentally nothing more than an unscheduled goto, as opposed to an asynchronous call/return. This is why the kernel is never in danger of recursing and only a small, fixed amount of kernel state is needed to deliver signals (ignore real-time signals). Maintaining this O(1) space and time characteristic explains a lot about the semantics of signals, abstractly and in concrete implementations. Know this doesn't make it any less dangerous in terms of the potential pitfalls, but IMO understanding how it works can help to make it clear how signals can be usefully employed. And it also shows why simply writing to a pipe is problematic--a pipe can overflow and cause an application to miss signals that smarter code wouldn't. signalfd was born precisely because of this limitation. (Unlike BSD kqueue, signalfd only supports a single listener--including signal handlers--per signal, which means signalfd only solves the very narrow problem of overflowing a pipe.)