源出處:http://www.startos.com/linux/tips/2011011921499_2.html
全域或者在棧中定義一個wait_queue_t類型變數的同時對其初始化,這保證了系統的可靠性,避免因使用者忘記初始化時導致的問題。通用的初始化宏,tsk為任意指標。分兩步:
1) 內部宏__WAITQUEUE_INITIALIZER初始化相應成員;當wq內嵌在別的結構體中時,此宏很重要,提高了可移植性;
2) 提供給外部的介面,定義一個變數,並將第一步的結果賦值給該變數。
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;
}
動態初始化一個等待隊列入口項,將其和當前進程關聯起來,以便喚醒當前進程。
2.1.3 資料結構設計規則
今後凡遇到新設計一類結構體,若此類結構體變數必須初始化且有相對集中的操作,則應提供以下兩個操作介面:
a) 定義建立一個結構體變數,並初始化之;
b) 動態初始化一個已經分配記憶體的該類變數
為了適應在堆棧及全域等任意地方分配的該變數,其應該接收指向該類變數的指標。
2.2 陳舊sleep_on系列
//初始化一個wait_queue_t
#define SLEEP_ON_VAR \
unsigned long flags; \
wait_queue_t wait; \
init_waitqueue_entry(&wait, current);
//添加到隊列中
#define SLEEP_ON_HEAD \
spin_lock_irqsave(&q->lock,flags); \
__add_wait_queue(q, &wait); \
spin_unlock(&q->lock);
//從隊列中刪除
#define SLEEP_ON_TAIL \
spin_lock_irq(&q->lock); \
__remove_wait_queue(q, &wait); \
spin_unlock_irqrestore(&q->lock, flags);
SLEEP_ON_VAR、 SLEEP_ON_HEAD及SLEEP_ON_ TAIL總是同時出現,不可分割。上述宏不是函數,只是連續的運算式而已,因為函數就將他們隔離開來了,函數他退出後變數就無意義了。也不能寫成 do――while的多語句宏,變數定義離開“{}”後就沒有意義了。是為了編寫代碼更清晰明了,同時避免多寫字,實際上就是代碼封裝複用。
void fastcall __sched interruptible_sleep_on(wait_queue_head_t *q)
{
SLEEP_ON_VAR //注意沒“;”
current->state = TASK_INTERRUPTIBLE;
SLEEP_ON_HEAD
schedule(); //此處可能出問題
SLEEP_ON_TAIL
}
EXPORT_SYMBOL(interruptible_sleep_on);
添加到隊列和從隊列中刪除由同一個模組做,符合模組設計規則,減小了耦合性。
喚醒的wakeup只負責改變進程狀態,進程重新獲得cpu後從隊列中刪除。
long fastcall __sched
interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout)
{
SLEEP_ON_VAR
current->state = TASK_INTERRUPTIBLE;
SLEEP_ON_HEAD
timeout = schedule_timeout(timeout);
SLEEP_ON_TAIL
return timeout;
}
EXPORT_SYMBOL(interruptible_sleep_on_timeout);
void fastcall __sched sleep_on(wait_queue_head_t *q)
{
SLEEP_ON_VAR
current->state = TASK_UNINTERRUPTIBLE;
SLEEP_ON_HEAD
schedule();
SLEEP_ON_TAIL
}
EXPORT_SYMBOL(sleep_on);
long fastcall __sched sleep_on_timeout(wait_queue_head_t *q, long timeout)
{
SLEEP_ON_VAR
current->state = TASK_UNINTERRUPTIBLE;
SLEEP_ON_HEAD
timeout = schedule_timeout(timeout);
SLEEP_ON_TAIL
return timeout;
}
EXPORT_SYMBOL(sleep_on_timeout);