蜕变成蝶~Linux设备驱动中的阻塞和非阻塞I/O

今天意外收到一个消息,真是惊呆我了,博客轩给我发了信息,说是俺的博客文章有特色可以出本书,,这简直让我受宠若惊,俺只是个大三的技术宅,写的博客也是自己所学的一些见解和在网上看到我一些博文以及帖子里综合起来写的,,总之这又给了额外的动力,让自己继续前进,,希望和大家能够分享一些自己的经验,,在最需要奋斗的年级以及在技术的领域踽踽独行的过程中有共同的伙伴继续前进~
今天写的是Linux设备驱动中的阻塞和非阻塞I/0,何谓阻塞与非阻塞I/O?简单来说就是对I/O操作的两种不同的方式,驱动程序可以灵活的支持用户空间对设备的这两种访问方式。
一、基本概念:
- 阻塞操作 : 是指在执行设备操作时,若不能获得资源,则挂起进程直到满足操作条件后再进行操作。被挂起的进程进入休眠, 被从调度器移走,直到条件满足。
- 非阻塞操作 :在不能进行设备操作时,并不挂起,它或者放弃,或者不停地查询,直到可以进行操作。非阻塞应用程序通常使用select系统调用查询是否可以对设备进行无阻塞的访问最终会引发设备驱动中 poll函数执行。
二、轮询操作
阻塞的读取一个字符:
char buf;
fd = open("/dev/ttyS1",O_RDWR);
.....
res = read(fd,&buf,1); //当串口上有输入时才返回,没有输入则进程挂起睡眠
if(res == 1)
{
printf("%c/n",buf);
}
非阻塞的读一个字符:
char buf;
fd = open("/dev/ttyS1",O_RDWR|O_NONBLOCK);//O_NONBLOCK 非阻塞标识
.....
while(read(fd,&buf,1)!=1);//串口上没有输入则返回,所以循环读取
printf("%c/n",buf);
阻塞操作常常用等待队列来实现,而非阻塞操作用轮询的方式来实现。非阻塞I/O的操作在应用层通常会用到select()和poll()系统调用查询是否可对设备进行无阻塞访问。select()和poll()系统调用最终会引发设备驱动中的poll()函数被调用。这里对队列就不多介绍了,大家可以看看数据结构里面的知识点。
应用层的select()原型为:
int select(int numfds,fd_set *readfds,fd_set *writefds,fd_set *exceptionfds, struct timeval *timeout); numfds 的值为需要检查的号码最高的文件描述符加1,若select()在等待timeout时间后,若没有文件描述符准备好则返回。
应用程序为:
#inlcude------
main()
{
int fd,num;
char rd_ch[BUFFER_LEN];
fd_set rfds,wfds; //读写文件描述符集
//以非阻塞方式打开/dev/globalfifo设备文件
fd=open("/dev/globalfifo",O_RDWR|O_NONBLOCK);
if(fd != -1)
{
//FIFO 清零
if(ioctl(fd,FIFO_CLEAR,0) < 0)
{
printf("ioctl cmd failed /n");
}
while(1)
{
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_SET(fd,&rfds);
FD_SET(fd,&wfds);
select(fd+1,&rfds,&wfds,null,null); }
}
}
下面说说设备驱动中的poll()函数,函数原型如下:
static unsigned int poll(struct file *file, struct socket *sock,poll_table *wait) //第一个参数是file结构体指针,第三个参数是轮询表指针,这个函数应该进行两项工作
- 对可能引起设备文件状态变化的等待队列调用poll_wait()函数,将对应的等待队列头添加到poll_table
- 返回表示是否能对设备进行无阻塞读,写访问的掩码
这里还要提到poll_wait()函数,很多人会以为是和wait_event()一样的函数,会阻塞的等待某件事情的发生,其实这个函数并不会引起阻塞,它的工作是把当前的进程增添到wait参数指定的等待列表poll_table中去,poll_wait()函数原型如下:
static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
从中可以看出是将等待队列头wait_address添加到p所指向的结构体中(poll_table)
驱动函数中的poll()函数典型模板如下:
static unsigned int xxx_poll(struct file *filp,struct socket *sock,
poll_table *wait)
{
unsigned int mask = 0;
struct xxx_dev *dev = filp->private_data;//获得设备结构体指针
...
poll_wait(filp,&dev->r_wait,wait);//加读等待队列头到poll_table
poll_wait(filp,&dev->w_wait,wait);//加写等待队列头到poll_table
...
if(...)//可读
mask |= POLLIN | POLLRDNORM;
if(...)//可写
mask |= POLLOUT | POLLRDNORM;
...
return mask; }
三、支持轮询操作的globalfifo驱动
在globalfifo的poll()函数中,首先将设备结构体重的r_wait和w_wait等待队列头加到等待队列表,globalfifo设备驱动的poll()函数如下:
static unsigned int gloablfif0_poll(struct file *filp,poll_table *wait)
{
unsigned int mask = 0;
struct globalfifo_dev *dev = filp->private_data; down(&dev->sem); poll_wait(filp,&dev->r_wait , wait) ;
poll_wait(filp,&dev->r_wait , wait) ; if(dev->current_len != 0)
{
mask |= POLLIN | POLLRDNORM;
} if(dev->current_len != GLOBALFIFO_SIZE)
{
mask |= POLLOUT | POLLWRNORM;
} up(&dev->sem);
return mask;
}
四、总结
阻塞与非阻塞操作:
- 定义并初始化等待对列头;
- 定义并初始化等待队列;
- 把等待队列添加到等待队列头
- 设置进程状态(TASK_INTERRUPTIBLE(可以被信号打断)和TASK_UNINTERRUPTIBLE(不能被信号打断))
- 调用其它进程
poll机制:
- 把等待队列头加到poll_table
- 返回表示是否能对设备进行无阻塞读,写访问的掩码
版权所有,转载请注明转载地址:http://www.cnblogs.com/lihuidashen/p/4442573.html
蜕变成蝶~Linux设备驱动中的阻塞和非阻塞I/O的更多相关文章
- 蜕变成蝶~Linux设备驱动中的并发控制
并发和竞争发生在两类体系中: 对称多处理器(SMP)的多个CPU 内核可抢占的单CPU系统 访问共享资源的代码区域称为临界区(critical sections),临界区需要以某种互斥机制加以保护.在 ...
- 蜕变成蝶~Linux设备驱动之CPU与内存和I/O
那是世上最远的距离 思念让我无法去呼吸 你的一动和一举 占据我心里 陪我每个孤独无尽的夜里 用我心中盛放的画笔 描绘你微笑时的绚丽 爱让人痛彻心底 我却不怀疑 你的存在是我生命的奇迹 感受你的每一次的 ...
- 蜕变成蝶~Linux设备驱动之异步通知和异步I/O
在设备驱动中使用异步通知可以使得对设备的访问可进行时,由驱动主动通知应用程序进行访问.因此,使用无阻塞I/O的应用程序无需轮询设备是否可访问,而阻塞访问也可以被类似“中断”的异步通知所取代.异步通知类 ...
- 蜕变成蝶~Linux设备驱动之字符设备驱动
一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流 ...
- 蜕变成蝶~Linux设备驱动之按键设备驱动
在上述的驱动系列博客中,我们已经了解了关于阻塞和非阻塞.异步通知.轮询.内存和I/O口访问.并发控制等知识,按键设备驱动相对来说是比较简单的,本章内容可以加深我们对字符设备驱动架构.阻塞与非阻塞.中断 ...
- 蜕变成蝶~Linux设备驱动之中断与定时器
“我叮咛你的 你说 不会遗忘 你告诉我的 我也全部珍藏 对于我们来说 记忆是飘不落的日子 永远不会发黄 相聚的时候 总是很短 期待的时候 总是很长 岁月的溪水边 捡拾起多少闪亮的诗行 如果你要想念我 ...
- 蜕变成蝶~Linux设备驱动之DMA
如果不曾相逢 也许 心绪永远不会沉重 如果真的失之交臂 恐怕一生也不得轻松 一个眼神 便足以让心海 掠过飓风 在贫瘠的土地上 更深地懂得风景 一次远行 便足以憔悴了一颗 羸弱的心 每望一眼秋水微澜 便 ...
- 蜕变成蝶~Linux设备驱动之watchdog设备驱动
看门狗(watchdog )分硬件看门狗和软件看门狗.硬件看门狗是利用一个定时器 电路,其定时输出连接到电路的复位端,程序在一定时间范围内对定时器清零 (俗称 “喂狗”),如果程序出现故障,不在定时周 ...
- Linux设备驱动中的阻塞和非阻塞I/O
[基本概念] 1.阻塞 阻塞操作是指在执行设备操作时,托不能获得资源,则挂起进程直到满足操作所需的条件后再进行操作.被挂起的进程进入休眠状态(不占用cpu资源),从调度器的运行队列转移到等待队列,直到 ...
随机推荐
- Exception引起的性能问题
先show一下两段代码,两段代码都能比较好的实现业务逻辑,但是在高并发下,如果传入的参数为空,那么两段代码的性能表现完全不一样. private static string Get(string fi ...
- oval-and-rectangle
oval-and-rectangle Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- Java基础知识--集合
集合类 数组和集合的比较:数组可以存储对象,也可以存储基本数据类型,但是缺点就是长度固定,不能改变:集合长度是可变的,但是集合只能存储对象,集合可以存储不同类型的对象. Java容器类库一共有两种主要 ...
- jmeter接口测试实例1-添加学生信息
jmeter实例1:添加学生信息 进入jmeter,添加线程组改名称为添加学生信息(为了好区分接口),添加http请求,输入IP,方法,路径,在body data中输入json串,同上面postman ...
- Java第一课
1.引入Java虚拟机原因?过程:源文件--编译器(使用javac命令)-----二进制的字节码文件(平台无关)--解释器(使用Java命令)-----可执行文件结论:Java中的跨平台是通过[JVM ...
- python 绘图pylab
绘图 1.绘图主要通过代码来进行认知 demo: import pylab #绘图库 pylab.figure(1) #创建图一 pylab.plot([1,2,3,4],[1,2,3,4]) #在图 ...
- C_关于递归算法的几个例子
1.递归算法的定义: 2.递归与迭代的优劣 eg1:斐波那契数列:斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibona ...
- web端设计和web前端开发 的区别
- 基于ubuntu的docker安装
系统版本:Ubuntu16.04 docker版本:18.02.0 Ubuntu 系统的内核版本>3.10(执行 uname -r 可查看内核版本) 在安装前先简单介绍一下docker,按照 ...
- shell之磁盘容量检查,配合crontab可以定时清理磁盘
我的做法: !/bin/bashAvailable=`df -k | sed -n 2p | awk '{print $4}'`if [ $Available -eq 0 ];then ...