What is the rationale behind making I/O uninterruptible? What would be the negative consequences if a process handling I/O were allowed to handle a signal?
Any I/O is handled by a system call invoked by a process. Eventually such a system call will trickle its way down to some appropriate low-level device driver function to perform the actual I/O operation.
I/O can be tricky - to actually get data in and out of the device, various steps may need to be followed, in order and possibly with timing requirements. If these steps are not completed atomically, the next time they are tried, the device may not respond, misbehave, or even cause the system to lockup. These steps may be different and unique for each device, hence why there are so many device drivers.
A well written device driver should know how to deal with the device it's trying to service, so it should not normally experience problems unless there's a driver bug, you're using the wrong driver for the device, or the physical device is failing.
Now that I've read the book "The Design of the Unix Operating Systems" by Maurice Bach, let me answer this question by myself.
In short, making I/O uninterruptible is for the purpose of making the I/O task finish ASAP, without being interfered by signals.
Some related knowledge that I gained from the book:
- The word "uninterruptible" should refer to "uninterruptible sleep". When a process is in uninterruptible sleep, it can NOT be waked up by signals, nor would it handle signals.
- A process handles signals when: a. it is running in kernel mode and is about to return to the user mode. b. it is about to enter and leave sleep state when the sleep is interruptible.
- What happens when a sleeping process is waken up by a signal? It would handle the signal, with the default action being exiting the process. When a process is waiting for I/O completion, you of course do not want it to exit prematurely.
Some code paths in the kernel are marked uninterruptible, mostly because the code has to comply to strict timing (to answer to a device) or because it is doing something that doesn't admit interference. In Linux' case, most to the former has been pushed out to independent in-kernel treads, and the second ones have been mostly erradicated (I suspect mostly under pressure from the current multi-CPU machines). I.e., it has been some time now that I haven't seen a process in uninterruptible sleep.