我知道如何使用 wait_event
在 Linux 内核队列中等待以及如何唤醒它们。
现在我需要弄清楚如何同时在多个队列中等待。我需要多路复用多个事件源,基本上以类似于 poll
或 select
的方式,但由于事件源没有可轮询文件描述符的形式,我无法在这些系统调用的实现中找到灵感。
我最初的想法是从 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/