异步通知—信号
阻塞和非阻塞都是应用程序主动查询设备的使用情况。
Linux使用异步通知机制实现驱动程序主动向应用程序发出可访问通知,然后应用程序从驱动程序中读取或写入数据。
阻塞、非阻塞或异步通知没有优劣脂粉,根据实际需求选择合适的处理方法。
异步通知的核心是信号,信号类似于硬件的中断,是在软件层次上对中断的一种模拟,信号相当与中断号。驱动程序主动向应用程序发送信号,应用程序收到信号后,可以从驱动设备中读取或写入数据。
在arch/xtensa/include/uapi/asm/signal.h文件中定义了Linux支持的所有信号。
#define SIGHUP 1 /* 终端挂起或控制进程终止 */
#define SIGINT 2 /* 终端中断(Ctrl+C 组合键) */
#define SIGQUIT 3 /* 终端退出(Ctrl+\组合键) */
#define SIGILL 4 /* 非法指令 */
#define SIGTRAP 5 /* debug 使用,由断点指令产生 */
#define SIGABRT 6 /* 由 abort(3)发出的退出指令 */
#define SIGIOT 6 /* IOT 指令 */
#define SIGBUS 7 /* 总线错误 */
#define SIGFPE 8 /* 浮点运算错误 */
#define SIGKILL 9 /* 杀死、终止进程 */
#define SIGUSR1 10 /* 用户自定义信号 1 */
#define SIGSEGV 11 /* 段违例(无效的内存段) */
#define SIGUSR2 12 /* 用户自定义信号 2 */
#define SIGPIPE 13 /* 向非读管道写入数据 */
#define SIGALRM 14 /* 闹钟 */
#define SIGTERM 15 /* 软件终止 */
#define SIGSTKFLT 16 /* 栈异常 */
#define SIGCHLD 17 /* 子进程结束 */
#define SIGCONT 18 /* 进程继续 */
#define SIGSTOP 19 /* 停止进程的执行,只是暂停 */
#define SIGTSTP 20 /* 停止进程的运行(Ctrl+Z 组合键) */
#define SIGTTIN 21 /* 后台进程需要从终端读取数据 */
#define SIGTTOU 22 /* 后台进程需要向终端写数据 */
#define SIGURG 23 /* 有"紧急"数据 */
#define SIGXCPU 24 /* 超过 CPU 资源限制 */
#define SIGXFSZ 25 /* 文件大小超额 */
#define SIGVTALRM 26 /* 虚拟时钟信号 */
#define SIGPROF 27 /* 时钟信号描述 */
#define SIGWINCH 28 /* 窗口大小改变 */
#define SIGIO 29 /* 可以进行输入/输出操作 */
#define SIGPOLL SIGIO
/* #define SIGLOST 29 */
#define SIGPWR 30 /* 断点重启 */
#define SIGSYS 31 /* 非法的系统调用 */
#define SIGUNUSED 31 /* 未使用信号 */
常用信号: SIGKILL(9)、SIGSTOP(19)、SIGIO(29)。
应用程序中的信号处理
1.注册信号处理函数
应用程序使用signal指定信号处理函数。
sighandler_t signal(int signum, sighandler_t handler)
- signum:要设置的处理函数的信号。
- handler:信号得处理函数。
- 返回值:成功,返回信号得前一个处理函数;失败,返回SIG_ERR。
信号处理函数原型。
typedef void (*sighandler_t)(int)
2.将应用程序的进程号发送给内核
fcntl(fd, F_SETOWN, getpid());
3.开启异步通知?
fcntl设置进程状态为FASYNC,驱动程序中的fasync函数执行。?
flags = fcntl(fd, F_GETFL); /* 获取当前的进程状态 */
fcntl(fd, F_SETFL, flag | FASYNC); /* 开启当前进程的异步通知功能 */
驱动程序中的信号处理
在设备驱动中定义一个fasync_struct结构体指针变量。
struct xxx_dev {
/* ... */
struct fasync_struct *async_queue;
};
在file_operation操作集中添加fasync函数。
static struct file_operations xxx_ops = {
/* ... */
.fasync = xxx_fasync,
.release = xxx_release,
};
fasync函数通过调用fasync_helper函数来初始化定义的fasync_struct结构体指针。
static int xxx_fasync(int fd, struct file *filp, int on){
struct xxx_dev *dev = filp->private_data;
if(fasync_helper(fd, filp, on, &dev->async_queue) < 0) {
return -EIO;
}
return 0;
}
关闭驱动时,在xxx_release函数中使用fasync_helper释放fasync_struct。
static int xxx_release(struct inode *inode, struct file *filp){
return xxx_fasync(-1, filp, 0); /* 删除异步通知 */
}
?当设备可以访问时,驱动程序使用kill_fasync向应用程序发送信号。
void kill_fasync(struct fasync_struct **fp, int sig, int band);
- fp:要操作的fasync_struct。
- sig:要发送的信号。
- band:可读时为POLL_IN,可写时为POLL_OUT。
|