wait_queue_head_t和wait_queue_t 聯繫

在使用等待隊列的時候我們知道需要以下步驟:


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)


這裏面我們看到有一句DEFINE_WAIT(__wait);他的最終調用如下,我們看到這裏面其實就是定義了一個wait_queue_t的變量,其中.private = current .這個current是一個

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),	\
	}


我們來繼續看wait_event中的prepare_to_wait函數的實現,我們看到調用__add_wait_queue將當前進程加入到一個wait_queue_head_t的等待隊列頭裏面,利用裏面的

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中阻塞進程是可以實現的。




發佈了39 篇原創文章 · 獲贊 30 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章