嵌入式驱动开发详解8(阻塞/非阻塞/异步通信)

embedded/2025/1/8 5:07:37/

文章目录

  • 前言
  • 阻塞
  • 非阻塞
  • 异步通知
  • 后续

前言

首先来回顾一下“中断”,中断是处理器提供的一种异步机制,我们配置好中断以后就 可以让处理器去处理其他的事情了,当中断发生以后会触发我们事先设置好的中断服务函数, 在中断服务函数中做具体的处理。同样的,Linux 应用程序可以通过阻塞或者非阻塞这两种方式来访问驱动设备,通过阻塞方式访问的话应用程序会处于休眠态,等待驱动设备可以使用,非阻塞方式的话会通过 poll 函数来不断的轮询,查看驱动设备文件是否可以使用。这两种方式都需要应用程序主动的去查询设备的使用情况;“信号”为此应运而生,信号类似于我们硬件上使用的“中断”,只不过信号是软件层次上的。算是在软件层次上对中断的一种模拟,驱动可以通过主动向应用程序发送信号的方式来报告自己可以访问了,应用程序获取到信号以后就可以从驱动设备中读取或者写入数据了,这就是异步通行,接下来我将逐一分析阻塞,非阻塞和异步通知三种访问模式。

阻塞

在这里插入图片描述原理:应用程序调用 read 函数从设备中读取数据,当设备不可用或数据未准备好的 时候就会进入到休眠态。等设备可用的时候就会从休眠态唤醒,然后从设备中读取数据返回给 应用程序。
特点:当设备文件不可操作的时候进程可以进入休眠态,这样可以将 CPU 资源让出来。
使用方法Linux 内核提供了等待队列(wait queue)来实现阻塞进程的唤醒工作,先创建并初始化一个等待队列------>每个访问设备的进程都是一个队列项,当设备不可用的时候就要将这些进程对应的等待队列项添加到等待队列里面,添加到等待队列头中以后进程才能进入休眠态------>当设备可以使用的时候就要唤醒进入休眠态的进程,一般在中断函数里面完成唤醒工作。
API函数:API详细介绍肯定没有百度自行搜索详细,这里只列举一些API函数。

  1. 等待队列头初始化:
    void init_waitqueue_head(wait_queue_head_t *q)
  2. 定义并初始化一个等待队列项:
    DECLARE_WAITQUEUE(name, tsk)
  3. 将队列项添加/移除等待队列头:
    void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
    void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
  4. 等待唤醒(手动唤醒):
    void wake_up(wait_queue_head_t *q)
    void wake_up_interruptible(wait_queue_head_t *q)
  5. 等待唤醒(事件唤醒):
    在这里插入图片描述

非阻塞

在这里插入图片描述原理:应用程序使用非阻塞访问方式从设备读取数据,当设备不可用或 数据未准备好的时候会立即向内核返回一个错误码,表示数据读取失败。应用程序会再次重新读取数据,这样一直往复循环,直到数据读取成功。
特点:需要应用程序通过 poll 函数不断的轮询。
使用方法:应用程序通过 select、epoll 或 poll 函数来查询设备是否可以操作,如果可以操作的话就从设备读取或者向设备写入数据。当应用程序调用 select、epoll 或 poll 函数的时候设备驱动程序中的 poll 函数就会执行,因此需要在设备驱动程序中编写 poll 函数。
API函数

  • select函数:在单个线程中,select 函数能够监视的文件描述符数量有最大的限制,一般为 1024。
    int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
  • poll函数:poll 函数本质上和 select 没有太大的差别,但是 poll 函数没有最大文件描述符限制。
    int poll(struct pollfd *fds, nfds_t nfds, int timeout)
  • epoll函数:epoll 就是为处理大并发而准备的,一般常常在网络编程中使用 epoll 函数。
    int epoll_create(int size)//size从 Linux2.6.8 开始此参数已经没有意义了,随便填写一个大于 0 的值就可以。
    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
    int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
  • 驱动程序 poll 函数:当应用程序调用 select 或 poll 函数来对驱动程序进行非阻塞访问的时候,驱动程序 file_operations 操作集中的 poll 函数就会执行。
    unsigned int (*poll) (struct file *filp, struct poll_table_struct *wait)
    驱动程序的 poll 函数中调用 poll_wait 函数,poll_wait 函数不会引起阻塞,只是 将应用程序添加到 poll_table 中
    void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)

异步通知

