等待隊列操作分析: 在linux驅動(dòng)程序中可以用等待隊列(wiat queue)來(lái)實(shí)現阻塞的喚醒(1)定義等待隊列頭等待隊列頭結構體的定義:struct __wait_queue_head { spinlock_t lock; //自旋鎖變量,用于在對等待隊列頭
//指向的等待隊列鏈表進(jìn)行操作時(shí)鎖上,查看哪有對lock的操作? struct list_head task_list; // 指向等待隊列的list_head};typedef struct __wait_queue_head wait_queue_head_t;#define DECLARE_WAIT_QUEUE_HEAD(name) \ \\聲明一個(gè)待隊列頭對象 name: wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)#define __WAIT_QUEUE_HEAD_INITIALIZER(name) { \\\待隊列頭的初始化: .lock = __SPIN_LOCK_UNLOCKED(name.lock), \ .task_list = { &(name).task_list, &(name).task_list } }將lock賦為unlocked,將等待隊列頭指向的等待隊列鏈表指向name,從而將等待隊列頭和
等待隊列連起來(lái);(2)等待隊列中存放的是在執行設備操作時(shí)不能獲得資源而掛起的進(jìn)程定義等待對列:struct __wait_queue { unsigned int flags; //prepare_to_wait()里有對flags的操作,查看以得出其含義#define WQ_FLAG_EXCLUSIVE 0x01 //一個(gè)常數,在prepare_to_wait()用于修改flags的值
wait_queue_func_t func; //喚醒阻塞任務(wù)的函數 struct list_head task_list; // 阻塞任務(wù)鏈表};typedef struct __wait_queue wait_queue_t;#define DECLARE_WAITQUEUE(name, tsk) \\\聲明一個(gè)等待隊列并初始化為name wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)#define __WAITQUEUE_INITIALIZER(name, tsk) { \ \\等待對列初始化: .private = tsk, \ .func = default_wake_function, \ .task_list = { NULL, NULL } }下列兩個(gè)函數用于對特定的成員進(jìn)行賦值(當傳入不同類(lèi)型的參數時(shí));static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p){ q->flags = 0; q->private = p; //私有數據指針 q->func = default_wake_function; //使用默認的喚醒函數}static inline void init_waitqueue_func_entry(wait_queue_t *q, wait_queue_func_t func){ q->flags = 0; q->private = NULL; q->func = func; // 自定義的喚醒函數}(3)對等待隊列進(jìn)行操作 static inline int waitqueue_active(wait_queue_head_t *q){ return !list_empty(&q->task_list);} 判斷等待對列頭是否為空,當一個(gè)進(jìn)程訪(fǎng)問(wèn)設備而得不到資源時(shí)就會(huì )被放入等待隊列頭指
向的等待隊列中,當該它是第一個(gè)被阻塞的進(jìn)程,(等待隊列頭是一開(kāi)始就有的還
是有了第一個(gè)被阻塞的進(jìn)程后才創(chuàng )建的?)若此時(shí)等待隊列頭還是空的,要先創(chuàng )建(見(jiàn)上面)
然后再插入新的等待隊列 。
對等待隊列的鏈表操作static inline void __add_wait_queue(wait_queue_head_t *head,\
wait_queue_t *new) /{ list_add(&new->task_list, &head->task_list);}/增加一個(gè)等待隊列new到等待
隊列頭head指向的等待隊列鏈表中;static inline void __add_wait_queue_tail(wait_queue_head_t *head, // wait_queue_t *new){ list_add_tail(&new->task_list, &head->task_list);}增加一個(gè)等待隊列到表尾 static inline void __remove_wait_queue \
(wait_queue_head_t *head,wait_queue_t *old){ list_del(&old->task_list);}刪除一個(gè)等待隊列(4)等待事件當等待隊列加入到鏈表中以后,就要等待特定的condition來(lái) 喚醒它; #define __wait_event(wq, condition) \\\wq:在等待事件的等待隊列;condition:等待的條件do { \ DEFINE_WAIT(__wait); \定義并初始化一個(gè)wait_queue_t結構 \ for (;;) { \ prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE); \ if (condition) \ //看wait_queue:wq要等的condition是否滿(mǎn)足 break; \ schedule(); \//condition不成立,放棄cpu重新調度一個(gè)task } \ finish_wait(&wq, &__wait); \} while (0)等待condition在成立,否則進(jìn)程睡眠(TASK_UNINTERRUPTIBLE);condition滿(mǎn)足
后等待結束,跳出循環(huán)(后面調用wake_up(x)進(jìn)行喚醒)當任何能改變等待條件
的值的變量發(fā)生改變時(shí),要調用wake_up();
wait_event(wq, condition) 在__wait_event()的基礎上多了一次查詢(xún)(每次被喚醒的時(shí)候)
#define __wait_event_timeout(wq, condition, ret) \
當condition滿(mǎn)足或ret使用完了時(shí)進(jìn)程被喚醒;返回值為:return timeout < 0 ? 0 : timeout
timeout是一個(gè)jiffies類(lèi)型的變量,當時(shí)間用完了,函數返回0,當等待的條件成立了,
timeout還未用完,則將最后的jiffies保留下來(lái)。類(lèi)似的操作還有:
#define __wait_event_interruptible_timeout(wq, condition, ret)
\可中斷,有超時(shí)時(shí)間的__wait_event(),當timeout長(cháng)的時(shí)間完了后,函數返回0;當時(shí)間未完,
函數被信號中斷則返回-ERESTARTSYS;如果timeout isn't out,保留jiffies最后的值;#define wait_event_interruptible_timeout(wq, condition, timeout) \
多了一次查詢(xún)
#define __wait_event_interruptible_exclusive(wq, condition, ret) \#define wait_event_interruptible_exclusive(wq, condition) \這幾個(gè)函數都有用到prepare_to_wait()下面分析一下這個(gè)函數;prepare_to_wait() 函數
void fastcall
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); //獲得自旋鎖并保存EFLAGS的值
if (list_empty(&wait->task_list)) //判斷是等待隊列是否為空:空時(shí)返回1;函數為:
//static inline int list_empty(const struct list_head *head)
__add_wait_queue(q, wait); //{ return head->next == head;}
/* 插入等待隊列中(為何空時(shí)插入,非空時(shí)不行?)
* don't alter the task state if this is just going to
* queue an async wait queue callback
*/
if (is_sync_wait(wait))
set_current_state(state); //因為非阻塞進(jìn)程訪(fǎng)問(wèn)不到設備時(shí)并不掛起,所以不改狀態(tài)
//set_current_state()->set_mb()->mb() :強制順序執行(更改狀態(tài))
//函數mb()內存柵頭文件中定義的
spin_unlock_irqrestore(&q->lock, flags);//解鎖將EFLAGS的值讀回
}
prepare_to_wait()的作用是將等待隊列插入等待隊列鏈表中,并更改等待隊列的狀態(tài)為state;
TASK_RUNNING:可運行狀態(tài)。處于該狀態(tài)的進(jìn)程可以被調度執行而成為當前進(jìn)程。
TASK_INTERRUPTIBLE:可中斷的睡眠狀態(tài)。處于該狀態(tài)的進(jìn)程在所需資源有效時(shí)被喚醒,也可以通過(guò)信號或定時(shí)中斷喚醒。
TASK_UNINTERRUPTIBLE:不可中斷的睡眠狀態(tài)。處于該狀態(tài)的進(jìn)程僅當所需資源有效時(shí)被喚醒。
TASK_ZOMBIE:僵尸狀態(tài)。表示進(jìn)程結束且已釋放資源,但其task_struct仍未釋放。
TASK_STOPPED:暫停狀態(tài)。處于該狀態(tài)的進(jìn)程通過(guò)其他進(jìn)程的信號才能被喚醒。
喚醒:
#define wake_up(x) __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1, NULL)
void fastcall __wake_up(wait_queue_head_t *q, unsigned int mode,
int nr_exclusive, void *key)
{
unsigned long flags;
spin_lock_irqsave(&q->lock, flags);
__wake_up_common(q, mode, nr_exclusive, 0, key);
spin_unlock_irqrestore(&q->lock, flags);
}
Wake_up()喚醒等待隊列中的進(jìn)程,其參數含義:
q:等待隊列;
mode:要喚醒的進(jìn)程
nr_exclusive:要喚醒的進(jìn)程數;
key:is directly passed to the wakeup function
聯(lián)系客服