转载:http://www.cnblogs.com/zhuyp1015/archive/2012/06/09/2542894.html
突然想到epoll的内核实现,但是有点不明白设置了回调函数添加到等待队列后是如何唤醒的。所以找到了这篇文章。
Linux将进程状态描述为如下五种:
TASK_RUNNING
:可运行状态。处于该状态的进程可以被调度执行而成为当前进程。
TASK_INTERRUPTIBLE
:可中断的睡眠状态。处于该状态的进程在所需资源有效时被唤醒,也可以通过信号或定时中断唤醒(因为有signal_pending()函数)。
TASK_UNINTERRUPTIBLE
:不可中断的睡眠状态。处于该状态的进程仅当所需资源有效时被唤醒。
TASK_ZOMBIE
:僵尸状态。表示进程结束且已释放资源,但其task_struct仍未释放。
TASK_STOPPED
:暂停状态。处于该状态的进程通过其他进程的信号才能被唤醒。
等待队列是如何睡眠一个进程和如何唤醒一个进程的。
使用等待队列前通常先定义一个等待队列头:static wait_queue_head_t wq ,然后调用wait_event_*函数将等待某条件condition的当前进程插入到等待队列wq中并睡眠,一直等到condition条件满足后,内核再将睡眠在等待队列wq上的某一进程或所有进程唤醒。
这里我们来分析一下唤醒的过程,举比较常用的wait_event_interruptible来分析:
/**
* wait_event_interruptible - sleep until a condition gets true
* @wq: the waitqueue to wait on
* @condition: a C expression for the event to wait for
*
* The process is put to sleep (TASK_INTERRUPTIBLE) until the
* @condition evaluates to true or a signal is received.
* The @condition is checked each time the waitqueue @wq is woken up.
*
* wake_up() has to be called after changing any variable that could
* change the result of the wait condition.
*
* The function will return -ERESTARTSYS if it was interrupted by a
* signal and 0 if @condition evaluated to true.
*/
#define wait_event_interruptible(wq, condition) \
({ \
int __ret = 0; \
if (!(condition)) \
__wait_event_interruptible(wq, condition, __ret); \
__ret; \
})
这里很简单,判断一下condition条件是否满足,如果不满足则调用__wait_event_interruptible函数。
#define __wait_event_interruptible_timeout(wq, condition, ret) \
do { \
DEFINE_WAIT(__wait); \
\
for (;;) { \
prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE); \
if (condition) \
break; \
if (!signal_pending(current)) { \
ret = schedule_timeout(ret); \
if (!ret) \
break; \
continue; \
} \
ret = -ERESTARTSYS; \
break; \
} \
finish_wait(&wq, &__wait); \
} while (0)
__wait_event_interruptible
首先定义了一个wait_queue_t类型的等待队列项__wait:
#define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, autoremove_wake_function)
#define DEFINE_WAIT_FUNC(name, function) \
wait_queue_t name = { \
.private = current, \
.func = function, \
.task_list = LIST_HEAD_INIT((name).task_list), \
}
可以发现,这里__wait的private成员(通常用来存放进程的描述符)已经被初始化为current, 表示该等待队列项对应为当前进程。func成员为该等待队列项对应的唤醒函数,该进程被唤醒后会执行它,已经被初始化为默认的autoremove_wake_function函数。
然后在一个for (;