原理:异步通知的核心就是信号,在 arch/xtensa/include/uapi/asm/signal.h 文件中定义了 Linux 所支 持的所有信号:在这里插入图片描述“kill -9 PID”杀死指定进程的方法就是向指定的进程(PID)发送 SIGKILL 这个信号。当按下键盘上的 CTRL+C 组合键以后会向当前正在占用终端的应用程序发 出 SIGINT 信号,SIGINT 信号默认的动作是关闭当前应用程序。
特点:驱动通过主动向应用程序发送信号来报告自己可以访问,而不是通过应用程序来访问自己。
使用方法:如果要使用异步通知,需要在设备驱动中实现 file_operations 操作集中的 fasync 函数,fasync 函数里面一般通过调用 fasync_helper 函数来初始化前面定义的 fasync_struct 结构体指针,当应用程序通过“fcntl(fd, F_SETFL, flags | FASYNC)”改变 fasync 标记的时候,驱动程序 file_operations 操作集中的 fasync 函数就会执行。当设备可以访问的时候,驱动程序需要向应用程序发出信号,相当于产生“中断”。kill_fasync 函数负责发送指定的信号,应用程序收到信号后就会执行对应的中断回调函数;在关闭驱动文件的时候需要在 file_operations 操作集中的 release 函数中释放 fasync_struct。

后续

三种访问方式都有对应的例程,可以参考链接:https://github.com/NUAATRY/imx6ull_dev 中的实验12-14。


http://www.ppmy.cn/embedded/152190.html

相关文章

VulnHub—potato-suncs

使用命令扫描靶机ip arp-scan -l 尝试访问一下ip 发现一个大土豆没什么用 尝试扫描一下子域名 没有发现什么有用的信息 尝试扫描端口 namp -A 192.168.19.137 -p- 尝试访问一下端口,发现都访问不进去 查看源代码发现了网页的标题 potato,就想着爆破一下密码 hydr…

【软考网工笔记】计算机基础理论与安全——网络安全

病毒 Melissa 宏病毒 1. 是一种快速传播的能够感染那些使用MS Word 97 和MS Office 2000 的计算机宏病毒。 2. 前面有**Macro** 表示这是宏病毒; 3. 宏病毒可以感染后缀为.xls的文件;Worm 蠕虫病毒 1. 通常是通过网络或者系统漏洞进行传播。 2. 利用信…

C++二十三种设计模式之桥接模式

C二十三种设计模式之桥接模式 一、组成二、特点三、目的四、缺点五、示例代码 一、组成 抽象类:声明功能接口,维护实现类的引用。 扩展抽象类:调用实现类功能接口,并实现自己的功能接口。 实现类:声明功能接口。 具体…

最好用的图文识别OCR -- PaddleOCR(1) 快速集成

最近在项目中遇到了 OCR 的需求,希望能够实现高效而准确的文字识别。由于预算限制,我并未选择商业付费方案,而是优先尝试了开源工具。一开始,我测试了 GOT-OCR2.0,但由于我的 Mac 配置较低,不支持 GPU 运算…

VVenC 编码器源码结构与接口函数介绍

VVenC VVenC(Fraunhofer Versatile Video Encoder)是由德国弗劳恩霍夫海因里希研究所(Fraunhofer Heinrich Hertz Institute, HHI)开发的一个开源的高效视频编码器。它实现了最新的视频编码标准——Versatile Video Coding (VVC)…

flink的EventTime和Watermark

时间机制 Flink中的时间机制主要用在判断是否触发时间窗口window的计算。 在Flink中有三种时间概念:ProcessTime、IngestionTime、EventTime。 ProcessTime:是在数据抵达算子产生的时间(Flink默认使用ProcessTime) IngestionT…

ESP32模组物联网方案,高性能通信无线交互,设备智能化升级应用

随着物联网技术的迅猛发展,我们的生活和工作方式正在发生众多变化。智能家居和工业自动化作为物联网应用的两大支柱,正在深刻地影响着我们的日常。 从家中的智能插座到工厂里的自动化生产线,物联网设备无处不在,它们通过无线网络…

EasyExcel监听器详解

EasyExcel监听器详解 EasyExcel 监听器概述 EasyExcel 是一个 Java 语言编写的简单易用的 Excel 操作框架。它的监听器机制允许开发者在读取或写入 Excel 文件时,以事件驱动的方式来处理数据,而不是一次性将整个 Excel 文件的数据加载到内存中。这种方式…