Linux 驱动层实现阻塞和非阻塞
linux应用层的函数默认是阻塞型的,但是要想真正实现阻塞,还需要驱动的支持才行。
例:open()、scanf()、fgets()、read()、accept() 等
1、默认情形,驱动层不实现阻塞和非阻塞
struct samsung_key{
int major;
int irqno;
struct class *cls;
struct device *dev;
struct key_event event;
};
struct samsung_key *key_dev;
ssize_t key_drv_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos)
{
int ret;
ret = copy_to_user(buf, &key_dev->event, count);
if(ret > )
{
printk("copy_to_user error\n");
return -EFAULT;
}
memset(&key_dev->event, , sizeof(struct key_event));
return ;
}
// 中断处理程序,多个按键可以根据 irqno 区分
irqreturn_t key_irq_handler(int irqno, void *dev_id)
{
int ret;
printk("------------%s-------------\n", __FUNCTION__);
ret = gpio_get_value(key_info[i].key_gpio);
ret ? (key_dev->key.value = ) : (key_dev->key.value = );
printk("key = %d status = %d\n", key_dev->key.name, key_dev->key.value);
// 返回值一定要是 IRQ_HANDLED
return IRQ_HANDLED;
}
static int __init key_drv_init(void)
{
... ...
key_dev->irqno = IRQ_EINT();
ret = request_irq(key_dev->irqno, key_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "key_eint", NULL);
... ...
}
static int __exit key_drv_exit(void)
{
... ...
free_irq(key_dev->irqno,NULL);
... ...
}
// 应用层
fd = open("/dev/key0", O_RDWR);
这种情况下,应用层的 read 会一直不停的读按键值,使用 top 指令查看,发现 cpu 几乎被全部占用。
2、驱动层实现阻塞
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
// 初始化等待队列头
init_waitqueue_head(wait_queue_head_t *q);
// 功能:在特定的时候进行休眠
// 参数1:等待队列头
// 参数2:条件,条件为假,该代码就会阻塞,如果为真,不做任何事情
wait_event_interruptible(wait_queue_head_t q,condition);
// 功能: 资源可达的时候,唤醒
wake_up_interruptible(wait_queue_head_t *q);
struct samsung_key{
int major;
int irqno;
struct class *cls;
struct device *dev;
struct key_event event;
unsigned char have_data;
wait_queue_head_t wq_head;
};
struct samsung_key *key_dev;
ssize_t key_drv_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos)
{
int ret;
// 判断是否阻塞,条件为假,就会阻塞,让出cpu
wait_event_interruptible(key_dev->wq_head,key_dev->have_data);
ret = copy_to_user(buf, &key_dev->event, count);
if(ret > )
{
printk("copy_to_user error\n");
return -EFAULT;
}
memset(&key_dev->event, , sizeof(struct key_event));
key_dev->have_data = ;
return ;
}
// 中断处理程序,多个按键可以根据 irqno 区分
irqreturn_t key_irq_handler(int irqno, void *dev_id)
{
int ret;
printk("------------%s-------------\n", __FUNCTION__);
ret = gpio_get_value(key_info[i].key_gpio);
ret ? (key_dev->key.value = ) : (key_dev->key.value = );
printk("key = %d status = %d\n", key_dev->key.name, key_dev->key.value);
key_dev->have_data = ;
// 唤醒
wake_up_interruptible(&key_dev->wq_head);
// 返回值一定要是 IRQ_HANDLED
return IRQ_HANDLED;
}
static int __init key_drv_init(void)
{
... ...
key_dev->irqno = IRQ_EINT();
ret = request_irq(key_dev->irqno, key_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "key_eint", NULL);
// 初始化等待队列头
init_waitqueue_head(&key_dev->wq_head);
... ...
}
static int __exit key_drv_exit(void)
{
... ...
free_irq(key_dev->irqno,NULL);
... ...
}
// 应用层
fd = open("/dev/key0", O_RDWR);
实现阻塞后,应用层读不到按键值时就会休眠,让出cpu资源
3、驱动层实现非阻塞
实现非阻塞很容易,只需在读数据前加判断就行,可以单独实现非阻塞,也可以同时兼容阻塞和非阻塞、
// 单独实现非阻塞
ssize_t key_drv_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos)
{
int ret; // 非阻塞,资源不可达的时候,立刻返回,资源可达,直接读写数据
if( (filp->f_flags & O_NONBLOCK) && !key_dev->have_data)
return -EAGAIN; ret = copy_to_user(buf, &key_dev->event, count);
if(ret > )
{
printk("copy_to_user error\n");
return -EFAULT;
}
memset(&key_dev->event, , sizeof(struct key_event));
key_dev->have_data = ; return ;
} // 应用层以非阻塞的方式
fd = open("/dev/key0", O_RDWR | O_NONBLOCK);
非阻塞模式下,当应用程序运行后,没有读到按键值,就会收到一个错误(-EAGAIN)返回值。
// 驱动层兼容阻塞和非阻塞
ssize_t key_drv_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos)
{
int ret; // 资源不可达的时候,立刻返回,资源可达,直接读写数据
if( (filp->f_flags & O_NONBLOCK) && !key_dev->have_data)
return -EAGAIN; // 判断是否阻塞,条件为假,就会阻塞,让出cpu
wait_event_interruptible(key_dev->wq_head,key_dev->have_data); ret = copy_to_user(buf, &key_dev->event, count);
if(ret > )
{
printk("copy_to_user error\n");
return -EFAULT;
}
memset(&key_dev->event, , sizeof(struct key_event));
key_dev->have_data = ; return ;
}
Linux 驱动层实现阻塞和非阻塞的更多相关文章
- Linux设备驱动中的阻塞和非阻塞I/O
[基本概念] 1.阻塞 阻塞操作是指在执行设备操作时,托不能获得资源,则挂起进程直到满足操作所需的条件后再进行操作.被挂起的进程进入休眠状态(不占用cpu资源),从调度器的运行队列转移到等待队列,直到 ...
- Linux设备驱动中的IO模型---阻塞和非阻塞IO【转】
在前面学习网络编程时,曾经学过I/O模型 Linux 系统应用编程——网络编程(I/O模型),下面学习一下I/O模型在设备驱动中的应用. 回顾一下在Unix/Linux下共有五种I/O模型,分别是: ...
- Linux设备驱动中的阻塞和非阻塞I/O <转载>
Green 博客园 首页 新随笔 联系 订阅 管理 Linux设备驱动中的阻塞和非阻塞I/O [基本概念] 1.阻塞 阻塞操作是指在执行设备操作时,托不能获得资源,则挂起进程直到满足操作所需的条件 ...
- 蜕变成蝶~Linux设备驱动中的阻塞和非阻塞I/O
今天意外收到一个消息,真是惊呆我了,博客轩给我发了信息,说是俺的博客文章有特色可以出本书,,这简直让我受宠若惊,俺只是个大三的技术宅,写的博客也是自己所学的一些见解和在网上看到我一些博文以及帖子里综合 ...
- linux驱动编写之阻塞与非阻塞
一.概念 应用程序使用API接口,如open.read等来最终操作驱动,有两种结果--成功和失败.成功,很好处理,直接返回想要的结果:但是,失败,是继续等待,还是返回失败类型呢? 如果继续等待,将进 ...
- 《linux设备驱动开发详解》笔记——8阻塞与非阻塞IO
8.1 阻塞与非阻塞IO 8.1.0 概述 阻塞:访问设备时,若不能获取资源,则进程挂起,进入睡眠状态:也就是进入等待队列 非阻塞:不能获取资源时,不睡眠,要么退出.要么一直查询:直接退出且无资源时, ...
- Linux驱动之异步OR同步,阻塞OR非阻塞概念介绍
链接:https://www.zhihu.com/question/19732473/answer/20851256 1.同步与异步同步和异步关注的是消息通信机制 (synchronous commu ...
- 简述linux同步与异步、阻塞与非阻塞概念以及五种IO模型
1.概念剖析 相信很多从事linux后台开发工作的都接触过同步&异步.阻塞&非阻塞这样的概念,也相信都曾经产生过误解,比如认为同步就是阻塞.异步就是非阻塞,下面我们先剖析下这几个概念分 ...
- Linux驱动之同步、互斥、阻塞的应用
同步.互斥.阻塞的概念: 同步:在并发程序设计中,各进程对公共变量的访问必须加以制约,这种制约称为同步. 互斥机制:访问共享资源的代码区叫做临界区,这里的共享资源可能被多个线程需要,但这些共享资源又不 ...
随机推荐
- PHP练习题一
目录:1.如何使用php导入导出csv?2.php接收POST数据的方式有哪些?3.如何让json_encode()不转义斜杠?我在做服务器返回一些数据时需要返回一些地址,但是默认的json_code ...
- Android -- junit测试框架,logcat获取log信息
1. 相关概念 白盒测试: 知道程序源代码. 根据测试的粒度分为不同的类型 方法测试 function test 单元测试 unit test 集成 ...
- Generate parentheses,生成括号对,递归,深度优先搜索。
问题描述:给n对括号,生成所有合理的括号对.比如n=2,(()),()() 算法思路:利用深度优先搜索的递归思想,对n进行深度优先搜索.边界条件是n==0:前面电话号组成字符串也是利用dfs. pub ...
- JQuery小知识点代码
1.链式操作 $(function(){ /*var oDiv = $('#div1'); oDiv.html('hello'); oDiv.css('background','red'); oDiv ...
- angular一些常用的方法:
angular.copy(); 用法:对Object对象的深度拷贝$scope.data = {name:'yanjinyun',age:'11'}; $scope.origData = angula ...
- 【LABVIEW到C#】4》String的操作之Search and Replace.vi
C#封装如下: public class SearchAndRepalce : Darrenstring { public bool replaced; private string stringou ...
- SpringMVC中WebDataBinder的应用及原理
Controller方法的参数类型可以是基本类型,也可以是封装后的普通Java类型.若这个普通Java类型没有声明任何注解,则意味着它的每一个属性都需要到Request中去查找对应的请求参数.众所周 ...
- DRF 的 版本,解析器,与序列化
DRF 的 版本,解析器,与序列化 补充 配置文件中的 类的调用: (字符串) v1 = ["view.xx.apth.Role","view.xx.apth.Role& ...
- linux中的阻塞机制及等待队列
阻塞与非阻塞是设备访问的两种方式.驱动程序需要提供阻塞(等待队列,中断)和非阻塞方式(轮询,异步通知)访问设备.在写阻塞与非阻塞的驱动程序时,经常用到等待队列. 一.阻塞与非阻塞 阻塞调用是没有获得资 ...
- 【android】下载文件至本应用程序的file目录或者sdcard
一.判断是否有sdcard卡 //判断是否有SD卡 //ture:有SD卡 //false:没有SD卡 public boolean avaiableMedia(){ String status ...