Linux内核:如何在多个等待队列中等待?

时间:2016-10-13 10:38:52

标签: linux linux-kernel kernel

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

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

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

但是,考虑到如何实现prepare_to_wait,如果多次添加相同的“服务员”,我担心队列的内部链表会被破坏(如果一个队列导致唤醒,可能会发生这种情况,但是没有满足等待条件并且正在重新开始等待。)

1 个答案:

答案 0 :(得分:2)

在几个等待中等待的可能场景之一:

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()调用的waitqueue中删除,只需将wait对象添加到队列一次就足够了周期。