概述
异步通知—信号
阻塞和非阻塞都是应用程序主动查询设备的使用情况。
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。
最后
以上就是坚强茉莉为你收集整理的【Linux驱动开发】异步通知异步通知—信号应用程序中的信号处理驱动程序中的信号处理的全部内容,希望文章能够帮你解决【Linux驱动开发】异步通知异步通知—信号应用程序中的信号处理驱动程序中的信号处理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复