异步通知
介绍
前面我们学习了中断,这是处理器提供的一种异步机制
后面又学习用户态用阻塞/非阻塞的方式来访问设备驱动。
现在内核提供了一种软件层面上的,类似中断一样的机制:信号
- 设备驱动可以主动通知用户态应用程序。
- 是软件层面上对中断的一种模拟
- 根据后面的api:
- 可以把信号这个异步通知机制,想象成是用户态程序和驱动程序之间建立的一个通知通道
- 阻塞/非阻塞(用户态主动访问驱动)
- 异步通知(驱动通知用户态)
这些都是针对不同场合提出来的不同的解决办法,按需选择
信号 – 异步通知的核心
linux为了实现异步通知,提供了一个信号的机制。定义在arch/xtensa/include/uapi/asm/signal.h中。内部定义了linux所支持的所有信号
linux支持的信号
#define SIGHUP 1 #define SIGINT 2 #define SIGQUIT 3 #define SIGILL 4 #define SIGTRAP 5 #define SIGABRT 6 #define SIGIOT 6 #define SIGBUS 7 #define SIGFPE 8 #define SIGKILL 9 #define SIGUSR1 10 #define SIGSEGV 11 #define SIGUSR2 12 #define SIGPIPE 13 #define SIGALRM 14 #define SIGTERM 15 #define SIGSTKFLT 16 #define SIGCHLD 17 #define SIGCONT 18 #define SIGSTOP 19 #define SIGTSTP 20 #define SIGTTIN 21 #define SIGTTOU 22 #define SIGURG 23 #define SIGXCPU 24 #define SIGXFSZ 25 #define SIGVTALRM 26 #define SIGPROF 27 #define SIGWINCH 28 #define SIGIO 29 #define SIGPOLL SIGIO
#define SIGPWR 30 #define SIGSYS 31 #define SIGUNUSED 31
|
除了 SIGKILL(9)和 SIGSTOP(19)这两个信号不能被忽略外,其他的信号都可以忽略。
这些信号就相当于中断号,不同的中断号代表了不同的中断,不同的中断所做的处理不同,因此,驱动程序可以通过向应用程序发送不同的信号来实现不同的功能
就是驱动发送信号(指令),通知应用程序进入“中断”,执行“用户态中断处理函数”
api
用户态api
signal() : 设置指定信号的处理函数
handler: 信号(中断)处理函数
fcntl系统调用: 调用驱动中提供的接口.fasync 来配置信号通道
总结:应用程序对异步通知的处理:
- 信号处理初始化(核心前提)
- 指定信号接收进程(关键:告诉内核 “发给谁”)
- 开启文件异步通知功能(关键:建立通知通道)
我们可以通过这两个函数,在用户态的代码里面,重载一些信号的回调函数,比如:
ctrl-c : 信号SIGINT
kill -9 PID: 信号SIGKILL
#include "stdlib.h" #include "stdio.h" #include "signal.h"
void sigint_handler(int num) { printf("\r\nSIGINT signal!\r\n"); exit(0); }
int main(void) { signal(SIGINT, sigint_handler); while(1); return 0; }
|
驱动层api
异步通知结构体(信号)定义
linux内核中,定义了结构体fasync_struct:
struct fasync_struct { spinlock_t fa_lock; int magic; int fa_fd; struct fasync_struct *fa_next; struct file *fa_file; struct rcu_head fa_rcu; };
|
一般在设备结构体里面,增加这样一个结构体变量(就像让这个结构体,有一个发送信号的功能一样)
struct imx6uirq_dev { struct device *dev; struct class *cls; struct cdev cdev; struct fasync_struct *async_queue; };
|
api
.fasync: 设备文件的操作方法之一
- 是提供给应用层来配置信号的接口。

- 内部调用
fasync_helper来初始化设备结构体里面的信号功能结构体变量
fasync_helper()
kill_fasync(): 驱动向用户态程序发送指定信号
demo
#include <linux/fs.h> #include <linux/cdev.h> #include <linux/fcntl.h>
struct xxx_dev { struct fasync_struct *async_queue; };
static int xxx_fasync(int fd, struct file *filp, int on) { struct xxx_dev *dev = (struct xxx_dev *)filp->private_data; if (fasync_helper(fd, filp, on, &dev->async_queue) < 0) return -EIO; return 0; }
static int xxx_release(struct inode *inode, struct file *filp) { return xxx_fasync(-1, filp, 0); }
static struct file_operations xxx_ops = { .fasync = xxx_fasync, .release = xxx_release, };
|