_wait_event 具体实现过程
来自:http://www.linuxforum.net/forum/showthreaded.php?Board=linuxK&Number=572220
是不是当前进程要等待某个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。
从而可以在下次调度时运行。
唤醒是别人的动作。