异步通知实验

news2024/9/27 5:47:28

目录

一、异步通知简介

阻塞、非阻塞、异步通知区别

信号与信号修改测试

测试

二、驱动编写

1、定义fasync_struct 结构体指针变量

2、操作集添加fasync

3、实现imx6uirq_fasync 函数

 4、关闭驱动文件操作

​编辑

5、定时器处理函数

三、编写APP

1、编写信号的处理函数

2、信号处理与异步通知

代码如下

imx6uirq设备结构体

 操作集

 imxuirq_fasync函数

 imx6uirq_release函数

 定时器处理函数

 APP

验证 


       在前面使用阻塞或者非阻塞的方式来读取驱动中按键值都是应用程序主动读取的,对于非阻塞方式来说还需要应用程序通过 poll 函数不断的轮询。最好的方式就是驱动程序能主动向应用程序发出通知,报告自己可以访问,然后应用程序在从驱动程序中读取或写入数据,Linux 提供了异步通知个机制来完成此功能。

一、异步通知简介

        首先来回顾一下“中断”,中断是处理器提供的一种异步机制,我们配置好中断以后就可以让处理器去处理其他的事情了,当中断发生以后会触发我们事先设置好的中断服务函数,在中断服务函数中做具体的处理。采用中断以后处理器就不需要时刻的去查看也没有出发中断的事件发生,因为会触发中断的事件发生以后会自动触发中断。同样的, Linux 应用程序可以通过阻塞或者非阻塞这两种方式来访问驱动设备,通过阻塞方式访问的话应用程序会处于休眠态,等待驱动设备可以使用,非阻塞方式的话会通过 poll 函数来不断的轮询,查看驱动设备文件是否可以使用。这两种方式都需要应用程序主动的去查询设备的使用情况。如果能提供一种类似中断的机制,当驱动程序可以
访问的时候主动告诉应用程序那就最好。

        “信号”为此应运而生,信号类似于我们硬件上使用的“中断”,只不过信号是软件层次上的。算是在软件层次上对中断的一种模拟,驱动可以通过主动向应用程序发送信号的方式来报告自己可以访问了,应用程序获取到信号以后就可以从驱动设备中读取或者写入数据了。整个过程就相当于应用程序收到了驱动发送过来了的一个中断,然后应用程序去响应这个中断,在整个处理过程中应用程序并没有去查询驱动设备是否可以访问,一切都是由驱动设备自己告诉给应用程序的

阻塞、非阻塞、异步通知区别

阻塞: 进程等待设备资源可用, 等待过程中, 进程休眠(CPU切换去执行别的进程)        

        :(我睡觉等你,好了就叫醒我执行)

非阻塞: 不等待,轮询设备

        :(你好了没有啊?你好了没有啊?你好了没有啊?你好了没有啊?... ... ...)

异步通知: 让设备主动去通知进程

        :(你叫我)

阻塞、非阻塞、异步通知,这三种是针对不同的场合提出来的不同的解决方法,没有优劣
之分,在实际的工作和学习中,根据自己的实际需求选择合适的处理方法即可

信号与信号修改测试

        异步通知的核心就是信号,在 arch/xtensa/include/uapi/asm/signal.h 文件中定义了 Linux 所支持的所有信号,这列出几个,如下

#define SIGKILL        9         /* 杀死、终止进程 */

#define SIGQUIT       3         /* 终端退出(Ctrl+\组合键) */
#define SIGINT         2         /* 终端中断(Ctrl+C 组合键) */
#define SIGSTOP    19        /* 停止进程的执行,只是暂停 */

#define SIGIO          29        /* 可以进行输入/输出操作 */

        在信号里,除了 SIGKILL(9)和 SIGSTOP(19)这两个信号不能被忽略外,其他的信号都可以忽略。这些信号就相当于中断号,不同的中断号代表了不同的中断,不同的中断所做的处理不同,因此,驱动程序可以通过向应用程序发送不同的信号来实现不同的功能。

        使用中断的时候需要设置中断处理函数,同样的,如果要在应用程序中使用信号,那么就必须设置信号所使用的信号处理函数,在应用程序中使用 signal 函数来设置指定信号的处理函数, signal 函数原型如下所示:

