Linux驱动阻塞的实现

Qt之 读取 /dev/input/event*设备 并解析 qt 读取/dev/input/event 设备,并解析数据 阅读详情

文章来源:http://hi.baidu.com/decload/item/5877610a09c894da72e6767e

应用程序:

阻塞地都取串口一个字符

非阻塞地都取串口一个字符

char buf; 
fd = open("/dev/ttys",O_RDWR);
.. .. 
res = read(fd,&buf,1); //当串口上有输入时才返回 
if(res == 1) 
{ 
     printf("%c\n",buf); 
}char buf;
fd = open("/dev/ttys",O_RDWR | O_NONBLOCK);
.. .. 
while( read(fd,&buf,1) !=1); //当串口上无输入也返回,所
                                                //以要循环尝试读取串口
printf("%c\n",buf);

现在我们有了阻塞的方式读取,那么阻塞的进程因为没有获得资源会进入休眠状态,现在就要聊聊有关唤醒的事了。在Linux设备驱动中,可以使用等待队列(wait queue)来实现阻塞进程的唤醒.等待队列能够用于实现内核中的异步事件通知机制。 Linux提供了有关等待队列的操作:1)wait_queue_head_t my_queue; //定义等待队列头2) init_waitqueue_head(&my_queue);   //初始化队列头如果觉得上边两步来的麻烦,可以直接使用DECLARE_WAIT_QUEUE_HEAD(name)   //定义并初始化 3) DECLARE_WAITQUEUE(name,tsk); //定义等待队列4) void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);    void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);

    用于将等待队列wait添加到等待队列头指向的等待队列链表中 。

5) wait_event(queue, conditon);

     wait_event_interruptible(queue, condition);  //可以被信号打断

     wait_event_timeout(queue, condition, timeout);

     wait_event_interruptible_timeout(queue, condition, timeout); //不能被信号打断

     queue:作为等待队列头的等待队列被唤醒

     conditon:必须满足,否则阻塞

     timeout和conditon相比,有更高优先级

6) void wake_up(wait_queue_head_t *queue);

     void wake_up_interruptible(wait_queue_head_t *queue);

     上述操作会唤醒以queue作为等待队列头的所有等待队列中所有属于该等待队列头的等待队列对应的进程。

7) sleep_on(wait_queue_head_t *q);

     interruptible_sleep_on(wait_queue_head_t *q);

     sleep_on作用是把目前进程的状态置成TASK_UNINTERRUPTIBLE,并定义一个等待队列,之后把他附属到等待队列头q,直到资源可用,q引导的等待队列被唤醒。interruptible_sleep_on作用是一样的, 只不过它把进程状态置为TASK_INTERRUPTIBLE.

    这两个函数的流程是首先,定义并初始化等待队列,把进程的状态置成TASK_UNINTERRUPTIBLE或TASK_INTERRUPTIBLE,并将对待队列添加到等待队列头。

然后通过schedule(放弃CPU,调度其他进程执行。最后,当进程被其他地方唤醒,将等待队列移除等待队列头。

    在Linux内核中,使用set_current_state()和__add_wait_queue()函数来实现目前进程状态的改变,直接使用current->state = TASK_UNINTERRUPTIBLE

类似的语句也是可以的。

    因此我们有时也可能在许多驱动中看到,它并不调用sleep_on或interruptible_sleep_on(),而是亲自进行进程的状态改变和切换。

 参考:http://www.cnblogs.com/hanyan225/archive/2010/10/12/1848914.html

 

 

例一:使用 interruptible_sleep_on 函数:

 

static wait_queue_head_t write_wait; //定义写等待队列头
static wait_queue_head_t read_wait;  //定义读等待队列头

static int __init globalfifo_init(void)
{
 //...
 
 //初始化等待队列头
 init_waitqueue_head(&write_wait); 
 init_waitqueue_head(&read_wait);
 
 //...
}

static ssize_t XXX_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{ 
 int ret;
 while (dev->current_len == 0) //无数据可读
 {
  //判断是否非阻塞
  if (filp->f_flags & O_NONBLOCK)
  {
   ret = -EAGAIN;
   goto out;
  }
  
  //定义等待队列并插入读等待队列头,会阻塞
  interruptible_sleep_on(&read_wait);
  
  //被信号唤醒
  if (signal_pending(current))
     {
       ret =  - ERESTARTSYS;
       goto out_2;
     }     
 } 
 
 //....
 //唤醒写等待队列
 wake_up_interruptible(&write_wait); 
 
 //....
 out_2:
  return ret;
}

static ssize_t XXX_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
 int ret;
 while (dev->current_len == GLOBALFIFO_SIZE) //没有写的空间
 {
  //判断是否阻塞
  if (filp->f_flags & O_NONBLOCK)
  {
   ret = -EAGAIN;
   goto out;
  }
 
  //定义等待队列并插入读等待队列头,会阻塞
  interruptible_sleep_on(&write_wait);
  
  //被信号唤醒
  if (signal_pending(current))
     {
       ret =  - ERESTARTSYS;
       goto out_2;
     }          
 } 
 //....
 //唤醒写等待队列
 wake_up_interruptible(&read_wait); 
 //....
 out_2:
  return ret;
}

 

 

 

 

