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. java获取当前文件路径 [转]

    1.如何获得当前文件路径 常用: 字符串类型:System.getProperty("user.dir"); 综合: package com.zcjl.test.base; imp ...

  2. 制作基于Buildbot的自动化测试系统Docker镜像

    Buildbot in Docker 前言 最近使用Buildbot做了一个自动测试的框架,为了部署方便,可以把测试框架做成Docker镜像,方便部署.这里记录下过程,供大家参考. 项目介绍 项目是一 ...

  3. Spring中<ref local=""/>与<ref bean=""/>区别

    小 Spring中<ref local=""/>与<ref bean=""/>区别 (2011-03-19 19:21:58) 转载▼ ...

  4. spring半自动代理

    1.被代理类接口Person.java package com.xiaostudy; /** * @desc 被代理类接口 * * @author xiaostudy * */ public inte ...

  5. tomcat官方下载连接——安装版&绿色版

    Tomcat绿色版Windows64位9.0.10 http://mirror.bit.edu.cn/apache/tomcat/tomcat-9/v9.0.10/bin/apache-tomcat- ...

  6. 内存中加载DLL DELPHI版

    //从内存中加载DLL DELPHI版 unit MemLibrary; interface uses Windows; function memLoadLibrary(pLib: Pointer): ...

  7. Web API与AJAX:理解FormBody和 FormUri的WebAPI中的属性

    这是这一系列文章"与 AJAX 的 Web API".在这一系列我们都解释消耗 Web API rest 风格的服务使用 jQuery ajax() 和其他方法的各种方法.您可以阅 ...

  8. 利用大数据技术处理海量GPS数据

    我秀中国物联网地图服务平台目前接入的监控车辆近百万辆,每天采集GPS数据7亿多条,产生日志文件70GB,使用传统的数据处理方式非常耗时. 比如,仅仅对GPS做一些简单的统计分析,程序就需要几个小时才能 ...

  9. 【Python】生成器和迭代器

    l=[1,2,3,4] for n in l: print n 在看上面这段代码的时候,我们没有显式的控制列表的偏移量,就可以自动的遍历了整个列表对象.那么for 语句是怎么来遍历列表l的呢?要回答这 ...

  10. 遮罩效果 css3

    CSS3提供了遮罩效果,这是以前CSS2中比较难实现的一个新特性,配合SVG或者canvas同样也可以实现遮罩效果,他的效果就如下图所示: 简单的说就是在一个层上面加一个过滤层,过滤层透明度越低,底层 ...