【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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奶油芝士汉堡包

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值