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 > 0){printk("copy_to_user error\n");return -EFAULT;}memset(&key_dev->event, 0, sizeof(struct key_event));    return 0;
}// 中断处理程序,多个按键可以根据 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 = 0) : (key_dev->key.value = 1);  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(2);  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;// 判断是否阻塞,条件为假,就会阻塞,让出cpuwait_event_interruptible(key_dev->wq_head,key_dev->have_data);ret = copy_to_user(buf, &key_dev->event, count);if(ret > 0){printk("copy_to_user error\n");return -EFAULT;}memset(&key_dev->event, 0, sizeof(struct key_event));key_dev->have_data = 0;    return 0;
}// 中断处理程序,多个按键可以根据 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 = 0) : (key_dev->key.value = 1);  printk("key = %d status = %d\n", key_dev->key.name, key_dev->key.value);  key_dev->have_data = 1;// 唤醒wake_up_interruptible(&key_dev->wq_head);// 返回值一定要是 IRQ_HANDLED  return IRQ_HANDLED;
}  static int __init key_drv_init(void)
{  ... ...  key_dev->irqno = IRQ_EINT(2);  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 > 0){printk("copy_to_user error\n");return -EFAULT;}memset(&key_dev->event, 0, sizeof(struct key_event));key_dev->have_data = 0;    return 0;
}// 应用层以非阻塞的方式
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;// 判断是否阻塞,条件为假,就会阻塞,让出cpuwait_event_interruptible(key_dev->wq_head,key_dev->have_data);ret = copy_to_user(buf, &key_dev->event, count);if(ret > 0){printk("copy_to_user error\n");return -EFAULT;}memset(&key_dev->event, 0, sizeof(struct key_event));key_dev->have_data = 0;    return 0;
}

转载于:https://www.cnblogs.com/lialong1st/p/7756671.html

Linux 驱动层实现阻塞和非阻塞相关推荐

  1. Linux驱动入门(四)非阻塞方式实现按键驱动

    Linux驱动入门系列 Linux驱动入门(一)字符设备驱动基础 Linux驱动入门(二)操作硬件 Linux驱动入门(三)Led驱动 Linux驱动入门(四)非阻塞方式实现按键驱动 Linux驱动入 ...

  2. Linux 设备驱动中的 I/O模型(一)—— 阻塞和非阻塞I/O

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

  3. Linux驱动开发6 阻塞与非阻塞

    阻塞和非阻塞 IO 是 Linux 驱动开发里面很常见的两种设备访问模式,在编写驱动的时候 一定要考虑到阻塞和非阻塞.本章我们就来学习一下阻塞和非阻塞 IO ,以及如何在驱动程序中 处理阻塞与非阻塞, ...

  4. linux驱动 阻塞和非阻塞IO 篇二

    @上一篇介绍了linux阻塞与非阻塞的基本概念,以及应用程序的小demo和kernel层对应的api函数.那接下来就以实例来分析,如何在linux驱动层添加等待队列和轮询的方法,以及区别. ** 一: ...

  5. linux设备驱动学习(四)——阻塞与非阻塞I/O

    1.阻塞与非阻塞I/O介绍 阻塞和非阻塞I/O是设备访问的两种不同模式.阻塞操作是指在执行设备操作时,若不能获得资源,则挂起进程直到满足可操作的条件后再进行操作.被挂起的进程进入睡眠状态,被从调度器的 ...

  6. linux 设备驱动阻塞,深入浅出:Linux设备驱动中的阻塞和非阻塞I/O

    今天写的是Linux设备驱动中的阻塞和非阻塞I/0,何谓阻塞与非阻塞I/O?简单来说就是对I/O操作的两种不同的方式,驱动程序可以灵活的支持用户空间对设备的这两种访问方式. 一.基本概念: 阻塞操作 ...

  7. linux驱动开发 - 10_阻塞和非阻塞 IO

    文章目录 1 阻塞和非阻塞 IO 1.1 阻塞和非阻塞简介 1.2 等待队列 1.等待队列头 2.等待队列项 3.将队列项添加/移除等待队列头 4.等待唤醒 5.等待事件 1.3 Linux驱动下的p ...

  8. linux驱动阻塞和非阻塞

    文章目录 一.阻塞与非阻塞理解 二.阻塞在内核实现--等待队列 三.非阻塞在内核实现--轮询 1.select 2. poll 函数 3. epoll 函数 一.阻塞与非阻塞理解 1.阻塞 如果不能获 ...

  9. linux write引起进程挂起,Linux设备驱动中的阻塞与非阻塞总结

    Linux设备驱动中的阻塞与非阻塞总结 阻塞操作是指,在执行设备操作时,若不能获得资源,则进程挂起直到满足可操作的条件再进行操作. 非阻塞操作的进程在不能进行设备操作时,并不挂起.被挂起的进程进入sl ...

  10. Linux设备驱动中的阻塞与非阻塞I/O

    阻塞和非阻塞I/O是设备访问的两种不同模式,驱动程序可以灵活的支持用户空间对设备的这两种访问方式 本例子讲述了这两者的区别 并实现I/O的等待队列机制, 并进行了用户空间的验证 基本概念: 1> ...

最新文章

  1. SpringMVC+Apache Shiro+JPA(hibernate)案例教学(二)
  2. zz[as3 hack技术]垃圾回收机强制执行
  3. nginx 配置简介
  4. Debian | 软件安装升级点滴记录
  5. python中函数重载和重写
  6. ubuntu 16.04 apache 开启Rewrite功能
  7. 锐捷交换机配置命令大全_锐捷交换机常用配置命令汇总
  8. labeme批量转换json文件_Python实现markdown文件批量转换为word
  9. spring boot 学习(十一)使用@Async实现异步调用
  10. python求两个数的最大值、用带参函数实现_Python有参函数使用代码实例
  11. AOJ2025 Eight Princes
  12. python模块规定的格式,按照这样写,最规范
  13. 异常0x0000005
  14. 听课记录高中计算机,高中听课记录
  15. GitHub 上发现的几个好项目
  16. 确定性网络:从“尽力而为”到“确定承诺”
  17. 华为机考108题(c++)(41-51)
  18. hpp文件和h文件有什么区别
  19. 【转】Microsoft Teams 常见问题
  20. 软件测试日记-了解CRM系统

热门文章

  1. 如何打造基于 markdown 的论文工作流程(一)
  2. Egret入门学习日记 --- 第八篇(书中 2.0~2.6节 内容)
  3. python实现汉诺塔(递归)
  4. 【js高级程序设计】迭代器
  5. 学习总结之 WebApi 用户登录和匿名登录,及权限验证
  6. unity5, Configurable Joint: Anchor, Connected Anchor, Auto Configure Connected Anchor
  7. 体验下Xcode5与ios7
  8. Extjs 屏蔽F5
  9. 有关parent.frame.cols在firefox浏览器上不兼容的问题解决
  10. JavaScript函数和对象