sighandler_t signal(int signum, sighandler_t handler)
signum:要设置处理函数的信号。
handler: 信号的处理函数。
返回值: 设置成功的话返回信号的前一个处理函数,设置失败的话返回 SIG_ERR

信号处理函数原型如下所示

typedef void (*sighandler_t)(int)

        前面讲解的使用“ kill -9 PID”杀死指定进程的方法就是向指定的进程(PID)发送SIGKILL 这个信号。当按下键盘上的 CTRL+C 组合键以后会向当前正在占用终端的应用程序发出 SIGINT 信号, SIGINT 信号默认的动作是关闭当前应用程序。这里我们修改一下 SIGINT 信号的默认处理函数,当按下 CTRL+C 组合键以后先在终端上打印出“SIGINT signal!”这行字符串,然后再关闭当前应用程序。

测试

下面用vim编写修改一个终端中断(Ctrl+C 组合键)处理

 13行,调用signal 函数,SIGINT是要设置处理函数的信号。sigint_handler: 信号的处理函数。
             这里简单一些就不接收返回值

5-9行,信号的处理函数,这里就直接打印字符串,然后就关闭退出当前应用程序

执行结果如下

 运行程序之后,按ctrl+c就会打印字符串并且退出运行

二、驱动编写

复制利用之前的中断实验工程,修改makefile和把app名字修改,留下文件如下左,其余文件删除

添加头文件

#include <linux/poll.h>      

#include <linux/ide.h>   

#include <linux/fcntl.h>

1、定义fasync_struct 结构体指针变量

一般需要将fasync_struct 结构体指针变量定义到设备结构体中

50行就是在 imx6uirq_dev 中添加了一个 fasync_struct 结构体指针变量

2、操作集添加fasync

如果要使用异步通知,需要在设备驱动中实现 file_operations 操作集中的 fasync 函数

 

3、实现imx6uirq_fasync 函数

 89行,设置私有数据

90行,通过调用 fasync_helper 函数来初始化前面定义的 fasync_struct 结构体指针, 原型如下

int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
前三个参数就是 imx6uirq_fasync 函数的那三个参数

第四个参数就是要初始化的 fasync_struct 结构体指针变量。

 4、关闭驱动文件操作

在关闭驱动文件的时候需要在 file_operations 操作集中的 release 函数中释放 fasync_struct,
fasync_struct 的释放函数同样为 fasync_helper 函数

 97行,删除异步通知,把fd设置为-1(fd文件描述符从0开始,错误为负)

5、定时器处理函数

 132-134行,判断按键是否释放,是的话使用kill_fasync 函数发送SIGIO信号,也就是可以进行输入/输出操作。当设备可以访问的时候,驱动程序需要向应用程序发出信号,相当于产生“中断”。 kill_fasync函数负责发送指定的信号, 原型如下所示:

void kill_fasync(struct fasync_struct **fp, int sig, int band)
fp:要操作的 fasync_struct。
sig: 要发送的信号。
band: 可读时设置为 POLL_IN,可写时设置为 POLL_OUT。
返回值: 无

 驱动到这就添加好了,下面编写APP

三、编写APP

添加头文件

#include <signal.h> #include <fcntl.h>

1、编写信号的处理函数

 18行,利用读操作,把驱动的keyvalue值读出来

22行,读取成功就打印

2、信号处理与异步通知

52行,使用 signal 函数来设置指定信号的处理函数,在上面测试ctrl+c组合键的时候有介绍

53行,利用fcntl函数设置当前进程接收信号,函数原型如下         

int fcntl(int fd, int cmd,... );

参数fd是被参数cmd操作的文件描述符

cmd有很多选项,这里就使用F_GETFL通过 getpid()获取当前的进程ID接收SIGIO信号

