4 ms·
I consider any uninterruptable sleep in the kernel a bug. There's no technical reason a process waiting for a resource (e.g. disk I/O) couldn't be killed on the
by ambrop7 14y ago
I consider any uninterruptable sleep in the kernel a bug. There's no technical reason a process waiting for a resource (e.g. disk I/O) couldn't be killed on the spot, leaving the resource on its own. If it can't be, it just means it hasn't been implemented in the kernel.
- dfox 14y agoIt's bug motivated by compatibility. On original 70's implementations of Unix, file system I/O mostly led to busy wait in kernel and thus was not interruptible because it was simply not possible and there were applications that relied on this behavior. On UNIX, signal received during system call generally causes the kernel to abort whatever it was doing and requires application to deal with that situation and restart the operation, implementations of stdio in libc generally do the right thing, but most applications that do filesystem I/O directly do not (and surprisingly large number of commonly used network services behave erraticaly when network write(2) is interrupted by signal). And even applications that handle -EINTR from all I/O still have places where it is not handled (allowing interruptible disk I/O will cause things like stat(2) to return EINTR). Allowing SIGKILL to work and not any other signal is ugly special case, and while generally reasonable it is still special case that is relevant for things like NFS (with modern linux NFS client allowing you to disable this behavior) and broken hardware (and then trying to recover the situation with anything other than kernel-level debugger is mostly meaningless, with power cycling being the real solution when you can do that. Accidentally we currently have similar issue on one backend server where power-cycling is not an option).
- derleth 14y ago> [Fixing the bug] was simply not possible and there were applications that relied on this behavior [so now that it's technically possible to fix it, it would break compatibility so much we actually can't fix it anyway.] I'm beginning to wonder if it's possible to design a platform complex enough to be usable without running into this problem.
- asveikau 14y ago> implementations of stdio in libc generally do the right thing Tell me, what is the "right thing" for stdio to do when it sees EINTR? It strikes me that this can't really be solved at the library level. There are times when you'll want to retry and there are times when you'll want to drop your work and surface the error to the caller. Doesn't seem to me like a library can decide which is which. Which is probably why the I/O syscalls need to surface it in the first place. (I'd argue if a library like stdio, which does nothing but wrap syscalls and buffer stuff, can decide it, then there's no need for EINTR to exist at all because the syscall could theoretically make the same decisions.)
- agwa 14y agoThe right thing is almost always to retry the syscall. Syscalls on Unix return EINTR because it makes the kernel simpler, which was a key design goal in Unix[1]. If you need to do something when a signal fires, you do it in a signal handler (relying on EINTR instead of a signal handler is error-prone because if the signal fires between syscalls you lose it). That's the theory anyways - in practice it's really hard to use signal handlers to do stuff because of things like threads and async-signal safety. There are newer syscalls like pselect() which let you atomically unblock signals, execute the syscall, and re-block the signals, meaning EINTR can be used reliably, and then there's the even newer Linux-only signalfd() syscall which lets you receive signals via a file descriptor. But stdio is still very much oriented for the older signal handler approach. [1] See the paper "The Rise of ``Worse is Better''" http://www.stanford.edu/class/cs240/readings/worse-is-better.html http://www.stanford.edu/class/cs240/readings/worse-is-better...
- asveikau 14y agoYes, I'm aware, "almost always". Not always, though. I was thinking specifically of an application that might want to use signals to cancel blocking I/O and continue running. (PS: When I wrote my reply I was also already familiar with your linked article, the challenges of signal safety, and the signalfd() syscall. Surely an interesting set of topics but I still maintain that a library doesn't really have a "good" way to deal with EINTR, especially if all it does is wrap read or write.)
- ambrop7 14y agoSIGKILL is not really a "special case", because signals are not equivalent, they have assigned semantics. SIGSTOP also can't be caught. The fact that other signals can be caught and these can't just follows from their intended purpose. If these two signals could be caught, they wouldn't be serving their purpose, and another way of forcibly killing a process would have to be devised. Could you please elaborate how fixing all uninterruptable sleeps would break existing software? Note that I'm not talking about adding any new I/O timeouts to NFS or anything else during normal operation - only that when a process receives SIGKILL it will die immediately, as opposed to when the I/O completes. But if you're sending SIGKILL you surely want the process to die.
- anonymous 14y agoSo having a system that cannot be safely shut down because someone has opened a file handle on a remote fs that became unavailable is preferable to special-casing one signal? But by all means, if the signal thing bothers you - fine, I just really want some way to stop the process. Let's add two new system calls, something like "terminate with extreme prejudice" (abbr. twep) and "unmount without mercy" (abbr. uwm).