例二: 不使用 interruptible_sleep_on函数, 手工置进程状态和调度

struct globalfifo_dev                                     
{                                                        
  struct cdev cdev; /*cdev结构体*/                       
  unsigned int current_len;    /*fifo有效数据长度*/
  unsigned char mem[GLOBALFIFO_SIZE]; /*全局内存*/              
  wait_queue_head_t r_wait; /*阻塞读用的等待队列头*/    
  wait_queue_head_t w_wait; /*阻塞写用的等待队列头*/    
};

static int __init globalfifo_init(void)
{
 //...
 
 //初始化等待队列头
 init_waitqueue_head(&w_wait); 
 init_waitqueue_head(&r_wait);
 
 //...
}

static ssize_t XXX_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{ 
 int ret;
 struct globalfifo_dev *dev = filp->private_data; //获得设备结构体指针
 DECLARE_WAITQUEUE(wait, current); //定义等待队列
  add_wait_queue(&dev->r_wait, &wait); //将等待队列加入等待队列头
 
 while (dev->current_len == 0) //无数据可读
 {
  //判断是否非阻塞
  if (filp->f_flags & O_NONBLOCK)
  {
   ret = -EAGAIN;
   goto out;
  }
  
  __set_current_state(TASK_INTERRUPTIBLE); //改变进程状态为睡眠
      schedule(); //调度其他进程执行
  
  //被信号唤醒
  if (signal_pending(current))
     {
       ret =  - ERESTARTSYS;
       goto out_2;
     }     
 } 
 
 //....
 //唤醒写等待队列
 wake_up_interruptible(&w_wait); 
 
 //....
 out_2:
  remove_wait_queue(&dev->r_wait, &wait); //从附属的等待队列头移除
  return ret;
}

static ssize_t XXX_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
 int ret;
 struct globalfifo_dev *dev = filp->private_data; //获得设备结构体指针
 DECLARE_WAITQUEUE(wait, current); //定义等待队列
  add_wait_queue(&dev->w_wait, &wait); //进入写等待队列头
 
 while (dev->current_len == GLOBALFIFO_SIZE) //没有写的空间
 {
  //判断是否阻塞
  if (filp->f_flags & O_NONBLOCK)
  {
   ret = -EAGAIN;
   goto out;
  }
 
  __set_current_state(TASK_INTERRUPTIBLE); //改变进程状态为睡眠
     schedule(); //调度其他进程执行
  
  //被信号唤醒
  if (signal_pending(current))
     {
       ret =  - ERESTARTSYS;
       goto out_2;
     }          
 } 
 //....
 //唤醒写等待队列
 wake_up_interruptible(&r_wait); 
 //....
 out_2:
  remove_wait_queue(&dev->w_wait, &wait); //从附属的等待队列头移除
  return ret;
}