54行,用flags接收fcntl函数获取当前文件状态

55行,开启当前进程异步通知功能,重点就是通过 fcntl 函数设置进程状态为 FASYNC,经过这一步,驱动程序中的 fasync 函数就会执行

代码如下

imx6uirq设备结构体

struct imx6uirq_dev{
    dev_t devid;
    int major;
    int minor;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    struct device_node *nd;
    struct irq_keydesc irqkey[KEY_NUM];
    struct timer_list timer;
    atomic_t keyvalue;
    atomic_t releasekey;

    struct fasync_struct *fasync_queue;
}imx6uirq;

 操作集

static const  struct file_operations imx6uirq_fops = {
    .owner	=   THIS_MODULE,
    .open   =   imx6uirq_open,
    .read   =   imx6uirq_read,
    .write  =   imx6uirq_write,
    .release =  imx6uirq_release,

    .fasync = imx6uirq_fasync,
};

 imxuirq_fasync函数

static int imx6uirq_fasync(int fd, struct file *filp,int on)
{
    struct imx6uirq_dev *dev = filp->private_data;
    return fasync_helper(fd, filp , on , &dev->fasync_queue);
} 

 imx6uirq_release函数

static int imx6uirq_release(struct inode *inode, struct file *filp)
{
    return imx6uirq_fasync(-1, filp, 0);
}

 定时器处理函数

/*定时器处理函数*/
static void timer_func(unsigned long arg){
    int value = 0;
    struct imx6uirq_dev *dev = (struct imx6uirq_dev *)arg;
    value = gpio_get_value(dev->irqkey[0].gpio);
    if(value == 0){
        /*按下*/
        atomic_set(&dev->keyvalue,dev->irqkey[0].value);

    }else if(value == 1){
        /*释放*/
        atomic_set(&dev->keyvalue,0x80 | (dev->irqkey[0].value));
        atomic_set(&dev->releasekey,1);
    }
    if(atomic_read(&dev->releasekey))/*有效按键过程*/
    {
        kill_fasync(&dev->fasync_queue,SIGIO , POLL_IN);
        
    }
}

 APP

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <fcntl.h>

static int fd;

static void sigio_signal_func(int num)
{
    int err =0;
    unsigned int keyvalue = 0;
    err = read(fd , &keyvalue, sizeof(keyvalue));
    if(err < 0){

    }else{
        printf(" sigio signal! key value = %d\r\n",keyvalue);
    }
}

/*
    argc:应用程序参数个数(argv数组元素个数)
    argv:具体参数,也可以写作char **argv
    ./asyncnotiAPP <filename>    
    ./asyncnotiAPP  /dev/imx6uirq
*/
int main(int argc, char *argv[])
{
    int ret,flags=0;
    char *filename;
    unsigned char data;
    
    /*判断命令行输入参数是否正确*/
    if(argc != 2){
        printf("error usage!\r\n");
        return -1;
    }
    /*用指针指向文件*/
    filename = argv[1];
    /*打开文件*/
    fd = open(filename , O_RDWR);
    if(fd < 0){
        printf("file open failed\r\n",filename);
        return -1;
    }
    /*设置信号处理函数*/
    signal(SIGIO , sigio_signal_func);
    fcntl(fd , F_SETOWN,getpid());/*设置当前进程接收SIGIO信号*/
    flags = fcntl(fd , F_SETFL);
    fcntl(fd , F_SETFL , flags | FASYNC);/*异步通知*/
    while (1)
    {
        sleep(2);
    }
    
    /*关闭文件*/
    close(fd);

    return 0;
}

验证 

 启动之后按下按键就会打印出值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/376192.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ElasticSearch 学习笔记总结(二)

文章目录一、ES JavaAPI 环境准备二、ES JavaAPI 索引1. 索引 创建2. 索引 查找3. 索引 删除三、ES JavaAPI 文档1. 文档 创建2. 文档 修改3. 文档 查询4. 文档 删除4. 文档 批量新增 和 批量删除5. 高级查询 索引全量查询6. 高级查询四、ES 集群1. ES集群 概念2. window 集群搭…

