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驱动之同步、互斥、阻塞的应用
		
同步.互斥.阻塞的概念: 同步:在并发程序设计中,各进程对公共变量的访问必须加以制约,这种制约称为同步. 互斥机制:访问共享资源的代码区叫做临界区,这里的共享资源可能被多个线程需要,但这些共享资源又不 ...
 
随机推荐
- JAVA中的数据存储(堆及堆栈)- 转载
			
1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制.2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(对象可 ...
 - JavaWeb -- Struts1 动态bean, 动态校验, 动态生成javascript 表单校验
			
1. 动态formbean. 表单 JSP: <%@ page language="java" import="java.util.*" pageEnco ...
 - CTCS-2017滚粗记
			
Day 0: 下午不到四点就来到了宾馆,环境好评,网速能接受,但是你给我搞了个大床房是什么玩意儿啊... 晚上看MasterJH5574大神一直在写题热身(无限崇拜),自己板子没看几眼就丢到一遍去了, ...
 - Echarts的赋值,设置数据
			
柱形图案例的赋值 相关文档参考:https://blog.csdn.net/yangsitong1314/article/details/76984616 <div class="ma ...
 - 值提供器 AND 模型绑定器
			
本章介绍了值提供器的作用,ASP MVC自带的5中值提供器.以及模型绑定器的作用,自定义模型绑定器并使用自定义的模型绑定器(类型上加上[ModelBinder(typeof(xx))]或者在全局模型绑 ...
 - java处理HTTP请求
			
import com.diyfintech.wx.service.HttpService; import org.springframework.stereotype.Service; import ...
 - 转: 更高的压缩比,更好的性能–使用ORC文件格式优化Hive
			
Hive从0.11版本开始提供了ORC的文件格式,ORC文件不仅仅是一种列式文件存储格式,最重要的是有着很高的压缩比,并且对于MapReduce来说是可切分(Split)的.因此,在Hive中使用OR ...
 - Stylus的基础用法
			
介绍 在学习一个 Vue.js 项目的过程中,注意到源码中样式的部分并没有用熟悉的 .css 样式文件,而是发现了代码长得和 CSS 相像的 .styl 文件.这个 .styl 以前没见过啊,你是谁? ...
 - DOS命令说明
			
(转自:http://blog.csdn.net/mydriverc/article/details/2047152) 1 errorlevel dir cd md rd del ren cls ty ...
 - vue如何循环同一个echarts图表
			
因为我们知道echarts图表需要一个ID节点,所以我们循环echarts同一个图表时要考虑ID节点变化问题.废话不多说,直接上demo效果. 这里有一位分析师在不同的模拟组合,这时需求要在dialo ...