内核笔记:完成变量completion.

来源:互联网 发布:淘宝上买港版iphone6s 编辑:程序博客网 时间:2024/05/17 01:58

 一结构体变量定义:

 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)加载模块以完成完成变量
0 0