Linux驱动开发异步通知

Posted XXX_UUU_XXX

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux驱动开发异步通知相关的知识,希望对你有一定的参考价值。

异步通知—信号

阻塞和非阻塞都是应用程序主动查询设备的使用情况。

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设备驱动中的异步通知与同步I/O

arm驱动linux异步通知与异步IO

linux设备驱动归纳总结:7.异步通知fasync

Linux设备驱动基础04之异步通知

Linux设备驱动基础04之异步通知

Linux设备驱动基础04之异步通知