异步通知

异步通知是一种高效的I/O处理方式,它通过信号驱动,当设备准备就绪时主动通知应用程序,避免了轮询查询的开销。在应用层,涉及设置信号处理函数、所有权和信号,而在驱动层则需定义fasync_struct、实现fasync函数以及在设备资源就绪时发送信号。尽管可能存在通知来源的辨识问题,但结合poll机制可以有效解决。
摘要由CSDN通过智能技术生成

什么是异步通知?

异步通知类似于硬件上的“中断”,一旦设备就绪,由驱动程序主动通知应用程序,这样应用程序就不需要查询设备状态,而可以去干自己的事。通知采用信号的方式,所以可称为“信号驱动的异步I/O”。

为什么使用异步通知?

在一个进程中使用I/O多路复用可以同时监控多个I/O设备,但是这里有个问题,如果这些I/O设备都没有准备好的话,那进程就会阻塞休眠,这样就无法去干别的事了,所以就需要一种方法能主动告诉进程,I/O设备资源已经准备好,这种方法就是采用信号机制实现的异步通知(类型于硬件中断的软中断)。

信号

       信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程在启动信号机制后,不需要通过任何操作来等待信号的到达,事实上,进程也不知道信号什么时候会到达。

异步通知使用

应用层

应用层启动异步通知机制五个步骤:

1.指定接收信号,设置信号处理函数

struct sigaction act,oldact;

sigemptyset( &act.sa_mask );//清除信号集

sigaddset( &act.sa_mask, SIGIO );//将SIGIO 加入信号捕捉集

act.sa_flags = SA_SIGINFO;//设置标志位后,使用 my_signal_func 函数处理信号

act.sa_sigaction = my_signal_func;//信号处理函数

sigaction( SIGIO, &act, &oldact ) ;//act为新的,oldact为老的

2.设置异步I/O所有权

fcntl( my_fd, F_SETOWN, getpid() ) ;//所有权为本进程,这样驱动才知道将信号发给谁

3.设置 SIGIO 信号

fcntl( my_fd, F_SETSIG, SIGIO );

4.获取文件 flags

flag == fcntl( my_fd, F_GETFL ));

5.设置文件 flags,设置 FASYNC,支持异步通知

fcntl( my_fd, F_SETFL, flag | FASYNC );//先获取原先标志位,然后或上fasync标志位,便设置好了异步通知

 

驱动层

在驱动中使用异步通知机制需要四个步骤:

1.定义一个fasync_struct结构体指针

static struct my_device {

    char name[64];                                        /* 设备文件名 */

    wait_queue_head_t read_queue;        /* 读等待队列 */

    wait_queue_head_t write_queue;        /* 写等待队列 */

    struct kfifo my_kfifo;                        /* 环形缓存区 */

    struct fasync_struct *fasync;        /* 异步通知结构体指针 */

};

2.实现xxx_fasync函数,使用fasync_helper函数构造struct fasync_struct类型的节点,并添加到系统的链表(异步通知链表,自定义名称)中。

static int my_kfifo_drv_fasync(int fd, struct file *file, int mode)

{

    struct my_private_data *data = file->private_data;

    struct my_device *device = data->device;

    return fasync_helper( fd, file, mode, &device->fasync );

}

3.在设备资源准备就绪的地方添加kill_fasync函数发送信号SIGIO给内核

比如:

static ssize_t xxx_write(struct file *filp,const char __user *buf,size_t count,loff_t *ppos)

{

    struct my_private_data *data = file->private_data;

    struct my_device *device = data->device;

    ...

    if( device->fasync )

    kill_fasync(&device->fasync,GIGIO,POLL_IN);

    ...

}



static ssize_t xxx_read(struct file *filp,const char __user *buf,size_t count,loff_t *ppos)

{

    struct my_private_data *data = file->private_data;

    struct my_device *device = data->device;

    ...

    if( device->fasync )

    kill_fasync(&device->fasync,GIGIO,POLL_OUT);

    ...

}

4.最后要在文件关闭的时候,将文件从异步通知链表(自定义名称)中删除(前提是之前注册过,未注册也没关系,在移除函数内部会判断file是不是注册异步通知的file,只有是才会移除)

int xxx_release(struct inode *inode,struct file *filp)

{

    xxx_fasync(-1,filp,0);

    ...

    return 0;

}

 

缺陷

       当进程打开设备文件1和设备文件2并且都设置了I/O异步通知,那么当异步通知信号到来时,进程怎么知道是哪个文件发来的?因此,通常在信号处理函数中使用poll机制协助完成I/O操作!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值