一,手动睡眠
使用灵活
二,简单睡眠
使用简单
简单睡眠的实现:
<linux/sched.h>
1,定义等待队列头
wait_queue_head_t readq;
2,初始化等待队列头
init_waitqueue_head(wait_queue_head_t *);
例如:
init_waitqueue_head(&readq);
注意:这个操作不能省略,且必须在第一次使用等待队列之前初始化,否则后果严重
3,睡眠---等待事件
等待队列:分为排他式睡眠,不排它式睡眠。
wait_event(wait_queue_head_t , condition );
condition:是一个表达式 唤醒条件(条件为真唤醒,为假继续睡)
睡前:
真 不睡
假 睡
醒后:
真 醒
假 继续睡
4,唤醒
wake_up(wati_queue_head_t *)
例如:wake_up(&readq);
手动睡眠实现:
<linux/sched.h>
1、定义等待队列头
wait_queue_head_t readq;
2、初始化等待队列头
init_waitqueue_head(wait_queue_head_t *);
例:init_waitqueue_head(&readq);
注意:这个操作不能省,且必须在第一次使用等待队列之前初始化,否则后果严重
3、睡眠
1) 定义等待队列节点
2) 如果是可中断睡眠判断是否有信号产生
3) 将等待队列节点与当前进程关联
4) 将节点挂载队列头上
5) 设置当前进程状态为睡眠态
6) 调用schedule()函数,主动产生调度,因为当前进程状态为睡眠态,所以系统不会对当前进程产生调度----睡眠
7) 被唤醒后做好下一次睡眠的准备,并确认是否需要继续睡
8) 设置进程状态为运行态
9) 移除节点
4、唤醒
wake_up(wait_queue_head_t *)
二、非阻塞
非阻塞的实现是通过判断file->f_flags 对应的O_NONBLOCK是否置位来决定
read(struct file *file, ....)
{
if(不可读) {
if(file->f_flags & O_NONBLOCK) {
return -EAGAIN;
}
wait_event();
}
三,多路复用
liunx/...h linux操作系统
asm/....h 通用
plat/....h 品牌
mach/...h 平台
应用层:
select
|
|
flie_operations->poll
{
1,将当前驱动的等待队列与当前进程关连
poll_wait
2,判断设备的状态返回给上层
}
例:
static unsigned int xxx_poll(struct file *filp, poll_table *wait)
{
unsigned int mask = 0;
...
poll_wait(filp, r_wait, wait);//加读等待队列头
poll_wait(filp, w_wait, wait);//加写等待队列头
if (...)//可读
{
mask |= POLLIN | POLLRDNORM; /*标示数据可获得*/
}
if (...)//可写
{
mask |= POLLOUT | POLLWRNORM; /*标示数据可写入*/
}
...
return mask;
}
四、异步通知
应用程序:
singal(SIGIO, handler);
/*设置文件描述符的属主*/
fcntl(fd, F_SETOWN, getpid());
file->f_owner<====getpid()
/*打开异步模式*/
int oflags = fcntl(fd, F_GETFL);
oflags = file->f_flags
fcntl(fd, F_SETFL, oflags | FASYNC);
oflags |= FASYNC
当打开异步模式的时候驱动中file_operations->fasync方法会被调用
驱动实现:
1、定义异步结构
struct fasync_struct *mystruct;
2、实现file_operations->fasync(int fd, struct file *file, int on)
说明:on 0 <==== file->f_flags & ~FASYNC
1 <==== file->f_flags | FASYNC
return fasync_helper(fd, file, on, &mystruct)
3、在合适的位置发送信号
kill_fasync(&mystruct, SIGIO, POLL_IN);