3

我正在阅读 Robert Love 的“Linux 内核开发第三版”,以大致了解 Linux 内核的工作原理..(2.6.2.3)

我对等待队列的工作方式感到困惑,例如这段代码:

    /* ‘q’ is the wait queue we wish to sleep on */ 
DEFINE_WAIT(wait);
add_wait_queue(q, &wait); 

while (!condition) { /* condition is the event that we are waiting for */
    prepare_to_wait(&q, &wait, TASK_INTERRUPTIBLE); 
    if (signal_pending(current))
        /* handle signal */ 
      schedule();
    }

finish_wait(&q, &wait);
  • 我想知道哪个进程正在运行这段代码?它是内核线程吗?这是谁的处理时间?

  • 同样在循环中,当条件仍然不满足时,我们将继续睡眠并调用调度来运行另一个进程,问题是我们什么时候回到这个循环?

  • 这本书说,当一个进程休眠时,它会从我们的运行队列中删除,否则它会被唤醒并且必须进入一个繁忙的循环......

  • 还说:“睡眠应该始终在一个循环中处理,以确保任务等待的条件确实已经发生。”

我只想知道这个循环在什么上下文中运行?

对不起,如果这是一个愚蠢的问题。我只是很难看到大图

4

2 回答 2

7

哪个进程在运行代码?调用它的进程。我不是要取笑这个问题,但要点是内核代码可以在不同的上下文中运行:要么是因为系统调用导致了这个地方,要么是因为它位于中断处理程序中,要么是因为它是一个名为的回调函数从另一个上下文(例如工作队列或计时器函数)。

由于此示例正在休眠,因此它必须在允许休眠的上下文中,这意味着它是响应系统调用或至少在内核线程中执行的。所以答案是进程时间取自调用需要休眠的内核代码的进程(或内核线程)。那是唯一允许睡觉的地方。

某些特殊情况是工作队列,它们明确用于需要休眠的函数。典型用途是将需要从禁止休眠的上下文中休眠的函数排队。在这种情况下,进程上下文是指定用于处理工作队列项的内核工作线程之一的上下文。

当 wait_queue 被唤醒时,您将返回到此循环,这取决于调用的 wake_up 函数,将队列中等待的一个任务设置为可运行或所有任务。

最重要的是,除非您对实现细节感兴趣,否则请忘记这一点。由于很多人都弄错了,而且在任何需要它的地方基本上都是一样的,所以长期以来一直有宏封装整个过程。查找 wait_event(),这就是您的示例应该真正的样子:

wait_event(q, condition);
于 2013-10-12T14:58:10.923 回答
-2

根据你的例子......我添加了评论......

注意:默认情况下创建等待队列时,它将处于睡眠状态。

DEFINE_WAIT(等待);/* 首先等待 ---> 它指向的内核全局等待队列 */

add_wait_queue(q, &wait); /* first wait ---> 它是内核全局等待队列,它使用 add_wait_queue(q, &wait); ---> 您正在添加自己的等待队列(如附加链表)*/

while (!condition) { /* 条件是我们正在等待的事件 */ /*condition --> 假设您正在使用 write 方法从用户空间获取数据(使用 __get_user())*/

prepare_to_wait(&q, &wait, TASK_INTERRUPTIBLE); 

/* 当任何有中断的wake_up_process()调用产生时,这将等待 */ if (signal_pending(current))

/* 这会持续监控当前 CPU 上是否有任何信号正在等待队列正在运行,而没有等待任何通常使用的信号 return -ERESTARTSYS; 或“中断”循环,如果中断来了,例如,SIGINT 或 SIGKILL 并完成等待队列语句以再次检查//处理信号 */

  schedule();  // Scheduling of wait queue
               // Remove from global data structure 
}

finish_wait(&q, &wait); //完成等待队列

于 2017-02-13T07:32:23.240 回答