打印

异步通知

[复制链接]
200|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
车水马龙|  楼主 | 2018-8-22 10:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在设备驱动中使用异步通知可以使得对设备的访问可进行时,由驱动主动通知应用程序进行访问。这样,使用无阻塞 I/O 的应用程序无需轮询设备是否可访问,而阻塞访问也可以被类似“中断”的异步通知所取代。

1. 信号:使用信号进行进程间通信(IPC)是 UNIX 中的一种传统机制,Linux 也支持这种机制。在Linux 中,异步通知使用信号来实现,Linux 中可用的信号如下:

信号值含义SIGHUP1挂起SIGINT(ctrl+c)2终端中断SIGQUIT3终端退出SIGILL4无效命令SIGTRAP5跟踪陷阱SIGIOT6IOT 陷阱...  SIGKILL9强行终止(不能被捕获或忽略)SIGTERM15终止SIGCHLD17子进程已经停止或退出SIGSTOP19停止执行(不能被捕获或忽略)SIGIO29I/O



除了 SIGSTOP 和 SIGKILL 两个信号外,进程能够忽略或捕获其他的全部信号。一个信号被捕获的意思是当一个信号到达时有相应的代码处理它。如果一个信号没有被这个进程所捕获,内核将采用默认行为处理。



2. 信号的接收:用户程序中,定义信号的处理函数用如下函数:

[cpp] view plain copy

print?<img id="aimg_AB4va"  class="zoom" width="12" height="12" file="https://code.csdn.net/assets/CODE_ico.png" border="0" alt="" /><img id="aimg_dsy8Z"  class="zoom" width="12" height="12" file="https://code.csdn.net/assets/ico_fork.svg" border="0" alt="" />



void (*signal(int signum, void (*handler)(int)))(int);   





第一个参数,指定信号的值,就是上边 SIGCHLD 之类的宏的值

第二个参数,指定针对前边信号值的处理函数

SIG_IGN,忽略信号

SIG_DFL,系统默认的方式处理

用户自定义函数,信号捕捉后函数被执行

返回值:

成功,函数的返回值

失败,SIG_ERR



一个用 ctrl+c 触发到自己的函数中的例子:

[cpp] view plain copy

print?<img id="aimg_k6bug"  class="zoom" width="12" height="12" file="https://code.csdn.net/assets/CODE_ico.png" border="0" alt="" /><img id="aimg_xc2kH"  class="zoom" width="12" height="12" file="https://code.csdn.net/assets/ico_fork.svg" border="0" alt="" />



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





一个用实现输入字符,打印字符异步的例子:

[cpp] view plain copy

print?<img id="aimg_x9N9Y"  class="zoom" width="12" height="12" file="https://code.csdn.net/assets/CODE_ico.png" border="0" alt="" /><img id="aimg_b256d"  class="zoom" width="12" height="12" file="https://code.csdn.net/assets/ico_fork.svg" border="0" alt="" />



#include <sys/types.h>   #include <sys/stat.h>   #include <stdio.h>   #include <fcntl.h>   #include <signal.h>   #include <unistd.h>   #define MAX_LEN 100   void 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()作为处理函数

②fcntl(STDIN_FILENO, F_SETOWN, getpid()); 设置本进程为STDIN_FILENO 文件的拥有者(owner)

③对设备设置 FASYNC 标志

运行结果:

> ./signal_test

I am Chinese.

input available: I am Chinese.



I love Linux driver.

input available: I love Linux driver.

需要注意的是:当用户输入完字符串的时候,才会触发 SIGIO 的信号



用户空间是实现异步通知的 3 项工作:

通过 F_SETOWN IO 控制命令设置设备文件的拥有者为本进程,这样从设备驱动发出的信号才能被本进程接收到。 通过 F_SETFL IO 控制命令设置设备文件支持 FASYNC,即异步通知模式。 通过 signal()函数连接信号和信号处理函数。



3. 信号的释放:在设备驱动和应用程序的异步通知交互中,需要应用程序捕捉信号,驱动程序释放信号。



所要设计的 3 项工作:

支持 F_SETOWN 命令,能在这个控制命令处理中设置 filp->f_owner 为对应进程 ID。不过此项工作已由内核完成,设备驱动无需处理。 支持 F_SETFL 命令的处理,每当FASYNC 标志改变时,驱动程序中的fasync()函数将得以执行。因此,驱动中应该实现 fasync()函数。 在设备资源可获得时,调用 kill_fasync()函数激发相应的信号。

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

474

主题

476

帖子

0

粉丝