Why Doing I/O in Linux Is Uninterruptible

What is an uninterruptible process?

An uninterruptible process is a process which happens to be in a system call (kernel function) that cannot be interrupted by a signal.

To understand what that means, you need to understand the concept of an interruptible system call. The classic example is read(). This is a system call that can take a long time (seconds) since it can potentially involve spinning up a hard drive, or moving heads. During most of this time, the process will be sleeping, blocking on the hardware.

While the process is sleeping in the system call, it can receive a Unix asynchronous signal (say, SIGTERM), then the following happens:

  • The system call exits prematurely, and is set up to return -EINTR to user space.
  • The signal handler is executed.
  • If the process is still running, it gets the return value from the system call, and it can make the same call again.

Returning early from the system call enables the user space code to immediately alter its behavior in response to the signal. For example, terminating cleanly in reaction to SIGINT or SIGTERM.

On the other hand, some system calls are not allowed to be interrupted in this way. If the system calls stalls for some reason, the process can indefinitely remains in this unkillable state.

LWN ran a nice article that touched this topic in July.

To answer the original question:

  • How to prevent this from happening: figure out which driver is causing you trouble, and either stop using, or become a kernel hacker and fix it.

  • How to kill an uninterruptible process without rebooting: somehow make the system call terminate. Frequently the most effective manner to do this without hitting the power switch is to pull the power cord. You can also become a kernel hacker and make the driver use TASK_KILLABLE, as explained in the LWN article.

How to stop 'uninterruptible' process on Linux?

Simple answer: you cannot.

Longer answer: the uninterruptable sleep means the process will not be woken up by signals. It can be only woken up by what it's waiting for. When I get such situations eg. with CD-ROM, I usually reset the computer by using suspend-to-disk and resuming.

What happens to a signal for a process in D state (or TASK_UNINTERRUPTIBLE)?

TASK_UNINTERRUPTIBLE: The proccess is waiting on certain special cases of event, such as completion of of a disk I/O. If signal is generated (including SIGSTOP and SIGKILL) for a process in this state, then the signal is not delivered until the process emerges from this state.

Linux Process States

While waiting for read() or write() to/from a file descriptor return, the process will be put in a special kind of sleep, known as "D" or "Disk Sleep". This is special, because the process can not be killed or interrupted while in such a state. A process waiting for a return from ioctl() would also be put to sleep in this manner.

An exception to this is when a file (such as a terminal or other character device) is opened in O_NONBLOCK mode, passed when its assumed that a device (such as a modem) will need time to initialize. However, you indicated block devices in your question. Also, I have never tried an ioctl() that is likely to block on a fd opened in non blocking mode (at least not knowingly).

How another process is chosen depends entirely on the scheduler you are using, as well as what other processes might have done to modify their weights within that scheduler.

Some user space programs under certain circumstances have been known to remain in this state forever, until rebooted. These are typically grouped in with other "zombies", but the term would not be correct as they are not technically defunct.

Uninterruptible read/write calls

You can avoid EINTR from read() and write() by ensuring all your signal handlers are installed with the SA_RESTART flag of sigaction().

However this does not protect you from short reads / writes. This is only possible by putting the read() / write() into a loop (it does not require an additional buffer beyond the one that must already be supplied to the read() / write() call.)

Such a loop would look like:

/* If return value is less than `count', then errno == 0 indicates end of file,
* otherwise errno indicates the error that occurred. */
ssize_t hard_read(int fd, void *buf, size_t count)
{
ssize_t rv;
ssize_t total_read = 0;

while (total_read < count)
{
rv = read(fd, (char *)buf + total_read, count - total_read);

if (rv == 0)
errno = 0;

if (rv < 1)
if (errno == EINTR)
continue;
else
break;

total_read += rv;
}

return rv;
}

linux process waiting for I/O, its status is S+ not D?

At least, normal read() syscall is interruptible, explaining why your process is in interruptible sleep S+, and not in uninterruptible sleep. Here is one link:
What is an uninterruptable process?



Related Topics



Leave a reply



Submit