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驱动之同步、互斥、阻塞的应用
同步.互斥.阻塞的概念: 同步:在并发程序设计中,各进程对公共变量的访问必须加以制约,这种制约称为同步. 互斥机制:访问共享资源的代码区叫做临界区,这里的共享资源可能被多个线程需要,但这些共享资源又不 ...
随机推荐
- fabric动态获取远程目录列表
#!/usr/bin/pythonfrom fabric.api import *env.user='root'env.hosts=['172.10.224.183','172.10.224.132' ...
- SpringBoot2.0整合Sharding-Jdbc
maven: <parent> <groupId>org.springframework.boot</groupId> <artifactId>spri ...
- Search a 2D Matrix,在有序矩阵查找,二分查找的变形; 行有序,列有序查找。
问题描述:矩阵每一行有序,每一行的最后一个元素小于下一行的第一个元素,查找. 算法分析:这样的矩阵其实就是一个有序序列,可以使用折半查找算法. public class SearchInSortedM ...
- 解析CEPH: 存储引擎实现之一 filestore
Ceph作为一个高可用和强一致性的软件定义存储实现,去使用它非常重要的就是了解其内部的IO路径和存储实现.这篇文章主要介绍在IO路径中最底层的ObjectStore的实现之一FileStore. Ob ...
- 更新CentOS 6.7源为阿里源
1.备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2.下载新的CentOS-Base ...
- Java 自定义注解实现ORM对象关系映射
一,ORM概念 ORM即Object Relation Mapping,Object就是对象,Relation就是关系数据库,Mapping映射,就是说Java中的对象和关系数据库中的表存在一种对应关 ...
- T-SQL RIGHT JOIN
RIGHT JOIN外联接与LEFT JOIN相似.取得右表所有记录,并按过滤条件ON去取得左表的记录,取得这些记录,如遇上没有匹配的列使用NULL填充. 演示数据来源,两张表来自http://www ...
- Go语言 channel 管道 阻塞 死锁 经典问题
建议阅读:14.2协程间的信道 问题:为什么代码1会报死锁的错误,而代码2不会报错? 代码1: package main import ( "fmt" ) func main() ...
- charles抓包工具的使用:手机抓包设置和安装证书
一. 设置手机抓包 第一步:在charles里设置允许手机联网的权限,并设置接入接口 在Charles的菜单栏上选择"Proxy"->"Proxy Settings ...
- Python 用Redis简单实现分布式爬虫
Redis通常被认为是一种持久化的存储器关键字-值型存储,可以用于几台机子之间的数据共享平台. 连接数据库 注意:假设现有几台在同一局域网内的机器分别为Master和几个Slaver Master连接 ...