休眠有两种相关的进程状态:TASK_INTERRUPTIBLE and TASK_UNINTERRUPTIBLE。它们的惟一区别是处于TASK_UNINTERRUPTIBLE状态的进程会忽略信号,而处于 TASK_INTERRUPTIBLE状态的进程如果收到信号会被唤醒并处理信号(然后再次进入等待睡眠状态)。两种状态的进程位于同一个等待队列上,等待某些事件,不能够运行。
进程通过执行下面几步将自己加入到一个等待队列中: --------------------------------------------------------- 1. 调用DECLARE_WAITQUEUE()创建一个等待队列的项 |------------------------------------------------| |/* 'q' is the wait queue we wish to sleep on */ | |DECLARE_WAITQUEUE(wait, current); | |------------------------------------------------|
while (!condition) { /* condition is the event that we are waiting for */
3. 将进程的状态变更为TASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE |----------------------------------------------| | /* or TASK_UNINTERRUPTIBLE */ | | set_current_state(TASK_INTERRUPTIBLE); | |----------------------------------------------|
4. 如果状态被设置为TASK_INTERRUPTIBLE,则信号可以唤醒进程(信号和事件都可以唤醒该进程)。这就是所谓的伪唤醒(唤醒不是因为事件的发生,而是由信号唤醒的),因此检查并处理信号。 注: 信号和等待事件都可以唤醒处于TASK_INTERRUPTIBLE状态的进程,信号唤醒该进程为伪唤醒;该进程被唤醒后,如果(!condition)结果为真,则说明该进程不是由等待事件唤醒的,而是由信号唤醒的。所以该进程处理信号后将再次让出CPU控制权 |----------------------------------------------| | if (signal_pending(current)) | | /* handle signal */ | |----------------------------------------------|
5. Tests whether the condition is true. If it is, there is no need to sleep. If it is not true, the task calls schedule(). 本进程在此处交出CPU控制权,如果该进程再次被唤醒,将从while循环结尾处继续执行,因而将回到while循环的开始处while (!condition),进测等待事件是否真正发生. |----------------------------------------------| | schedule(); | |----------------------------------------------| }
6. Now that the condition is true, the task can set itself to TASK_RUNNING and remove itself from the wait queue via remove_wait_queue(). |----------------------------------------------| |set_current_state(TASK_RUNNING); | |remove_wait_queue(q, &wait); | |----------------------------------------------|