阿里P8:做测试10年我的一些经验分享,希望你们少走弯路

我是在2015年毕业的&#xff0c;当时是读的普通本科&#xff0c;不上不下的专业水平&#xff0c;毕业的时候&#xff0c;恰好遇到了金融危机。校园招聘里阴差阳错的巧合&#xff0c;让我走上了软件测试工程师的道路。 入职第一天&#xff0c;来了个高大上的讲师&#xff0c;记…

如何使用码匠连接 PostgreSQL

目录 在码匠中集成 PostgreSQL 在码匠中使用 PostgreSQL 关于码匠 PostgreSQL 是一种特性非常齐全的自由软件的对象-关系型数据库管理系统&#xff08;ORDBMS&#xff09;&#xff0c;它具有许多强大的功能&#xff0c;PostgreSQL 支持大部分的 SQL 标准并且提供了很多其他现…

一些无线通信系统模型的概念

一些无线通信系统模型的概念 扩频通信,指的是系统的带宽WWW远大于其信息传输速率R(bits/s)R(bits/s)R(bits/s), 定义展频带因子BeWRB_e \frac{W}{R}Be​RW​, 易知在扩频通信系统中,BeB_eBe​远大于1. 在频率上产生如此大的冗余度,主要是为了减轻无线通信或卫星通信中经常产生…

关于算法学习和刷题的建议

大家好&#xff0c;我是方圆。最近花时间学了学算法&#xff0c;应该算是我接触Java以来第一次真正的学习它&#xff0c;这篇帖子我会说一些我对算法学习的理解&#xff0c;当然这仅仅是浅浅的入算法的门&#xff0c;如果想深挖或者是有基础的人想提升自己&#xff0c;我觉得这…

【Linux】内核同步机制之等待队列和完成量

文章目录完成量和等待队列1. 等待队列1.1 基本元素1.2 等待队列的创建和初始化1.3 等待队列元素的创建和初始化1.4 添加和移除等待队列元素到等待队列2. 等待事件机制3. 等待队列唤醒4. 总结4.1 等待事件方式4.2 手动休眠方式4.3 借助内核封装函数&#xff0c;进行手动休眠5. 完…

前端开发_快应用开发

目录快应用官网真机调试组件组件嵌套问题tab组件list组件web组件css 样式问题[1]选择器[2]盒模型[3]样式布局-弹性布局[4-1]样式切换 - 类名的动态切换[4-2] 样式切换 - 行内样式动态切换[5]background[6]overflow[7]border-radius[8]盒子阴影[9] 单位系统接口[1] 检查某app是否…

机房运维6大隐患,你中了几个?

随着医院的看诊预约、缴费、打印报告等众多业务转至线上进行&#xff0c;对医院的网络及数据处理能力提出越来越高的要求&#xff0c;那么&#xff0c;机房的稳定、安全运行是医院网络信息系统的关键因素。 机房运维6大隐患 01.电源电力系统不稳定&#xff0c;网络设备运转遭到…

华为面试题就这?00后卷王直接拿下30k华为offer......

先说一下我的情况&#xff0c;某211本计算机&#xff0c;之前在深圳那边做了大约半年多少儿编程老师&#xff0c;之后内部平调回长沙这边&#xff0c;回来之后发现有点难&#xff0c;这边可能是业绩难做&#xff0c;虚假承诺很厉害&#xff0c;要给那些家长虚假承诺去骗人家&am…

红日(vulnstack)1 内网渗透ATTCK实战

环境准备 靶机链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;sx22 攻击机系统&#xff1a;kali linux 2022.03 网络配置&#xff1a; win7配置&#xff1a; kali配置&#xff1a; kali 192.168.1.108 192.168.111.129 桥接一块&#xff0c;自定义网卡4 win7 1…

一文读懂云渲染“串流”全链路时延及优化策略

