阻塞(休眠)调用是没有获得资源则挂起进程,被挂起的进程进入休眠状态,调用的函数只有在得到结果之后才返回,进程继续。
非阻塞(休眠)是不能进行设备操作时不挂起,或返回,或反复查询,直到可以进行操作为止,被调用的函数不会阻塞当前进程,而会立刻返回。
因为阻塞的进程会进入休眠状态,因此,必须确保有一个地方能够唤醒休眠的进程。唤醒进程的地方
最大可能发生在中断里面,因为硬件资源获得的同时往往伴随着一个中断。
使用wait_event()函数使得进程睡眠;而在内核另一处有一个对应的wake_up()函数被调用
wake_up() 应与wait_event() 或wait_event_timeout() 成对使用, 而wake_up_interruptible() 则应与
wait_event_interruptible() 或wait_event_interruptible_timeout() 成对使用。wake_up() 可唤醒处于
TASK_INTERRUPTIBLE 和TASK_UNINTERRUPTIBLE 的进程,而wake_up_interruptible()只能唤醒处于
TASK_INTERRUPTIBLE 的进程。
功能函数所在路径kernel/include/linux/wait.h, kernel/kernel/sched.c, kernel/kernel/wait.c.
核心数据结构 等待队列
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct__wait_queue_head wait_queue_head_t;
使用方法:
涉及头文件kernel/include/linux/wait.h
#include <linux/wait.h>
在数据结构体中定义
wait_queue_head_t XX
进程通过执行下面步骤将自己加入到一个等待队列中:
1) 调用DECLARE_WAITQUEUE
(wait, current)
定义和初始化一个等待队列头 //代替wait_queue_head_t my_queue和init_waitqueue_head(&my_queue);
2) 调用add_wait_queue()把自己加入到等待队列中。该队列会在进程等待的条件满足时唤醒它。在其他地方写相关代码,在事件发生时,对等的队列执行wake_up()操作。
3) 将进程状态变更为: TASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE。
4) 如果状态被置为TASK_INTERRUPTIBLE ,则信号唤醒进程。即为伪唤醒(唤醒不是因为事件的发生),因此检查并处理信号。
5) 检查condition是否为真,为真则没必要休眠,如果不为真,则调用scheduled()。
6) 当进程被唤醒的时候,它会再次检查条件是否为真。真就退出循环,否则再次调用scheduled()并一直重复这步操作。
7) condition满足后,进程将自己设置为TASK_RUNNING 并通过remove_wait_queue()退出。
sleep_on系列函数在linux代码中已注释不让使用,将在代码中剔除