Linux驱动入门(五)阻塞方式实现按键驱动 Linux驱动入门(一)字符设备驱动基础 Linux驱动入门(二)操作硬件 Linux驱动入门(三)Led驱动 Linux驱动入门(四)非阻塞方式实现按键驱动 Linux驱动入门(五)阻塞方式实现按键驱动 Linux驱动入门(六)poll机制实现按键驱动 Linux驱动入门(七)使用定时器消除按键抖动 Linux驱动入门(五)阻塞方式实现按键驱动 文章目录Linux驱动入门(五)阻塞方式实现按键驱... 阅读详情

相关推荐

【Linux 驱动开发】六. 中断和阻塞/非阻塞IO的实现

文章系统梳理 Linux 中断机制与阻塞/非阻塞 I/O 驱动实现流程,先解释中断引入的背景、上下半部职责及设备树中断资源的描述方法,随后以 GPIO 按键为例给出旧新两套 GPIO API 的获取虚拟中断号、注册处理函数、同步数据的代码框架,并扩展 threaded IRQ、tasklet、workqueue 等下半部策略。

猫猫的小茶馆 770

linux驱动的阻塞与非阻塞

Linux驱动阻塞的实现 from:http://blog.youkuaiyun.com/wanchres/article/details/7109198  阻塞地都取串口一个字符 非阻塞地都取串口一个字符 char buf; fd = open("/dev/ttys",O_RDWR); .. .. res = read(fd,&buf,1); //当串口上有输入

lishaoqi_scau的专栏 564

【Linux开发】linux设备驱动归纳总结(三):5.阻塞型IO实现

linux设备驱动归纳总结(三):5.阻塞型IO实现 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 一、休眠简介: 进程休眠,简单的说就是正在运行的进程让出CPU。休眠的进程会被内核搁置在在一边,只有当内核再次把休眠的

ZhangPY的专栏 822

