什么是异步通知异步通知在linux的实现中是通过信号,而 信号是在软件层次上对中断机制的一种模拟 。这种机制和中断非常类似,所以可以以中断的思想来理解这一过程,信号其实就相当于应用层的中断。
信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。
如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。
异步通知和异步io的区别异步通知 :当资源可获得时,由 驱动程序向应用层发送一个信号,主动通知应用程序 ,再由应用程序发起访问。
异步io : 主动获取设备的资源信息 ,首先发起一个io操作请求,资源可用时,应用层注册的回调函数会被主动调用。但是 异步通知不能直接调用应用层注册的回调函数,而是由驱动程序向应用层发送一个信号 。
信号含义信号名含义默认操作
sighup 该信号在用户终端连接(正常或非正常)结束时发出,通常是在终端的控制进程结束时,通知同一会话内的各个作业与控制终端不再关联。 终止
sigint 该信号在用户键入intr字符(通常是ctrl-c)时发出,终端驱动程序发送此信号并送到前台进程中的每一个进程。 终止
sigquit 该信号和sigint类似,但由quit字符(通常是ctrl-\\)来控制。 终止
sigill 该信号在一个进程企图执行一条非法指令时(可执行文件本身出现错误,或者试图执行数据段、堆栈溢出时)发出。 终止
sigfpe 该信号在发生致命的算术运算错误时发出。这里不仅包括浮点运算错误,还包括溢出及除数为0等其它所有的算术的错误。 终止
sigkill该信号用来立即结束程序的运行,并且不能被阻塞、处理和忽略。终止
sigalrm 该信号当一个定时器到时的时候发出。 终止
sigstop 该信号用于暂停一个进程,且不能被阻塞、处理或忽略。 暂停进程
sigtstp 该信号用于暂停交互进程,用户可键入susp字符(通常是ctrl-z)发出这个信号。 暂停进程
sigchld 子进程改变状态时,父进程会收到这个信号 忽略
sigabort 该信号用于结束进程 终止
当应用层接收到一个信号时,可以对信号执行忽略、捕捉和缺省三种操作:
忽略信号 :对信号不做任何处理,但是有两个信号不能忽略:即sigkill及sigstop。
捕捉信号 :定义信号处理函数,当信号发生时,执行相应的处理函数。
缺省信号 :执行linux对该信号的默认操作
应用层使用信号以下是应用层捕捉sigio信号的简单示例:
void input_handler(int signum){ //如果驱动发送了sigio信号,在此处理 printf(recive from %d\\n,signum); }int main(){ int fd ,oflags; fd=open(/dev/global,o_rdwr,s_irusr | s_iwusr); if(fd != -1){ //启动信号机制 signal(sigio,input_handler);//设置sigio信号的处理函数 fcntl(fd,f_setown,getpid());//将进程id赋值给filp- >f_owner oflags = fcntl(fd,f_getfl); fcntl(fd,f_setfl,oflags | fasync);//驱动的fasync方法被调用 while(1) { sleep(1000); }}}当应用层f_setown, 驱动什么都没做,内核只是将进程的id赋值给 filp->f_owner;当应用层f_setfl被执行来打开 fasync, 驱动的 fasync 方法被调用.当数据到达, 驱动向进程发出一个 sigio信号驱动如何实现异步信号驱动的实现主要用到一个结构体和 两个函数 :
fasync_struct结构体:
struct fasync_struct { spinlock_t fa_lock; int magic; int fa_fd; struct fasync_struct *fa_next; /* singly linked list */ struct file *fa_file; struct rcu_head fa_rcu;};函数:
fasync_helper():用于处理fasync标志变更
fasync_helper()函数是用来初始化fasync_struct结构体变量,并设置异步通知队列的
int fasync_helper(int fd, //文件描述符 struct file * filp, //文件指针 int on, struct fasync_struct **fapp); //要设置的结构第三个参数on表示设置还是删除,on为真时初始化,为假时(0),移除.
kill_fasync():发送信号
void kill_fasync(struct fasync_struct **fp, int sig, int band);fp:是已初始化的fasync_struct数据结构
sig:要发送的信号
band:在可读时设置为poll_in,在可写时设置为poll_out;
驱动实例static struct fasync_struct *btn_fasync;static irqreturn_t btn_irq_handler(int irq, void *dev){ struct btn_t *p = (struct btn_t *)dev; //发送信号 kill_fasync(&btn_fasync, sigio, poll_in); return irq_handled;}static int btn_drv_fasync(int fd, struct file *fp, int on){ //初始化btn_fasync结构,并添加到异步通知列表中 return fasync_helper(fd, fp, on, &btn_fasync);}static int btn_drv_close(struct inode *inode, struct file *filp){ if(filp- >f_flags & fasync) fasync_helper(-1, flip, 0, &btn_fasync);//将文件从异步通知的列表中删除 return 0;}static struct file_operations btn_ops={ ...... .release = btn_drv_close, .fasync = btn_drv_fasync,};主要步骤 :
1、构造struct fasync_struct链表的头
2、实现fasync接口函数,调用fasync_helper函数来构造struct fasync_struct节点,并加入链表。
3、在资源可用时,调用kill_fasync发送信号,并设置资源的可用类型是可读还是可写。
4、在文件最后一次关闭时,即在release接口中,需要显式调用驱动实现的fasync接口函数,将节点从链表中删除,这样进程就不会再次收到信号。
异步通知主要还是弄明白信号是软件层次对中断的一种模拟,并且信号是由驱动发出的。
HiQP系列微型DC/DC转换器PICO概述
联想拯救者电竞手机官宣搭载骁龙865 并有望支持高刷新率
台积电20纳米设计达阵
分享一个为工业树莓派共享网络的方法
3250A系列交/直流电子负载的特性及产品应用
Linux驱动学习笔记:异步通知
AMD2800X被曝将是10核20线程 跑分堪比英特尔i9
高频变压器的线圈匝数和线径计算步骤介绍
光纤传感器-罐头盖计数应用案例-阿童木光纤传感器
Imagination推出基于硬件又高度灵活的异构计算产品组合
乔纳森-艾维离职,成立自己的独立设计公司名为 “LoveFrom Jony”
二极管的伏安特性 二极管整流电路详解
N沟道型和P沟道型MOSFET的导通条件
SK海力士公布了第一颗DDR5-6400内存芯片
2019年币圈发生了哪一些事
什么是用户侧储能系统,关于它的详细介绍
Maxim全新2款LED驱动器 为汽车照明提供更高亮度LED驱动方案
单片微波集成电路同相正交混频器——HMC520A
带霍尔传感器的三相无刷直流电机控制
骁龙670加码vivo X23,发现更多美