Linux内核如何在中断处理期间找出要唤醒的进程?

Ric*_*ich 7 scheduling linux-kernel

我正在阅读有关章节进程调度的Linux 内核开发一书。在第 61 页的“醒来”部分,第一段内容如下:

唤醒是通过wake_up() 处理的,它唤醒在给定等待队列中等待的所有任务。Q1这是it什么?)调用 try_to_wake_up(),这将任务的(Q2哪个任务?所有唤醒任务?)状态设置为 TASK_RUNNING,调用 enqueue_task() 将任务添加到红黑树,如果被唤醒任务的优先级高于当前任务的优先级,则设置need_resched。导致事件发生的代码通常调用wake_up()本身。例如,当数据从硬盘到达时,VFS 在等待数据的进程所在的等待队列上调用wake_up()。

我对上面的内容很困惑。我就用上一段的例子,即磁盘读取数据后中断,但有更完整的画面。如果以下任何一项错误或不完整,请纠正我:

  1. 一些用户进程发出阻塞读操作,触发系统调用,该进程在内核领域。

  2. 内核设置磁盘控制器以请求所需的数据并使该进程进入睡眠状态(该进程被放入等待队列)。内核调度另一个进程运行。

  3. 发生磁盘中断。CPU 暂停当前正在执行的进程并跳转到磁盘中断处理。

  4. 磁盘控制器将在中断处理过程中的某个时间启动,将从磁盘读取的数据传输到主内存(在 CPU 的指导下或通过 DMA)

  5. (不确定,请更正)正如段落所说,VFS 在等待数据的进程所在的等待队列上调用wake_up()。

我的具体问题如下:

Q1(参考引用的段落):我假设第二句中的It指的是 function wake_up()。为什么该函数会wake_up唤醒所有任务,而不是仅仅唤醒等待此磁盘数据的任务?

Q2(参考引用的段落):try_to_wake_up()不知何故知道需要将状态设置为 TASK_RUNNING 的特定任务?或者try_to_wake_up()将所有唤醒任务的状态设置为 TASK_RUNNING?

Q3:内核有多少等待队列需要管理?如果有2个以上这样的等待队列,内核如何知道选择哪个队列,使得等待磁盘数据的进程在那个等待队列上?

Q4:现在说我们知道等待进程所在的队列。内核如何知道哪个进程正在等待来自磁盘的数据。我只能想象一些特定于请求磁盘数据的进程的信息被传递到磁盘控制器,比如进程的 PID、内存地址或其他东西。然后在完成中断处理后,磁盘控制器(或内核?)使用此信息来确定等待队列中的进程。

请帮我完成这张过程wake_up的图片!谢谢!

Gil*_*il' 8

Q1:“它”是wake_up。它唤醒所有等待磁盘数据的任务。如果他们不等待该数据,他们就不会在该队列中等待。

Q2:我不确定我是否理解这个问题。每个唤醒队列条目都包含一个指向任务的指针。try_to_wake_up接收一个指向它应该唤醒的任务的指针。每个函数调用一次。

Q3:有很多等待队列。每个可能发生的事件都有一个。磁盘驱动程序为每个磁盘请求设置一个等待队列。例如,当文件系统驱动程序想要某个磁盘块的内容时,它会向磁盘驱动程序询问该块,然后请求从发出文件系统请求的任务开始。如果对同一块的另一个请求传入而这个请求仍然未完成,则其他条目可能会被添加到等待队列中。

发生中断时,磁盘驱动程序根据硬件传递的信息确定哪个磁盘具有可用数据,并查找包含该磁盘的内核数据的数据结构以查找要填充的请求。在这个数据结构中,除其他外,还有数据要写入的位置和相应的唤醒队列,指示下一步要做什么。

Q4:进程进行系统调用,比如说读取一个文件。这会触发文件系统驱动程序中的一些代码,以确定需要从磁盘加载数据。该代码向磁盘驱动程序发出请求,并将调用进程添加到请求的等待队列中。(实际上有比这更多的层,但你明白了。)当磁盘读取完成时,等待队列事件触发,因此该进程从磁盘的等待队列中删除。等待队列事件触发的代码是文件系统驱动程序提供的一个函数,它将数据复制到进程的内存并导致read系统调用返回。