在
Linux中,当您进行阻止i / o调用(如读取或接受)时,实际发生了什么?
我的想法:进程从运行队列中取出,在某个等待队列上进入等待或阻塞状态.然后当建立tcp连接(用于接受)或硬盘驱动器准备就绪或读取文件时,会引发硬件中断,让那些进程等待唤醒并运行(在文件读取的情况下,如何linux知道要唤醒什么进程,因为可能有很多进程在等待不同的文件?).或者也许不是硬件中断,单个进程本身轮询以检查可用性.不确定,有帮助吗?
解决方法
每个Linux设备的实现似乎略有不同,并且随着更安全/更快的内核功能的添加,首选方式似乎每个Linux版本都有所不同,但通常:
>设备驱动程序创建读取和
为设备写入等待队列.
>任何想要等待的进程线程
对于i / o是适当的
等待队列.发生中断时
处理程序唤醒一个或多个
等待线程. (显然是
因为我们处于中断状态,所以线程不会立即运行
上下文,但被添加到
内核的调度队列).
>当由内核安排时
线程检查以查看条件
它是正确的 – 如果没有的话
它回到等待队列上.
一个典型的例子(略微简化):
在初始化的驱动程序中:
init_waitqueue_head(&readers_wait_q);
在驱动程序的读取功能中:
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);
那么中断处理程序就会发出:
wake_up_interruptible(&readers_wait_q);
请注意,wait_event_interruptible()是一个宏,它隐藏了一个检查条件的循环 – 在这种情况下为read_avail!= 0 – 如果条件不为真,则在被唤醒时重复添加到等待队列.
如上所述,有许多变体 – 主要的一个变量是,如果中断处理程序可能需要做很多工作,那么它会自行完成最小工作并将其余部分推迟到工作队列或tasklet(通常称为“下半部分”)这就是唤醒等待的线程.
有关更多详细信息,请参阅Linux设备驱动程序书
http://lwn.net/Kernel/LDD3