Linux阻止I/O实际上如何工作?

tgg*_*guy 8 linux blocking linux-kernel

在Linux中,当您进行阻止i/o调用(如读取或接受)时,实际发生了什么?

我的想法:进程从运行队列中取出,在某个等待队列上进入等待或阻塞状态.然后当建立tcp连接(用于接受)或硬盘驱动器准备就绪或读取文件时,会引发硬件中断,让那些进程等待唤醒并运行(在文件读取的情况下,如何linux知道要唤醒什么进程,因为可能有很多进程在等待不同的文件?).或者也许不是硬件中断,单个进程本身轮询以检查可用性.不确定,有帮助吗?

Dip*_*ick 13

每个Linux设备的实现似乎略有不同,并且随着更安全/更快的内核功能的添加,首选方式似乎每个Linux版本都有所不同,但通常:

  1. 设备驱动程序为设备创建读写等待队列.
  2. 任何想要等待i/o的进程线程都被放在适当的等待队列中.当发生中断时,处理程序唤醒一个或多个等待线程.(显然,线程不会立即运行,因为我们处于中断上下文中,但是被添加到内核的调度队列中).
  3. 当内核调度时,线程会检查条件是否适合继续 - 如果不是,它会返回等待队列.

一个典型的例子(略微简化):

在初始化的驱动程序中:

    init_waitqueue_head(&readers_wait_q);
Run Code Online (Sandbox Code Playgroud)

在驱动程序的读取功能中:

    if (filp->f_flags & O_NONBLOCK)
    {
        return -EAGAIN;
    }
    if (wait_event_interruptible(&readers_wait_q, read_avail != 0))
    {
        /* signal interrupted the wait, return */
        return -ERESTARTSYS;
    }
    to_copy = min(user_max_read, read_avail);
    copy_to_user(user_buf, read_ptr, to_copy);
Run Code Online (Sandbox Code Playgroud)

那么中断处理程序就会发出:

    wake_up_interruptible(&readers_wait_q);
Run Code Online (Sandbox Code Playgroud)

请注意,wait_event_interruptible()是一个宏,它隐藏了一个检查条件的循环 - read_avail != 0在这种情况下 - 如果条件不为真,则重复添加到等待队列.

如上所述,有许多变体 - 主要的一个变量是,如果中断处理程序可能需要做很多工作,那么它会自行完成最小工作并将其余部分推迟到工作队列或tasklet(通常称为"下半部分")这就是唤醒等待的线程.

有关更多详细信息,请参阅Linux设备驱动程序一书 - pdf可在此处获取:http: //lwn.net/Kernel/LDD3


S.L*_*ott -1

阅读此内容: http: //www.minix3.org/doc/

这是一个非常、清晰、非常容易理解的解释。它通常也适用于 Linux。