Linux 内核 : how to wait in multiple wait queues?

标签 linux linux-kernel kernel

我知道如何使用 wait_event 在 Linux 内核队列中等待以及如何唤醒它们。

现在我需要弄清楚如何同时在多个队列中等待。我需要多路复用多个事件源,基本上以类似于 pollselect 的方式,但由于事件源没有可轮询文件描述符的形式,我无法在这些系统调用的实现中找到灵感。

我最初的想法是从 wait_event 宏中获取代码,多次使用 DEFINE_WAIT 以及 prepare_to_wait

但是,考虑到 prepare_to_wait 的实现方式,如果多次添加相同的“等待者”,恐怕队列的内部链表会损坏(如果一个队列可能会发生这种情况导致唤醒,但不满足等待条件并重新开始等待)。

最佳答案

在多个等待队列中等待的可能场景之一:

int ret = 0; // Result of waiting; in form 0/-err.

// Define wait objects, one object per waitqueue.
DEFINE_WAIT_FUNC(wait1, default_wake_function);
DEFINE_WAIT_FUNC(wait2, default_wake_function);

// Add ourselves to all waitqueues.
add_wait_queue(wq1, &wait1);
add_wait_queue(wq2, &wait2);

// Waiting cycle
while(1) {
    // Change task state for waiting.
    // NOTE: this should come **before** condition checking for avoid races.
    set_current_state(TASK_INTERRUPTIBLE);
    // Check condition(s) which we are waiting
    if(cond) break;
    // Need to wait
    schedule();
    // Check if waiting has been interrupted by signal
    if (signal_pending(current)) {
        ret = -ERESTARTSYS;
        break;
    }               
}
// Remove ourselves from all waitqueues.
remove_wait_queue(wq1, &wait1);
remove_wait_queue(wq2, &wait2);
// Restore task state
__set_current_state(TASK_RUNNING);
// 'ret' contains result of waiting.

请注意,此场景与wait_event之一略有不同:

wait_event 使用 autoremove_wake_function 等待对象(使用 DEFINE_WAIT 创建)。此函数从 wake_up() 调用,从队列中删除等待对象。因此需要重新添加等待对象到队列每次迭代

但是在多个等待队列的情况下,不可能知道哪个等待队列被触发了。因此,遵循此策略需要在每次迭代时重新添加 每个等待对象,这是低效的。

相反,我们的场景使用 default_wake_function 作为等待对象,因此该对象不会在 wake_up() 调用时从等待队列中移除,添加等待对象就足够了在循环之前只进入队列一次。

关于Linux 内核 : how to wait in multiple wait queues?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40018689/

相关文章:

Linux Sed -e 参数

linux - bash:家园:找不到命令

linux - Linux 中的 select() 和 poll()

c - 如何将位图中的位映射到伙伴分配器中的物理页?

python - 重置 ipython 内核

java - 为什么我可以在 Linux 中成功移动正在写入的文件?

应用程序中嵌入的 Python 解释器无法加载 native 模块

linux - ARM 上的休眠 Linux

linux - 到达 fops 内部的 "write"和 "ioctl"

linux-kernel - 如何调试linux内核模块?