Linux驱动IO篇——异步通知

简介: Linux驱动IO篇——异步通知

什么是异步通知

异步通知在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 该信号用于结束进程 终止

当应用层接收到一个信号时,可以对信号执行忽略、捕捉和缺省三种操作:

忽略信号:对信号不做任何处理,但是有两个信号不能忽略:即SIGKILLSIGSTOP

捕捉信号:定义信号处理函数,当信号发生时,执行相应的处理函数。

缺省信号:执行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接口函数,将节点从链表中删除,这样进程就不会再次收到信号。

异步通知主要还是弄明白信号是软件层次对中断的一种模拟,并且信号是由驱动发出的

end

猜你喜欢

一个Linux驱动工程师必知的内核模块知识

Linux内核中常用的数据结构和算法

Linux内核中常用的C语言技巧

Linux内核基础篇——常用调试技巧汇总

Linux内核基础篇——动态输出调试

Linux内核基础篇——printk调试

Linux内核基础篇——initcall

相关文章
|
23天前
|
存储 缓存 Linux
Linux IO的奥秘:深入探索数据流动的魔法
Linux I/O(输入/输出)系统是其核心功能之一,负责处理数据在系统内部及与外界之间的流动。为了优化这一流程,Linux进行了一系列努力和抽象化,以提高效率、灵活性和易用性。🚀
Linux IO的奥秘:深入探索数据流动的魔法
|
27天前
|
缓存 监控 IDE
linux如何查看io性能
linux如何查看io性能
|
2月前
|
Linux API 调度
Linux系统驱动跟裸机驱动的区别
Linux系统驱动跟裸机驱动的区别
31 0
|
2月前
|
存储 缓存 Linux
【Shell 命令集合 磁盘维护 】Linux 设置和查看硬盘驱动器参数 hdparm命令使用教程
【Shell 命令集合 磁盘维护 】Linux 设置和查看硬盘驱动器参数 hdparm命令使用教程
38 0
|
10天前
|
机器学习/深度学习 缓存 监控
linux查看CPU、内存、网络、磁盘IO命令
`Linux`系统中,使用`top`命令查看CPU状态,要查看CPU详细信息,可利用`cat /proc/cpuinfo`相关命令。`free`命令用于查看内存使用情况。网络相关命令包括`ifconfig`(查看网卡状态)、`ifdown/ifup`(禁用/启用网卡)、`netstat`(列出网络连接,如`-tuln`组合)以及`nslookup`、`ping`、`telnet`、`traceroute`等。磁盘IO方面,`iostat`(如`-k -p ALL`)显示磁盘IO统计,`iotop`(如`-o -d 1`)则用于查看磁盘IO瓶颈。
|
21天前
|
Linux
Linux操作系统调优相关工具(三)查看IO运行状态相关工具 查看哪个磁盘或分区最繁忙?
Linux操作系统调优相关工具(三)查看IO运行状态相关工具 查看哪个磁盘或分区最繁忙?
22 0
|
29天前
|
缓存 Linux
Linux 文件IO简单实例
Linux 文件IO简单实例
12 1
|
16天前
|
Linux Go
Linux命令Top 100驱动人生! 面试必备
探索Linux命令不再迷茫!本文分10部分详解20个基础命令,带你由浅入深掌握文件、目录管理和文本处理。 [1]: <https://cloud.tencent.com/developer/article/2396114> [2]: <https://pan.quark.cn/s/865a0bbd5720> [3]: <https://yv4kfv1n3j.feishu.cn/docx/MRyxdaqz8ow5RjxyL1ucrvOYnnH>
68 0
|
23天前
|
监控 Linux API
Linux内核探幽:深入浅出IO模型
在Linux操作系统中,I/O(输入/输出)模型是一套定义如何处理数据读写的机制,它对系统性能有着重要影响。为了适应不同的应用场景和性能需求,Linux抽象出了多种I/O模型。每种模型都有其独特的特点、底层原理、优劣势以及适用场景。🤓
Linux内核探幽:深入浅出IO模型
|
23天前
|
存储 缓存 安全
Linux IO:打开数据之窗的魔法
Linux I/O(输入/输出)是操作系统中一个至关重要的组成部分,它涉及到数据在内存🧠、存储设备💾、网络接口🌐等之间的传输过程。在Linux中,I/O操作不仅仅是文件读写那么简单,它包括了一系列复杂的机制和策略,旨在提高数据处理的效率,保证系统的稳定性和性能。📊
Linux IO:打开数据之窗的魔法

热门文章

最新文章