linux
核心的等待佇列是以雙迴圈鍊錶為基礎資料結構,與程序排程機制緊密結合,能夠用於實現核心的非同步事件通知機制。
在這個鍊錶中,有兩種資料結構:
等待佇列頭(
wait_queue_head_t
)和等待佇列項(
wait_queue_t
)。等待佇列頭和等待佇列項中都包含乙個
list_head
型別的域作為
"連線件
"。它通過乙個雙鏈表和把等待tast的頭,和等待的程序列表鏈結起來。從上圖可以清晰看到。所以我們知道,如果要實現乙個等待佇列,首先要有兩個部分。佇列頭和佇列項。下面看他們的資料結構。
[cpp]view plain
copy
struct list_head ;
struct __wait_queue_head ;
typedef
struct __wait_queue_head wait_queue_head_t;
struct __wait_queue ;
所以佇列頭和佇列項是通過list_head聯絡到一起的,list_head是乙個雙向鍊錶,在linux核心中有著廣泛的應用。並且在list.h中對它有著很多的操作。
2.對列頭和佇列項的初始化:
wait_queue_head_t my_queue;
init_waitqueue_head(&my_queue);
直接定義並初始化。init_waitqueue_head()函式會將自旋鎖初始化為未鎖,等待佇列初始化為空的雙向迴圈鍊錶。
declare_wait_queue_head(my_queue);
定義並初始化
3.定義等待佇列: declare_waitqueue(name,tsk);
[cpp]view plain
copy
#define declare_waitqueue(name, tsk) /
wait_queue_t name =__waitqueue_initializer(name, tsk)
#define __waitqueue_initializer(name, tsk) , __waitqueue_debug_ini(name)}
它的解釋是:
通過declare_waitqueue巨集將等待佇列項初始化成對應的任務結構,並且用於連線的相關指標均設定為空。其中加入了除錯相關**。
程序通過執行下面步驟將自己加入到乙個等待佇列中:
1) 呼叫declare_waitqueue()建立乙個等待佇列的項;
2) 呼叫add_wait_queue()把自己加入到等待佇列中。該佇列會在程序等待的條件滿足時喚醒它。在其他地方寫相關**,在事件發生時,對等的佇列執行wake_up()操作。
3) 將程序狀態變更為: task_interruptible or task_uninterruptible。
4) 如果狀態被置為task_interruptible ,則訊號喚醒程序。即為偽喚醒(喚醒不是因為事件的發生),因此檢查並處理訊號。
5) 檢查condition是否為真,為真則沒必要休眠,如果不為真,則呼叫scheduled()。
6) 當程序被喚醒的時候,它會再次檢查條件是否為真。真就退出迴圈,否則再次呼叫scheduled()並一直重複這步操作。
7) condition滿足後,程序將自己設定為task_running 並通過remove_wait_queue()退出。
4.(從等待佇列頭中)新增/移出等待佇列
(1)add_wait_queue()函式: (2)remove_wait_queue()函式:
5.等待事件:(有條件睡眠)
1)wait_event()巨集:
[cpp]view plain
copy
#define wait_event(wq, condition) /
do while (0)
#define __wait_event_timeout(wq, condition, ret) /
do /
finish_wait(&wq, &__wait); /
} while (0)
在等待會列中睡眠直到condition為真。在等待的期間,程序會被置為task_uninterruptible進入睡眠,直到condition變數變為真。每次程序被喚醒的時候都會檢查condition的值.
(2)wait_event_interruptible()函式:
和wait_event()的區別是呼叫該巨集在等待的過程中當前程序會被設定為task_interruptible狀態.在每次被喚醒的時候,首先檢查condition是否為真,如果為真則返回,否則檢查如果程序是被訊號喚醒,會返回-erestartsys錯誤碼.如果是condition為真,則返回0.
(3)wait_event_timeout()巨集:
也與wait_event()類似.不過如果所給的睡眠時間為負數則立即返回.如果在睡眠期間被喚醒,且condition為真則返回剩餘的睡眠時間,否則繼續睡眠直到到達或超過給定的睡眠時間,然後返回0.
(4)wait_event_interruptible_timeout()巨集:
與wait_event_timeout()類似,不過如果在睡眠期間被訊號打斷則返回erestartsys錯誤碼.
(5) wait_event_interruptible_exclusive()巨集
同樣和wait_event_interruptible()一樣,不過該睡眠的程序是乙個互斥程序.
6.喚醒佇列:
(1)wake_up()函式:
喚醒等待佇列.可喚醒處於task_interruptible和task_uninteruptible狀態的程序,和wait_event/wait_event_timeout成對使用.
2)wake_up_interruptible()函式: #define wake_up_interruptible(x) __wake_up(x, task_interruptible, 1, null)
和wake_up()唯一的區別是它只能喚醒task_interruptible狀態的程序.,與wait_event_interruptible/wait_event_interruptible_timeout/ wait_event_interruptible_exclusive成對使用.
task_interruptible,允許通過傳送signal喚醒它(即可中斷的睡眠狀態);
task_uninterruptible,不接收任何 singal
7.在等待佇列上睡眠:(無條件睡眠,老核心使用,新核心建議不用)
(1)sleep_on()函式:
該函式的作用是定義乙個等待佇列(wait),並將當前程序新增到等待佇列中(wait),然後將當前程序的狀態置為task_uninterruptible,並將等待佇列(wait)新增到等待佇列頭(q)中。之後就被掛起直到資源可以獲取,才被從等待佇列頭(q)中喚醒,從等待佇列頭中移出。在被掛起等待資源期間,該程序不能被訊號喚醒。
(2)sleep_on_timeout()函式:
與sleep_on()函式的區別在於呼叫該函式時,如果在指定的時間內(timeout)沒有獲得等待的資源就會返回。實際上是呼叫schedule_timeout()函式實現的。值得注意的是如果所給的睡眠時間(timeout)小於0,則不會睡眠。該函式返回的是真正的睡眠時間。
(3)interruptible_sleep_on()函式:
該函式和sleep_on()函式唯一的區別是將當前程序的狀態置為task_interruptinle,這意味在睡眠如果該程序收到訊號則會被喚醒。
(4)interruptible_sleep_on_timeout()函式:
類似於sleep_on_timeout()函式。程序在睡眠中可能在等待的時間沒有到達就被訊號打斷而被喚醒,也可能是等待的時間到達而被喚醒。
linux 等待佇列
linux 核心的等待佇列是以雙迴圈鍊錶為基礎資料結構,與程序排程機制緊密結合,能夠用於實現核心的非同步事件通知機制。在這個鍊錶中,有兩種資料結構 等待佇列頭 wait queue head t 和等待佇列項 wait queue t 等待佇列頭和等待佇列項中都包含乙個 list head 型別的域...
Linux 等待佇列
在閱讀tun驅動時看到,有一些類似 add wait queue 的函式,這些函式正是執行等待佇列的相關操作,要說等待佇列還得從核心程序排程說起,核心排程系統內程序,分配時間片,但是有些程序如從網絡卡中讀資料,在 網絡卡有資料到達之前程序處於阻塞狀態,如果此時給相應程序分配時間片做排程,無疑是浪費系...
Linux等待佇列
等待佇列主要用於 當任務 程序 由於某個條件得不到滿足時,為避免不必要的輪詢,使得程序在等待期間進入睡眠狀態,直到等待的條件得到滿足時由核心喚醒,進入執行狀態。等待佇列是基於雙迴圈鍊錶 structlist head 來實現的,與程序排程機制緊密結合,能夠用於實現核心的非同步事件通知機制。struc...