_wait_event 具体实现过程

来源:互联网 发布:冰寒扒皮知乎 编辑:程序博客网 时间:2024/06/09 13:47

是不是当前进程要等待某个condition,然后就把它加到这个等待这个condition的wq中
_wait_event是当前进程调用它,也就是在宏DEFINE_WAIT(_wait)中的_wait就是把当前进程设置成_wait加到等待队列里,


以上基本正确


如果condition发生,是这个进程被唤醒设置成running而不是整个等待队列wq被唤醒?
如果conditon没有发生,还在prepare_to_wait里,这里保证了_wait不会被第二次加到等待队列中,但是第一次循环是加入了。finish_wait是将_wait移除。
那么在DEFINE_WAIT中的func设置成autoremove_wake_function意义何在?


prepare_to_wait()和finish_wait()并不是进程睡眠的地方,进程睡眠的地方是schedule().
prepare_to_wait()只是进行一些链表的操作,以确保自己在等待队列中,不会漏掉事件。
进程在确信自己已经在队列中后,再次检查条件,
这里,如果不检查,可能条件已经满足,直接去睡眠的话,可能再也没有人来唤醒它了。

然后,如果条件不满足,就调用schedule()去睡眠,
这里,进程的状态在prepare_to_wait()里设置为TASK_UNINTERRUPTIBLE,
所以,以后调度时就看不到该进程了,因此,该进程将没有机会运行,这就是睡眠。

注意,这里,该进程自己已经无能为力了,因为它自己已经不可能运行了。
只有等待他人来唤醒了。

当条件满足后,会有一个人(或者是其他进程,或者内核本身,等等)来唤醒某个等待队列上的进程。
具体是唤醒全部等待队列中的所有进程,还是只唤醒第一个进程,完全取决于该唤醒者,
等待在队列中的睡眠进程是无能为力的,与它们是没有关系的(呵呵,确切说,有一点关系)。

唤醒者通常调用__wake_up_common(),这样,依次取下等待队列中的__wait_queue_t结构,
调用该睡眠进程设置的func函数,即这里的autoremove_wake_function(),
将该进程的状态重新设置为RUNNING,
注意,此时该睡眠进程并不会立刻执行,只有等到下次调度的时候,该进程才有机会运行,
即醒来了。醒来是从schedule()回来,继续运行__wait_event()


总结一下,
睡眠是自己设置好进程状态(TASK_UNINTERRUPTIBLE,等等),加入等待队列,
并调用schedule()去睡眠。

睡眠是自己的动作。

唤醒是别人发现条件满足,调用__wake_up_common(),将睡眠进程从等待队列取下,
调用该睡眠进程设置的唤醒func,重新设置该睡眠进程为RUNNING。
从而可以在下次调度时运行。

唤醒是别人的动作。

 

wait_event_interruptible(queue_wait,condition)。该函数修改task的状态为TASK_INTERRUPTIBLE,意味着改进程将不会继续运行直到被唤醒,然后被添加到等待队列wq中。
在wait_event_interruptible()中首先判断condition是不是已经满足,如果是则直接返回0,否则调用__wait_event_interruptible(),并用__ret来存放返回值
---------------------------------------------------------------
#define wait_event_interruptible(wq, condition)          \
({                                                       \
    int __ret = 0;                                       \
    if (!(condition))                                    \
        
__wait_event_interruptible(wq, condition, __ret);\
    __ret;                                               \
})
wait_event_interruptible() --> __wait_event_interruptible()
__wait_event_interruptible()首先定义并初始化一个wait_queue_t变量__wait,其中数据为当前进程current,并把__wait入队。
   
在无限循环中,__wait_event_interruptible()将本进程置为可中断的挂起状态,反复检查condition是否成立,如果成立
则退出,如果不成立则继续休眠;条件满足后,即把本进程运行状态置为运行态,并将__wait从等待队列中清除掉,从而进程能够调度运行。如果进程当前有
异步信号(POSIX的),则返回-ERESTARTSYS。

 

原创粉丝点击