​这是一个让云游戏完美起步的时代。 云游戏作为产业内近年来炙手可热的话题&#xff0c;具有“云端运行、超高清、零延时、即点即玩”等众多特性。 随着 5G 时代的到来&#xff0c;以及中心云能力下沉至边缘云&#xff0c;高带宽、低延迟、高性能这些特性与云游戏紧密结合&a…

FastDDS-2.库概览

2. 库概览 Fast DDS&#xff08;前身为Fast RTPS&#xff09;是DDS规范的高效高性能实现&#xff0c;DDS规范是一种用于分布式应用软件的以数据为中心的通信中间件&#xff08;DCPS&#xff09;。本节回顾Fast DDS的体系结构、操作和关键特性。 2.1 架构 Fast DDS的架构如下图…

07_MySQL的单行函数

1. 函数的理解1.1 什么是函数函数在计算机语言的使用中贯穿始终&#xff0c;函数的作用是什么呢&#xff1f;它可以把我们经常使用的代码封装起来&#xff0c;需要的时候直接调用即可。这样既提高了代码效率 &#xff0c;又提高了可维护性 。在 SQL 中我们也可以使用函数对检索…

python之wheel 包命名规则、abi 兼容和安装

一、windows安装python包&#xff0c;遇见的问题 1、python3以后的版本&#xff0c;安装python包&#xff0c;可以直接使用pip安装&#xff0c;但是安装时偶尔报错 2、安装python源码包&#xff0c;如何确定自己该安装哪个版本&#xff0c;一看就晕倒~~~&#xff08;没人扶&…

PMP新考纲考试难不难,通过率怎样?

PMP考试难不难&#xff0c;还是因人而异的&#xff0c;对小白而言&#xff0c;肯定是难的&#xff0c;对项目管理老人而言&#xff0c;难度肯定是没那么高。 据考过的朋友讲&#xff0c;新考纲是有点难度的&#xff0c;尤其是最开始6月25日的考试&#xff0c;2023年就简单些了…

职场性别报告,男女薪酬仍有差距,男性平均薪酬比女性高29.7%

性别是否影响职业&#xff1f;女性求职比男性更加困难&#xff1f;男性薪酬比女性更有优势&#xff1f;人们一说到警察、建筑师通常会想到高大魁梧的男性形象&#xff0c;一说到幼师、护士往往想到的都是温柔的女性形象&#xff0c;职业好似与性别挂钩&#xff1b;女性求职通常…

OnlyOffice验证(二)在Centos7上部署OnlyOffice编译结果

在Centos7上部署OnlyOffice编译结果 此处将尝试将OnlyOffice验证&#xff08;一&#xff09;DocumentServer编译验证的结果部署到Centos7上。并且使用其它服务器现有的RabbitMq和Mysql。 安装Nginx 先安装Nginx需要的依赖环境&#xff1a; yum install openssl* -y yum insta…

java本地搭建宝塔部署实战likeadmin后台管理系统源码 - server端(一)

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 上次分享了那几期likeadmin的搭建视频教程&#xff0c;由于是php开发的&#xff0c;这对有些习惯用java开发的同学不太友好&#xff0c;好在这套系统也有java版本的&#xff0c;也有朋友让我录制java版的搭建教程…

1. 驱动开发--基础知识

文章目录1 驱动的概念2 linux体系架构3 模块化设计3.1 微内核和宏内核4 linux设备驱动分类4.1 驱动分类4.2 三类驱动程序详细对比分析4.3 为什么字符设备驱动最重要5 驱动程序的安全性要求5.1 驱动是内核的一部分5.2 驱动对内核的影响5.3 常见驱动安全性问题6 驱动应该这么学6.…

「TCG 规范解读」词汇表

可信计算组织&#xff08;Ttrusted Computing Group,TCG&#xff09;是一个非盈利的工业标准组织&#xff0c;它的宗旨是加强在相异计算机平台上的计算环境的安全性。TCG于2003年春成立&#xff0c;并采纳了由可信计算平台联盟&#xff08;the Trusted Computing Platform Alli…