在使用等待隊列的時候我們知道需要以下步驟:
1.定義並初始化一個等待隊列頭wait_queue_head_t
DECLARE_WAIT_QUEUE_HEAD(my_queue); <==> init_waitqueue_head(); + wait_queue_head_t *q;
2.調用wait_event , wait_event_interruptible , wait_event_timeout , wait_event_interruptible_timeout , wait_event_killable中的一個函數
讓進程阻塞
如何讓一個進程阻塞呢?我們看來看看wait_event的實現
#define __wait_event(wq, condition) \
do { \
DEFINE_WAIT(__wait); \
\
for (;;) { \
prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE); \
if (condition) \
break; \
schedule(); \
} \
finish_wait(&wq, &__wait); \
} while (0)
struct task的全局變量,他表示的就是當前進程。所以我們也可以將wait_queue_t當作是當前進程的一個表示。
#define DEFINE_WAIT_FUNC(name, function) \
wait_queue_t name = { \
.private = current, \
.func = function, \
.task_list = LIST_HEAD_INIT((name).task_list), \
}
struct list_head task_list將當前進程都串起來。然後調用set_current_state將當前進程設置成TASK_INTERRUPTIBLE,最後返回__wait_event判斷condition來調用
schdule()來調度別的進程,從而阻塞當前進程。
prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
{
unsigned long flags;
wait->flags &= ~WQ_FLAG_EXCLUSIVE;
spin_lock_irqsave(&q->lock, flags);
if (list_empty(&wait->task_list))
__add_wait_queue(q, wait);
set_current_state(state);
spin_unlock_irqrestore(&q->lock, flags);
}
因爲我們經常是在驅動程序中使用等待隊列,但是不同的進程打開同一個設備的時候所使用的驅動程序肯定是一個,所以我們不同進程使用在驅動程序中定義的
wait_queue_head_t是可以共享的,也就是說不同的進程使用wake_up(wait_queue_head_t)的時候是可以訪問到同一個等待隊列頭的,從而使用一個進程的某些操作來
喚醒另外的在wait_queue_head_t中阻塞進程是可以實現的。