读一下wait_event_interruptible()的源码,不难发现这个函数先将
当前进程的状态设置成TASK_INTERRUPTIBLE,然后调用schedule(),
而schedule()会将位于TASK_INTERRUPTIBLE状态的当前进程从runqueue
队列中删除。从runqueue队列中删除的结果是,当前这个进程将不再参
与调度,除非通过其他函数将这个进程重新放入这个runqueue队列中,
这就是wake_up()的作用了。
由于这一段代码位于一个由condition控制的for(;;)循环中,所以当由
shedule()返回时(当然是被wake_up之后,通过其他进程的schedule()而
再次调度本进程),如果条件condition不满足,本进程将自动再次被设
置为TASK_INTERRUPTIBLE状态,接下来执行schedule()的结果是再次被
从runqueue队列中删除。这时候就需要再次通过wake_up重新添加到
runqueue队列中。
如此反复,直到condition为真的时候被wake_up.
可见,成功地唤醒一个被wait_event_interruptible()的进程,需要满足:
在 1)condition为真的前提下,2) 调用wake_up()。
所以,如果你仅仅修改condition,那么只是满足其中一个条件,这个时候,
被wait_event_interruptible()起来的进程尚未位于runqueue队列中,因
此不会被 schedule。这个时候只要wake_up一下就立刻会重新进入运行调度。
/* wait_event_interruptible 宏 */
#define wait_event_interruptible(wq, condition) \
({ \
int __ret = 0; \
if (!(condition)) \
__wait_event_interruptible(wq, condition, __ret); \
__ret; \
})
当进程执行(进入)wait_event_interruptible宏时,首先检查一遍condition是否为真,如果为真,直接跳出wait_event_interruptible 宏,继续向下执行。
当condition为假时,进入__wait_event_interruptible:
/* __wait_event_interruptible 宏 */
#define __wait_event_interruptible(wq, condition, ret) \
do { \
DEFINE_WAIT(__wait); \
for (;;) { \
prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE); \
if (condition) \
break; \
if (!signal_pending(current)) { \
schedule(); \
continue; \
} \
ret = -ERESTARTSYS; \
break; \
} \
finish_wait(&wq, &__wait); \
} while (0)
一,进入__wait_event_interruptible后,首先定义并初始化一个wait_queue_t变量__wait,其中数据为当前进程current,并把__wait入队。接着进入for死循环中:
在for循环中,__wait_event_interruptible将本进程置为可中断的挂起状态,之后检查condition,如果condition为真,跳出for循环,执行finish_wait,之后跳出wait_event_interruptible。进程继续向下执行。
二,如果进入for循环后,第一次检查condition为假时,
进入第二个if语句,调用schedule,将位于TASK_INTERRUPTIBLE状态的当前进程从runqueue
队列中删除,而从runqueue队列中删除的结果是,当前这个进程将不再参
与调度,然后进程就停在这了!等待唤醒,即等待调用wake_up。如果不在其他函数内(中断处理程序)调用wake_up,那当前进程就死在这了
如果中断处理程序中调用wake_up(将这个进程重新放入这个runqueue队列中),那当前进程就等待被调度,被调度之后,即执行continue。继续for循环。