中断处理函数如何【发送信号】给应用层?

资讯 2年前
859

目录

· 驱动程序

示例代码全貌

Makefile 文件

编译、测试

· 应用程序

示例代码全貌

编译、测试

别人的经验,我们的阶梯!

大家好,我是道哥,今天我为大伙儿解说的技术知识点是:【中断程序如何发送信号给应用层】。

最近分享的几篇文章都比较基础,关于字符类设备的驱动程序,以及中断处理程序。

也许在现代的项目是用不到这样的技术,但是万丈高楼平地起。

只有明白了这些最基础的知识点之后,再去看那些进化出来的高级玩意,才会有一步一个脚印的获得感。

如果缺少了这些基础的环节,很多深层次的东西,学起来就有点空中楼阁的感觉。

就好比研究Linux内核,如果一上来就从Linux 4.x/5.x内核版本开始研究,可以看到很多“历史遗留”代码。

这些代码就见证着Linux一步一步的发展历史,甚至有些人还会专门去研究 Linux 0.11 版本的内核源码,因为很多基本思想都是一样的。

今天这篇文章,主要还是以代码实例为主,把之前的两个知识点结合起来:

在中断处理函数中,发送信号给应用层,以此来通知应用层处理响应的中断业务。

驱动程序

示例代码全貌

所有的操作都是在 ~/tmp/linux-4.15/drivers 目录下完成的。

首先创建驱动模块目录:

$ cd ~/tmp/linux-4.15/drivers

$ mkdir my_driver_interrupt_signal

$ touch my_driver_interrupt_signal.c

文件内容如下:

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

以上代码主要做了两件事情:

1. 注册中断号 1 的处理函数:myirq_handler();

2. 创建设备节点 /dev/mydev;

这里的中断号1,是键盘中断。

因为它是共享的中断,因此当键盘被按下的时候,操作系统就会依次调用所有的中断处理函数,当然就包括我们的驱动程序所注册的这个函数。

中断处理部分相关的几处关键代码如下:

image.png

在中断处理函数中,目标是发送信号 SIGUSR1 到应用层,因此驱动程序需要知道应用程序的进程号(PID)。

根据之前的文章Linux驱动实践:驱动程序如何发送【信号】给应用程序?,应用程序必须主动把自己的 PID 告诉驱动模块才可以。这可以通过 write 或者ioctl函数来实现,

驱动程序用来接收 PID 的相关代码是:

image.png

知道了应用程序的 PID,驱动程序就可以在中断发生的时候(按下键盘ESC键),发送信号出去了:

image.png

Makefile 文件

image.png

编译、测试

首先查看一下加载驱动模块之前,1号中断的所有驱动程序:

再看一下设备号:

$ cat /proc/devices

因为驱动注册在创建设备节点的时候,是动态请求系统分配的。

根据之前的几篇文章可以知道,系统一般会分配244这个主设备号给我们,此刻还不存在这个设备号。

编译、加载驱动模块:

$ make

$ sudo insmod my_driver_interrupt_signal.ko

首先看一下 dmesg 的输出信息:

然后看一下中断驱动程序:

可以看到我们的驱动程序( mydev )已经登记在1号中断的最右面。

最后看一下设备节点情况:

驱动模块已经准备妥当,下面就是应用程序了。

应用程序

应用程序的主要功能就是两部分:

通过 ioctl 函数把自己的 PID 告诉驱动程序;

注册信号 SIGUSR1 的处理函数;

示例代码全貌

image.png

image.png

在应用程序的最后,是一个 while(1) 死循环。因为只有在按下键盘上的ESC按键时,驱动程序才会发送信号上来,因此应用程序需要一直存活着。

编译、测试

新开一个中断窗口,编译、执行应用程序:

image.png

由于应用程序调用了 open 和 ioctl 这两个函数,因此,驱动程序中两个对应的函数就会被执行。

这可以通过 dmesg 命令的输出信息看出来:

这个时候,按下键盘上的 ESC 键,此时驱动程序中打印如下信息:

说明:驱动程序捕获到了键盘上的 ESC 键,并且发送信号给应用程序了。

在执行应用程序的终端窗口中,可以看到如下输出信息:

说明:应用程序接收到了驱动程序发来的信号!

© 版权声明

相关文章