linux之等待队列--阻塞型驱动学习---学习笔记

阻塞型IO字符设备驱动

程序进行读写操作时,有时目标设备无法立刻满足用户的读写需求,例如,调用read时没有数据可以交换,但以后可能会有,或者一个进程试图向设备写数据时,但设备暂时没有准备好接收数据。应用程序只是调用read或write并得到返回值,故应用程序不处理此类问题,此时驱动程序就应当阻塞进程,使它进入睡眠并等待条件满足,这就是阻塞型IO.

阻塞方式是文件读写操作的默认方式,但应用程序员可通过使用o_NONBLOCK标志来人为的设置读写操作为非阻塞方式(该标志定义在<linux/fcntl.h>中,在打开文件时指定)。

如果设置了O_NONBLOCK标志,read和write的行为是不同的。如果进程在没有数据就绪时就调用了read,或者在缓冲区没有空间时调用了write,系统只是简单的返回-EAGAIN,而不会阻塞进程。

 

等待队列

Linux2.6内核提供了如下关于等待队列的操作

在linux驱动程序设计汇总,可以使用等待队列中来实现进程的阻塞,等待队列可看做保存进程的容器,在阻塞进程时,将进程放入等待队列,当唤醒进程时,从等待队列取出进程,使之状态为TASK_RUNNING。

等待队列在内核中有着极其重要的作用,作为异步操作,他的实现简单而又强大。

 

它通过一个双链表和把等待tast的头,和等待的进程列表链接起来。从上图可以清晰看到。所以我们知道,如果要实现一个等待队列,首先要有两个部分。队列头和队列项。下面看他们的数据结构。

struct __wait_queue_head {

spinlock_t lock;

struct list_head task_list;

};

typedef struct  __wait_queue_head  wait_queue_head_t;

 

 

1、定义等待队列

Wait_queue_head_t  my_queue

2、初始化等待队列

Init_waitqueue_head(&my_queue)

函数实现:

 


 

3、定义并初始化等待队列

DECLARE_WAIT_QUEUE_HEAD(my_queue)

4、添加/移除等待队列
   void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
   void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
   add_wait_queue()用于将等待队列wait添加到等待队列头q指向的等待队列链表中,而remove_wait_queue()用于将等待队列wait从附属的等待队列头q指向的等待队列链表中移除。

 

5、有条件睡眠

Wait_event(queue,condition)

当condition为真时,立即返回;否则让进程进入TASK_UNINTERRUPTBLE模式的睡眠,并挂在queue参数所指定的等待队列上

 

Wait_event_interruptible(queue,condition)

当condition为真时,立即返回;否则让进程进入TASK_INTERRUPTIBLE的睡眠,并挂在queue参数所指定的等待队列上。

 

Wait_event_killable(queue ,condition)

当condition为真时,立即返回;否则让进程进入TASK_KILLABLE的睡眠,并挂在queue参数所指定的等待队列上。

 

6、从等待队列中唤醒进程

Wake_up(wait_queue_t *q)

从等待队列中唤醒为TASK_UNINTERRUPTIBLE,TASK_INTERRUPTIBLE,ASK_KIKKABLE的所有进程。

Wake_up_interruptible(wait_queue_t *q)

从等待队列中唤醒状态为TASK_INTERRUPTIBLE的进程。

7、实列分析

struct mem_dev

{

char *data;

unsigned long size;

wait_queue_head_t inq;

};

 

int static __init mem_init()

{

.....

init_waitqueue_head(&(mem_devp[i].inq));

}

 

static ssize_t mem_read(...)//使进程挂起在等待队列

{

...

while(!have_data) /*没有数据可读,考虑为什么不用if,而是用while*/

{

if(filp ->f_flags & O_ONOBLOCK)

return -EAGAIN;

wait_event_interruptible(dev->inq,have_data);//问题出在interruptible

}

...

}

 

static ssize_t mem_write(...)//唤醒等待队列中的进程

{

...

have_data = true;

wake_up (&dev->inq)); //唤醒进程

...

 

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值