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 驱动层实现阻塞和非阻塞的更多相关文章

  1. Linux设备驱动中的阻塞和非阻塞I/O

    [基本概念] 1.阻塞 阻塞操作是指在执行设备操作时,托不能获得资源,则挂起进程直到满足操作所需的条件后再进行操作.被挂起的进程进入休眠状态(不占用cpu资源),从调度器的运行队列转移到等待队列,直到 ...

  2. Linux设备驱动中的IO模型---阻塞和非阻塞IO【转】

    在前面学习网络编程时,曾经学过I/O模型 Linux 系统应用编程——网络编程(I/O模型),下面学习一下I/O模型在设备驱动中的应用. 回顾一下在Unix/Linux下共有五种I/O模型,分别是: ...

  3. Linux设备驱动中的阻塞和非阻塞I/O <转载>

    Green 博客园 首页 新随笔 联系 订阅 管理 Linux设备驱动中的阻塞和非阻塞I/O   [基本概念] 1.阻塞 阻塞操作是指在执行设备操作时,托不能获得资源,则挂起进程直到满足操作所需的条件 ...

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

    今天意外收到一个消息,真是惊呆我了,博客轩给我发了信息,说是俺的博客文章有特色可以出本书,,这简直让我受宠若惊,俺只是个大三的技术宅,写的博客也是自己所学的一些见解和在网上看到我一些博文以及帖子里综合 ...

  5. linux驱动编写之阻塞与非阻塞

    一.概念 应用程序使用API接口,如open.read等来最终操作驱动,有两种结果--成功和失败.成功,很好处理,直接返回想要的结果:但是,失败,是继续等待,还是返回失败类型呢?  如果继续等待,将进 ...

  6. 《linux设备驱动开发详解》笔记——8阻塞与非阻塞IO

    8.1 阻塞与非阻塞IO 8.1.0 概述 阻塞:访问设备时,若不能获取资源,则进程挂起,进入睡眠状态:也就是进入等待队列 非阻塞:不能获取资源时,不睡眠,要么退出.要么一直查询:直接退出且无资源时, ...

  7. Linux驱动之异步OR同步,阻塞OR非阻塞概念介绍

    链接:https://www.zhihu.com/question/19732473/answer/20851256 1.同步与异步同步和异步关注的是消息通信机制 (synchronous commu ...

  8. 简述linux同步与异步、阻塞与非阻塞概念以及五种IO模型

    1.概念剖析 相信很多从事linux后台开发工作的都接触过同步&异步.阻塞&非阻塞这样的概念,也相信都曾经产生过误解,比如认为同步就是阻塞.异步就是非阻塞,下面我们先剖析下这几个概念分 ...

  9. Linux驱动之同步、互斥、阻塞的应用

    同步.互斥.阻塞的概念: 同步:在并发程序设计中,各进程对公共变量的访问必须加以制约,这种制约称为同步. 互斥机制:访问共享资源的代码区叫做临界区,这里的共享资源可能被多个线程需要,但这些共享资源又不 ...

随机推荐

  1. hibernate的一对多配置

    首先是“一”的 Customer.java package com.xiaostudy.domain; import java.util.HashSet; import java.util.Set; ...

  2. maven项目Dao层优化

    平时我们习惯一个实体类就对应一个dao类,这样做,增删改查都大同小异,只是实体类对象不一样而已,因此,我们可以把公用的方法抽取来,建立一个IBaseDao接口,如下: public interface ...

  3. Java 常用正则表达式 - 转载

    只能输入数字:"^[0-9]*$".只能输入n位的数字:"^\d{n}$".只能输入至少n位的数字:"^\d{n,}$".只能输入m~n位的 ...

  4. 四十五 Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的bool组合查询

    bool查询说明 filter:[],字段的过滤,不参与打分must:[],如果有多个查询,都必须满足[并且]should:[],如果有多个查询,满足一个或者多个都匹配[或者]must_not:[], ...

  5. ubuntu定时执行任务——crontab的使用

    先补上几个链接,后续再总结 #参考# http://www.cnblogs.com/kaituorensheng/p/4494321.html http://blogread.cn/it/articl ...

  6. mysql 自查询

    先介绍用法: 用法解释  select  * from  a,b  : shopping 商品表 , baixitest SELECT b.name from shopping as a, baixi ...

  7. ZOJ 3488 Conic Section

    The conic sections are the nondegenerate curves generated by the intersections of a plane with one o ...

  8. 不安装APK直接启动应用

    相信这样一个问题,大家都不会陌生, “有什么的方法可以使Android的程序APK不用安装,而能够直接启动”. 发现最后的结局都是不能实现这个美好的愿望,而腾讯Android手机游戏平台却又能实现这个 ...

  9. Template pattern模板方法模式

    1>模板模式定义了算法的步骤,把这些步骤的实现延续到子类 2>模板模式为我们提供了一个代码复用的技巧 3>模板抽象类中可以定义具体方法.抽象方法和钩子方法 4>为了防止子类改变 ...

  10. SpringCloud教程 | 第九篇: 服务链路追踪(Spring Cloud Sleuth)

    版权声明:本文为博主原创文章,欢迎转载,转载请注明作者.原文超链接 ,博主地址:http://blog.csdn.net/forezp. http://blog.csdn.net/forezp/art ...