25 struct completion { 26 unsigned int done; //決定進程是否睡眠等待 27 wait_queue_head_t wait; //進程在此睡眠等待 28 };
睡眠等待:
91 extern void wait_for_completion(struct completion *);
92 extern void wait_for_completion_io(struct completion *);
93 extern int wait_for_completion_interruptible(struct completion *x);
94 extern int wait_for_completion_killable(struct completion *x);
95 extern unsigned long wait_for_completion_timeout(struct completion *x,
96 unsigned long timeout);
97 extern unsigned long wait_for_completion_io_timeout(struct completion *x,
98 unsigned long timeout);
99 extern long wait_for_completion_interruptible_timeout(
100 struct completion *x, unsigned long timeout);
101 extern long wait_for_completion_killable_timeout(
102 struct completion *x, unsigned long timeout);
以上函數實際都會調用wait_for_common()--->do_wait_for_common()
喚醒:
106 extern void complete(struct completion *); //completion->done +1,一次只滿足一個進程
107 extern void complete_all(struct completion *);//completion->done增幅很大, 進程不會再進入睡眠.
* 以上函數實際都會調用__wake_up_common()
不管是執行complete(x)還是wait_for_completion(x)都必須要搶佔x->wait.lock. 因此可能出現這種情況:x->done爲0.當進程A執行wait_for_completion(x)後等待x而進入睡眠。進程B執行了complete()後喚醒了進程A。但是在進程A搶佔x->wait.lock前, 同樣執行wait_for_completion(x)的進程C先搶佔到了鎖。獲得x->done後離開,x->done再次變爲0。而當A獲得鎖檢查x->done已經爲0, A 又再次進入睡眠.
* 完成變量x好比是一個大倉庫. x->done是倉庫裏的記貨員。
*執行wait_for_completion()的進程爲提貨人。
* 執行complete()的進程爲送貨人。
*倉庫有鎖,一次只能進一個人,出倉庫時鑰匙掛門口。
* 提貨人和送貨人來的順序不可知。 一件貨只能一個人提。
1)當是提貨A人先來到倉庫, 他取下鑰匙,進了倉庫鎖上大門。接着詢問記貨員有沒有貨, 如果有貨,他立刻提貨走人。如果沒貨,他就離開倉庫還回鑰匙,到倉庫合營的酒店睡覺。
2)當送貨人B來到倉庫, 取消鑰匙進了倉庫,存好貨物。記貨員登記以後, 便打電話(或廣播)通知在酒店裏睡覺的提貨人,如果有的話。送貨人換回鑰匙就離開了。
3)提貨人聽到電話(或廣播)便立即趕到倉庫提貨, 提到貨和記貨員登記便執行離開。但是因爲酒店和倉庫有點遠, 在提貨人A趕到倉庫時,很可能有提貨人C已經提走了貨.
擴展:
1) 提貨人A可能攤上大事要趕火車, 所以他只能等timeout小時.如果這時間內沒貨, 他就攜款潛逃了。wait_for_completion_timeout();
2) 提貨人A還有其他任務, 如果但他接到老闆的電話還沒有領到貨, 他也不管了.。 wait_for_completion_interruptible();
還有可能這個電話是用來引爆A身上的定時炸彈。。。。 wait_for_completion_killable()
3) 送貨人B送的貨太多,足夠所有的提貨人來提取。 complete_all()
假設驅動模塊使用了完成變量,在驅動移除時因爲有進程在等待完成變量而進入睡眠導致無法移除。
可嘗試
a).cat /proc/kallsyms | grep 'completion_name'若completion_name 0xfb002238寫簡單的模塊:
b)
static int __init complete_init(void)
{
complete((struct completion*)0xfb002238);
}
c)加載模塊以完成完成變量