驱动篇:异步通知与异步 I/O(一)
发布日期:2021-06-29 11:34:46 浏览次数:2 分类:技术文章

本文共 2727 字,大约阅读时间需要 9 分钟。

驱动篇:异步通知与异步 I/O(一)

在设备驱动中使用异步通知可以使得对设备的访问可进行时,由驱动主动通知应用程序进行访问。这样,使用无阻塞I/O 的应用程序无须轮询设备是否可访问,而阻塞访问也可以被类似“中断”的异步通知所取代。

异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上“中断”的概念,比较准确的称谓是“信号驱动的异步I/O”。信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。
在这里插入图片描述阻塞、非阻塞I/O、异步通知本身没有优劣,应该根据不同的应用场景合理选择。Linux系统中,异步通知使用信号来实现。
除了SIGSTOP和SIGKILL两个信号外,进程能够忽略或捕获其他的全部信号。一个信号被捕获的意思是当一个信号到达时有相应的代码处理它。如果一个信号没有被这个进程所捕获,内核将采用默认行为处理。
信号的接收
使用signal()函数来设置对应信号的处理函数

void (*signal(int signum, void (*handler))(int))(int);该函数原型较难理解,它可以分解如下:typedef void (*sighandler_t)(int);sighandler_t signal(int signum, sighandler_t handler);

第一个参数指定信号的值,第二个参数指定针对前面信号值的处理函数,若为SIG_IGN,表示忽略该信号;若为SIG_DFL,表示采用系统默认方式处理信号;若为用户自定义的函数,则信号被捕获到后,该函数将被执行。如果 signal()调用成功,它返回最后一次为信号signum 绑定的处理函数handler值,失败则返回SIG_ERR。

在进程执行时,按下[Ctrl+c]组合键将向其发出SIGINT信号,kill正在运行的

进程将向其发出SIGTERM信号,signal()捕获信号范例

void sigterm_handler(int signo) {
printf("Have caught sig N.O. %d\n", signo); exit(0); } int main(void){
signal(SIGINT, sigterm_handler);signal(SIGTERM, sigterm_handler);while(1);return 0;}

除了 signal()函数外,sigaction()函数可用于改变进程接收到特定信号后的行为,它的原型如下:

int sigaction(int signum,const struct sigaction *act,struct sigaction*oldact);

该函数的第一个参数为信号的值,可以为除 SIGKILL 及 SIGSTOP 外的任何一个特定有效的信号。第二个参数是指向结构体 sigaction 的一个实例的指针,在结构体sigaction 的实例中,指定了对特定信号的处理函数,若为空,则进程会以默认方式对信号处理。第三个参数 oldact 指向的对象用来保存原来对相应信号的处理函数,可指定 oldact 为 NULL。如果把第二、第三个参数都设为 NULL,那么该函数可用于检查信号的有效性

使用信号实现异步通知的例子,它通过 signal(SIGIO, input_handler)对标准输入文件描述符 STDIN_FILENO 启动信号机制。用户输入后,应用程序将接收到 SIGIO 信号,其处理函数 input_handler()将被调用

使用信号实现异步通知的应用程序实例

#include 
#include
#include
#include
#include
#include
#define MAX_LEN 100void input_handler(int num){ char data[MAX_LEN];int len;//读取并输出 STDIN_FILENO 上的输入len = read(STDIN_FILENO, &data, MAX_LEN);data[len] = 0;printf("input available:%s\n", data);}main(){ int oflags;//启动信号驱动机制signal(SIGIO, input_handler);fcntl(STDIN_FILENO, F_SETOWN, getpid());oflags = fcntl(STDIN_FILENO, F_GETFL);fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC);//最后进入一个死循环,仅为保持进程不终止,如果程序中没有这个死循环//会立即执行完毕while (1);}

SIGIO 信号安装 input_handler()作为处理函数,第 25 行设置本进程为 STDIN_FILENO 文件的拥有者(owner),没有这一步内核不会知道应该将信号发给哪个进程。而为了启用异步通知机制, 还需对设备设置 FASYNC 标志,第 26~27 行代码实现此目的。整个程序的执行效果如下:

[root@localhost driver_study]# ./signal_testI am Chinese.input available: I am Chinese.I love Linux driver.input available: I love Linux driver.

从中可以看出,当用户输入一串字符后,标准输入设备释放 SIGIO 信号,这个信号“中断”驱使对应的应用程序中的 input_handler()得以执行,将用户输入显示出来。由此可见,为了在用户空间中能处理一个设备释放的信号,它必须完成以下 3 项

l 通过 F_SETOWN IO 控制命令设置设备文件的拥有者为本进程,这样从设备驱动发出的信号才能被本进程接收到。

l 通过 F_SETFL IO 控制命令设置设备文件支持 FASYNC,即异步通知模式。
l 通过 signal()函数连接信号和信号处理函数

转载地址:https://blog.csdn.net/zytgg123456/article/details/109922874 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:驱动篇:中断与时钟(一)
下一篇:驱动篇:轮询操作(一)

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2024年04月25日 17时24分34秒