嵌入式linux 异步通知

        中断是处理器提供的一种异步机制,我们配置好中断以后就可以让处理器去处理其他的事情了,当中断发生以后会触发我们事先设置好的中断服务函数,在中断服务函数里面处理具体的事物。linux应用程序可以通过阻塞或者非阻塞这两种方式来访问驱动,通过阻塞访问的话应用程序会处于休眠态,等待驱动设备可以使用,非阻塞方式的话通过poll函数不断的轮询,查看设备是否可以使用,但是这两种方式都需要应用程序主动地去查询设备的使用情况。由此“信号”应运而生,信号类似与硬件上面的中断,只不过信号是软件方面的“中断”,驱动可以主动向应用程序发送信号的方式来报告自己可以访问了。

        阻塞、非阻塞、异步通知,这三种是针对不同的场合提出来的不同的解决方法,没有优劣之分,在实际学习和工作中,根据实际需求选择合适的方式就行。

信号汇总              这些信号就相当于中断号,不用的中断号代表了不同的中断,不同的中断代表了不同的处理,因此,驱动程序可以通过向应用程序发送不同的信号来实现不同的功能。

        我们使用中断的时候需要设置中断处理函数,同样的,如果在应用程序中使用信号,那么就必须设置信号所使用的信号处理函数,在应用程序中使用signal函数来设置指定信号的处理函数。        signum:要设置处理函数的信号。

        handler:信号的处理函数

        返回值:设置成功的话返回信号的前一个处理函数,设置失败的话发挥SIG_ERR。

驱动中的信号处理

        1,fasync_struct结构体

        首先我们需要在驱动程序中定义一个fasync_struct结构体指针变量,fasync_struct结构体内容如下:

         一般将此结构体指针变量定义到设备结构体中

/* 异步相关结构体 */
struct fasync_struct *async_queue;   

        2,fasync函数

        要使用异步通知,需要在设备驱动中实现file_operations操作集中的fasync函数,fasync函数里面一般通过调用fasync_helper函数来初始化定义前面的fasync_struc结构体指针。

//在file_operations操作集中
.fasync = imx6uirq_fasync,

//实现操作集中的函数
static int imx6uirq_fasync(int fd, struct file *filp, int on)
{
    struct imx6uirq_dev *dev = (struct imx6uirq *)filp->private_data;
    return fasyn_helper(fd, filp, on, &dev->async_queue);
}

        fasync_helper函数的前三个参数就是fasyn函数的那三个参数,第四个参数就是要初始化的fasync_struct结构体的指针变量当应用程序通过fcntl(fd,F_SETFL。flags|FASYNC)改变fasync标记的时候,驱动程序file_operations操作集中的fasync函数就会执行。

        当关闭驱动文件的时候需要在file_operations操作集中的release函数中释放fasync_struct,fasync_struct的释放函数同样为fasync_helper。release函数参数如下;      

 3,kill_fasync函数

        当设备可以访问的时候,驱动程序需要向应用程序发出信号,相当于产生“中断”,kill_fasyc函数负责发送指定的信号

        fp:要操作的fasync_struct

        sig:要发送的信号

        band:可读时设置POLL_IN,可写的时候设置POLL_OUT

/* 释放SIGIO信号 */
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);

应用程序对异步通知的处理

        1,注册信号处理函数

        single函数设置信号处理函数,前面已经讲过了。

        2,将本应用程序的进程号告诉内核

        使用fcntl(fd,F_SETOWN,gitpid());将本应用程序的进程号告诉内核。

        3,开启异步通知

        使用下面两行程序开启异步通知,重点是通过fcntl函数设置进程状态为FASYNC,经过这一步,驱动程序fasync函数就会执行。

/* 设置信号SIGIO的处理函数 */
signal(SIGIO, sigio_signal_func);
	
fcntl(fd, F_SETOWN, getpid());		/* 设置当前进程接收SIGIO信号 	*/
flags = fcntl(fd, F_GETFL);			/* 获取当前的进程状态 			*/
fcntl(fd, F_SETFL, flags | FASYNC);	/* 设置进程启用异步通知功能 	*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值