读一下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一下就立刻会重新进入运行调度。
2. 关于wait_event_interruptible的返回值
根据 wait_event_interruptible 的宏定义知:
1) 条件condition为真时调用这个函数将直接返回0,而当前进程不会
被 wait_event_interruptible和从runqueue队列中删除。
2) 如果要被wait_event_interruptible的当前进程有nonblocked pending
signals, 那么会直接返回-ERESTARTSYS(i.e. -512),当前进程不会
被wait_event_interruptible 和从runqueue队列中删除。
3) 其他情况下,当前进程会被正常的wait_event_interruptible,并从
runqueue队列中删除,进入TASK_INTERRUPTIBLE状态退出运行调度,
直到再次被唤醒加入runqueue队列中后而参与调度,将正常返回0。
附1:wait_event_interruptible 宏
#define wait_event_interruptible(wq, condition) \
({ \
int __ret = 0; \
if (!(condition)) \
__wait_event_interruptible(wq, condition, __ret); \
__ret; \
})
注: C语言中{a,b, ..., x}的的值等于最后一项,即x,因此上述
宏的值是 __ret。
附2:wait_event_interruptible()和 wake_up的等效代码
wait_event_interruptible(wq, condition) /*等效没有考虑返回值*/
{
if (!(condition))
{
wait_queue_t _ _wait;
init_waitqueue_entry(&_ _wait, current);
add_wait_queue(&wq, &_ _wait);
for (;;)
{
set_current_state(TASK_INTERRUPTIBLE);
if (condition)
break;
schedule(); /* implicit call: del_from_runqueue(current)*/
}
current->state = TASK_RUNNING;
remove_wait_queue(&wq, &_ _wait);
}
}
void wake_up(wait_queue_head_t *q)
{
struct list_head *tmp;
wait_queue_t *curr;
list_for_each(tmp, &q->task_list)
{
curr = list_entry(tmp, wait_queue_t, task_list);
wake_up_process(curr->task);
/* implicit call: add_to_runqueue(curr->task);*/
if (curr->flags)
break;
}
}
Linux kernel 中使用 wait_event_interruptible(wq, condition) 使进程睡眠
http://blog.csdn.net/moonlighting/article/details/21538199?locationNum=2
wait_event_interruptible(wq, condition) 修改当前进程为TASK_INTERRUPTIBLE状态,并把进程添加到等待队列wq中, 意味着该进程要等到被唤醒时才能继续运行,或者被信号中断;如果没有被唤醒或者中断,它会一直等下去。
wait_event_interruptible(wq, condition) 就是用来等待condition为真, condition 一般是一个表达式,每次查看condition时都可能不一样。在wait_event_interruptible(wq, condition) 中首先判断 condition 条件是否为真,如果为真,则返回 0;否则,调用 __wait_event_interruptible(wq, condtion),并把返回值保存到_ret中。
#define wait_event_timeout(wq, condition, timeout)\
({ \
long __ret = timeout;\
if (!(condition)) \
__wait_event_timeout(wq, condition, __ret);\
__ret; \
})
__wait_event_interruptible(wq, condition, ret) 也是一个宏,定义如下
#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)
其中,prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE) 先把进程放入等待队列wq中,然后把进程状态设备 TASK_INTERRUTIBLE。检查 condition 是否为真,为真则中断循环。检查是否有没有处理的信号, 如果没有,则调用schedule(),让出CPU。
Linux kernel 中使用 wait_event_interruptible(wq, condition) 使进程睡眠
http://blog.csdn.net/moonlighting/article/details/21538199?locationNum=2
wait_event_interruptible(wq, condition) 修改当前进程为TASK_INTERRUPTIBLE状态,并把进程添加到等待队列wq中, 意味着该进程要等到被唤醒时才能继续运行,或者被信号中断;如果没有被唤醒或者中断,它会一直等下去。
wait_event_interruptible(wq, condition) 就是用来等待condition为真, condition 一般是一个表达式,每次查看condition时都可能不一样。在wait_event_interruptible(wq, condition) 中首先判断 condition 条件是否为真,如果为真,则返回 0;否则,调用 __wait_event_interruptible(wq, condtion),并把返回值保存到_ret中。
#define wait_event_timeout(wq, condition, timeout)\
({ \
long __ret = timeout;\
if (!(condition)) \
__wait_event_timeout(wq, condition, __ret);\
__ret; \
})
__wait_event_interruptible(wq, condition, ret) 也是一个宏,定义如下
#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)
其中,prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE) 先把进程放入等待队列wq中,然后把进程状态设备 TASK_INTERRUTIBLE。检查 condition 是否为真,为真则中断循环。检查是否有没有处理的信号, 如果没有,则调用schedule(),让出CPU。