6 ms·
>The worst bugs and races were fixed up by the BSD folks and others, but the underlying concept is an unfortunate combination of "basically irredeemable", "indi
by Qwertious 10y ago
>The worst bugs and races were fixed up by the BSD folks and others, but the underlying concept is an unfortunate combination of "basically irredeemable", "indispensable" (you have to have some kind of "kernel tells you something has happened" API, and signals are what we got) and "insidious" (thanks to EINTR). I think they're a strong candidate for "worst design decision in unix".
Suppose you were to throw the whole thing out and write a good replacement (and backwards-compatibility be damned), what would it be like?
- jbarham 10y agoFWIW Plan 9 uses what it calls a "notification" mechanism: http://plan9.bell-labs.com/magic/man2html/2/notify http://plan9.bell-labs.com/magic/man2html/2/notify
- adrianratnapala 10y agoWhile the "notification" system seems is cleaner than the signals system (and presumably avoids those races fixed by BSD) -- it does not seem fundamentally different. If I am understanding that man page correctly, it does nothing at all to fix EINTR: "If the note interrupted an incomplete system call, that call returns an error (with error string interrupted) after the process resumes."
- nitwit005 10y agoEINTR is only "needed" because of the situation where a call is made to a blocking system call like read, and a signal is received before it completes. It needs to cancel the blocking call so that it can run the signal handler. If you get rid of signals, you wouldn't need EINTR. Even with signals, what people do 99% of the time is just retry the system call immediately. It would probably have been much better to have it do so automatically by default, avoiding exposing EINTR to most users.
- JdeBP 10y ago... and, thence, SA_RESTART.
- to3m 10y agoMore on what EINTR is for: http://250bpm.com/blog:12 http://250bpm.com/blog:12
- noselasd 10y agoEINTR is retried automatically if you use sigaction() and set the SA_RESTART flag. If you use signal() instead of sigaction() it depends on your OS whether EINTR is automatically retried - never use signal(). (There's a few exceptions still - partial completed syscalls, e.g. a signal can cause read() to return partial data or sleep() to return before it should - neither case gives you EINTR though)
- adrianratnapala 10y agoYes, but how does the Plan9 "notify" mechanism help with any of that? It seems to just be a tidied up version of signals, and therefore "needs" to do EINTR in much the same way as Unix.
- reacweb 10y agoMaybe, the signal coming from another process should be handled in an independent thread (maybe created the first time a signal is raised). Something would still be needed to interrupt pending system calls.
- ktRolster 10y agosystemd? edit: Actually there are some fairly decent systems for IPC now, with the Mach kernel from CMU probably being the most popular example. Most systems with micro-kernels probably have something similar, and of course dbus is there, and Android intents. I think Applescript deserves a mention here, because although it's a rather weird language, the IPC stuff is really really easy.
- pjc50 10y agoSuppose you were to throw the whole thing out and write a good replacement (and backwards-compatibility be damned), what would it be like? Steal the best bits from Windows NT, and improve the existing mechanisms. Kill signals in their current form. Build a general-purpose notification mechanism consisting of a mutex and a message. Possibly allow a process to have more than one message queue (Windows makes this really, really easy). All IO, networking and informational signals (SIGWINCH, SIGCHLD etc) then come as messages (these may have to be fixed size, but anything from a few words to a 4k page would do). select, poll etc are replaced by waiting on a mutex. You can put all your worker threads waiting on that mutex. A message arrives. The kernel wakes one waiting thread and gives it the message (via an atomic deque-or-block syscall). You don't have to do any O(n) processing to work out which socket it relates to as the kernel has helpfully put it in the message. In the deluxe 4k page version, a 1500-byte ethernet frame arrives, is DMA'd into the top half of a page, the kernel inspects it and sets message headers to say where the data is, and hands it directly into the userspace of a waiting process. The one downside of this is that UNIX pipe programs become slightly more complicated. Rather than just doing "while(read()) write()" you'd have to switch on the type of message recieved and implement your own abnormal exit functionality. This could probably be tidied away for you inside the standard library. External process control mechanisms would have to be built for killing processes and suspend/resume.
- gpderetta 10y agoUnix already has a general notification mechanism in the form of poll and select, no need to add a new one. The problem is not all interesting events are not portably delivered via a file descriptor, but that can be more easily extended (as done by lot of unices, including linux) than coming up with a completely new primitive. But some messages really must be delivered synchronously and can't normally be queued: SIGSEGV, SIGFPE, SIGBUS, etc. There is really no way around interrupts. BTW mutexes are not for signaling. What you want for signaling in a queue are semaphores, events or condition variables (or even file descriptors, like eventfd).
- pjc50 10y agoWell, the brief was to "throw the whole thing out", including select (which is bad) and poll (which is merely adequate). The machine traps are interesting in that they should only be generated locally - there's no sensible case for injecting SIGSEGV into other processes. Arguably we should learn from Windows "structured exception handling" here. There are two sensible things to do with traps (other than sudden death): hand over to a callback of some kind (which should be told about the state of the stack), or turn into a language-native exception and throw that.
- rtpg 10y agoConsidering that you can basically establish no invariants in the signals model, to me it sounds like a cooperative model is the way to go. Have a way to poll for "outstanding" signals and deal with them accordingly, in some sort of queue (and the OS drops older messages or something, if they're important you'd deal with them). The "freeze-the-world-and-do-this-thing-instead" model seems like the best way to introduce "my entire program is now broken"-style bugs. The OS deals with interrupts but the OS is also running by itself.
- JoshTriplett 10y ago> Suppose you were to throw the whole thing out and write a good replacement (and backwards-compatibility be damned), what would it be like? Keep the "you can always kill or stop a process" provided by SIGKILL and SIGSTOP/SIGCONT, using dedicated system calls. Handle every other kind of message (from the kernel or otherwise) via file descriptors, similar to signalfd.
- JdeBP 10y agoThat's two people so far who have mentioned signalfd here, without reference to what the headlined article has to say on the matter (which, ironically, amongst other things points to https://news.ycombinator.com/item?id=9564975 https://news.ycombinator.com/item?id=9564975 on Hacker News and what it, in its turn, points to).
- gmazza 10y ago(k)dbus is the most likely replacement here and systemd is a major vehicle for its adoption beyond DBus' current niche use in Gnome.