linux input读取键盘,Linux键盘原始阅读,有什么更好的,从/ dev / input / event0读取或从标准输入读取?(Linux keyboard raw reading, wh...

Linux键盘原始阅读,有什么更好的,从/ dev / input / event0读取或从标准输入读取?(Linux keyboard raw reading, what's better, reading from /dev/input/event0 or reading from stdin?)我正在为Raspberry Pi制作一个小型C视频游戏库。 我从头开始对输入系统进行编码,在阅读了...

weixin_42314399的博客 735

Linux字符设备驱动中的阻塞I/O实现

本文介绍了Linux字符设备驱动中阻塞I/O的实现方法。针对硬件链接的特殊需求,作者分析了原始驱动在FIFO满时无法被中断的问题,提出了改进方案:通过等待队列(wait_event_interruptible)实现可中断的阻塞操作,并正确处理O_NONBLOCK标志。文中给出了修改后的驱动代码示例和应用场景,展示了如何在非阻塞模式下立即返回错误,或在阻塞模式下响应中断信号。该方案提高了系统可靠性和用户体验,为开发者编写字符设备驱动提供了实用参考。

m0_62153576的博客 42

用LangFuse+LangChain打造可观测的AI应用:从埋点到成本监控实战

本文详细介绍了如何将开源可观测性平台LangFuse深度集成到基于LangChain构建的AI应用中,特别是电商客服机器人场景。通过从基础SDK集成、提示词管理到成本监控的完整实战,帮助开发者实现对LLM应用内部工作流的清晰追踪、问题排查与费用分析,从而打造稳定、可控的生产级AI应用。

dapp9builder的博客 709

linux输入设备在应用层的多种读取方式

1).查询方式与休眠唤醒方式(非阻塞方式与阻塞方式) 查询方式 APP调用open函数时,传入“O_NONBLOCK”表示“非阻塞”。 APP调用read函数读取数据时,如果驱动程序中有数据,那么APP的read函数会返回数据,否则也会立刻返回错误。 休眠唤醒方式 APP调用open函数时,不要传入“O_NONBLOCK”。 APP调用read函数读取数据时,如果驱动程序中有数据,那么APP的read函数会返回数据;否则APP就会在内核态休眠,当有数据时驱动程序会把APP唤醒,read函数恢复执

weixin_49460450的博客 914

安装Tailscale

如果返回 /usr/bin/tailscale 或类似路径,说明已安装但 sudo 可能找不到它。如果 which tailscale 没有输出,说明安装失败,重新执行安装步骤。Tailscale 的后台服务 tailscaled 必须运行。检查 tailscaled 服务是否运行。检查 tailscale 命令是否存在。

FairLikeSnow的博客 1469

陈香兰 linux 视频,阻塞操作. 在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t...

阻塞操作在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t testqueue; init_waitqueue_head(&testqueue);queue: wait_queue_head_t 类型的变量,表示要等待的队列头 condition: 条件判断 timeout: 超...

weixin_39640909的博客 177

PADS安装教程(超详细)

声明:个人实践 一、工具准备 pads9.5完整破解版百度网盘提取码【wjx9】 链接:https://pan.baidu.com/s/1pIP6BJO435ssmF7Hjwyz8A 提取码:wjx9 安装环境:win10 64位 二、开始解压安装 关闭杀毒,exe以管理员身份运行 点击【skip】,不然又得licese 点击【agree】 点击【modify】 设置安装的工具、路径及工程路径 设置完成后,开始【install】 在之后注册。 将Crack复制到PADS安装目录

qq_42057393的博客 5万+

3、全面掌握QGIS开发:从调试到应用的全方位指南

本文全面介绍了QGIS开发的各个环节,涵盖插件调试、PyQGIS API导航、插件创建与分发、独立地理空间应用开发,以及全局和项目级首选项的管理。通过详细的步骤说明、代码示例和流程图,帮助开发者系统掌握QGIS扩展与集成的核心技能,并展望了未来在功能拓展、跨平台兼容性和技术融合方面的可能性。

hill8的博客 89

Linux驱动 阻塞IO及程序实现

(一)阻塞简介: 当应用程序对设备驱动进行操作的时候,如果不能获取到设备资源,那么阻塞式 IO 就会将应用程 序对应的线程挂起,直到设备资源可以获取为止,流程如下: 可知阻塞访问最大的好处就是当设备文件不可操作的时候进程可以进入休眠态,这样可以将 CPU 资源让出来。 (二)等待列队: 1、等待队列头 当设备文件可以操作的时候就必须唤醒进程,一般在中断函数里面完成唤醒工作。 Linux 内核提供了等待队列(wait queue)来实现阻塞进程的唤醒工作,如果我们要在驱动中使用等待队列,必须创建

m0_58844968的博客 224

【OpenCV C++】基本绘图操作

OpenCV C++基本绘图操作程序说明代码运行效果 程序说明 // 程序描述:OpenCV C++基本绘图操作 //参 考:毛星云《OpenCV3编程入门》 // 操作系统: Windows 10 64bit // 开发语言: C++ // IDE 版 本:Visual Studio 2019 // OpenCV版本:4.20 代码 main函数写法很简单,先创建空表Mat图像,然后点用函数绘制化学原子图,接着绘制组合图,最后显示图像。 //-------------------------

程序员,他们想的是什么?他们想的永远都是技术,他们崇尚的也永远都是技术。 765

linux阻塞IO与非阻塞IO在应用层和驱动层的实现(一)

linux的 IO 指的是 Input/Output,也就是输入/输出,是应用程序对驱动设备的输入/输出操作。当应用程序对设备驱动进行操作的时候,如果不能获取到设备资源,那么阻塞式 IO 就会将应用程序对应的线程挂起,直到设备资源可以获取为止。阻塞其实就是进入了休眠状态,交出了 CPU 控制权。对于非阻塞 IO,应用程序对应的线程不会挂起,它要么一直轮询等待,直到设备资源可以使用,要么就直接放弃。

123 1万+

OpenClaw安卓手机攻略

想在安卓手机上安装 OpenClaw,目前主要有两种主流方法:一种是使用专门的,操作简单直观;另一种是在命令行环境下进行,自由度更高。你可以根据自己的偏好和动手能力来选择。

suny8的专栏 2899

QMK固件OLED显示屏配置教程:从零开始实现个性化键盘显示(实操部分)

本教程详细介绍了如何从零开始配置QMK固件的OLED显示屏,实现个性化键盘显示。首先,文章解释了OLED显示屏的基本概念及其在键盘中的应用,并介绍了I2C和SPI两种通信方式。接着,教程逐步指导用户如何在QMK固件中启用OLED功能,包括在rules.mk中启用OLED、在halconf.h和mcuconf.h中配置I2C功能,以及在config.h中设置I2C和OLED参数。最后,教程展示了如何在keymap.c中编写代码,实现OLED显示内容,并提供了进阶定制功能,如显示当前层信息、按键状态和QMK L

Despacito0o的博客 578

Linux 驱动层实现阻塞和非阻塞

linux应用层的函数默认是阻塞型的,但是要想真正实现阻塞,还需要驱动的支持才行。 例:open()、scanf()、fgets()、read()、accept() 等 1、默认情形,驱动层不实现阻塞和非阻塞 struct samsung_key{ int major; int irqno; struct class *cls; struct...

weixin_30865427的博客 164

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

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

Linux驱动入门系列 Linux驱动入门(一)字符设备驱动基础 Linux驱动入门(二)操作硬件 Linux驱动入门(三)Led驱动 Linux驱动入门(四)非阻塞方式实现按键驱动 Linux驱动入门(五)阻塞方式实现按键驱动 Linux驱动入门(六)poll机制实现按键驱动 Linux驱动入门(七)使用定时器消除按键抖动 Linux驱动入门(四)非阻塞方式实现按键驱动 文章目录Linux驱动入...

JT同学的博客 2038

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

linux设备驱动归纳总结(三):5.阻塞型IO实现

CU首页 ┊ fh265>>博客 微博 相册 个人中心 好友 消息 [退出] ┊ 随便看看   博文 博主 相册  投票 活动 发博文 公告:缅怀Dennis Ritchie活动开赛啦! 小白的博客——提升自已,分享别人 xiaobai.blog.chinaunix.net 好的女人可以不共享。好的技术绝对要共享!

fh400的专栏 1565

Linux字符设备驱动中的阻塞与非阻塞IO实现原理

在Linux设备驱动开发中,IO模型是连接用户空间与硬件的核心抽象。阻塞IO通过进程休眠与等待队列实现资源就绪通知,降低CPU空转开销;非阻塞IO则依赖O_NONBLOCK标志和-EAGAIN错误码提供即时响应,支撑select/poll/epoll等多路复用机制。其技术价值在于平衡实时性、吞吐量与系统资源利用率,广泛应用于串口通信、传感器驱动、嵌入式音频等场景。本文深入解析内核中wait_event_interruptible、wake_up_interruptible及kfifo协同机制,结合vser虚

weixin_35189483的博客 347

【Linux驱动】使用异步通知来实现定时器非阻塞延时(实现应用层的定时器回调)

【Linux驱动开发】使用异步通知来实现定时器非阻塞延时(实现应用层的定时器回调)

Mike Zhou的博客 1245

linux设备驱动归纳总结(三):.阻塞型IO实现

linux设备驱动归纳总结(三):5.阻塞型IO实现 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 一、休眠简介: 进程休眠,简单的说就是正在运行的进程让出CPU。休眠的进程会被内核搁置在在一边,只有当内核再次把休眠的进程唤醒,进程才会会

zacklin的专栏 1301

【Linux驱动】Linux阻塞IO —— 阻塞读取按键状态(等待队列实现)

【Linux驱动】Linux阻塞IO —— 阻塞读取按键状态(等待队列实现)

challenglistic的博客 1518

Linux设备驱动——字符设备的高阶驱动实现及关键要素之阻塞型I/O用法详解(休眠与唤醒机制)

指当进程/线程执行某个需求时,因为当下无法立即满足请求,而使其进程或线程阻塞。优点:在某些情况下,阻塞型 I/O 可以更有效地利用系统资源。在一些高负载场景下,可以避免频繁的上下文切换,降低系统开销。而且阻塞型I/O的编程模型通常比较直观和易于理解。代码顺序执行(算作一个同步过程),不需要太多复杂的逻辑来处理异步操作和事件回调。开发经验:(驱动程序应该(默认)阻塞型进程,将其置入休眠状态直到请求可继续)

weixin_56228133的博客 1283
上一篇: Android的IPC机制Binder的各个部分
下一篇: C++直接初始化和复制初始化
计算机与认知
博客等级 码龄14年 31粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值