• Linux设备驱动程序 之 异步通知


    尽管大多数时候阻塞型和非阻塞型操作的组合以及select方法可以有效的查询设备,但是某些时候用这种技术处理就效率不搞了;

    例如:一个进程在低优先级执行长的循环计算,但又需要尽可能快的处理输入数据,如果该进程正在响应来自数据收集外设新观测的数据,则应该在新数据可用时理解知晓并处理;我们可以使用poll来检查,但是跟好的做法是通过异步通知,应用程序可以再数据可用时收到一个信号,而不需要不停的使用轮询来关注数据;

    从应用程序的角度

    启用文件的异步通知机制,用户程序必须执行两个步骤:

    1. 需要制定一个进程作为文件的“属主(owner)”;当进程使用fcntl系统调用执行F_SETOWN命令时,属主进程的ID号就被保存在filp->f_owner中,这样做的目的是为了让内核知道该通知哪个进程;

    2. 为了真正启用异步通知机制,用户程序还必须在设备中设置FASYNC标志,这是通过fcntl的F_SETFL命令完成的;

    执行完这两个步骤之后,输入文件就可以在新数据到达时发送一个SIGIO信号,该信号被发送到存放在filp->f_owner中的进程,如果f_owner是负值,信号会被发送到该进程组;

    使用事例如下:

    1 signal(SIGIO, &input_handler);
    2 fcntl(STDIN_FILENO, F_SETOWN, getpid());
    3 oflags = fcntl(STDIN_FILENO, F_GETFL);
    4 fcntl(STDIN_FILENO, F_SETFL, oflags|FASYNC);

    不是所有设备都支持异步通知,我们可以选择不提供异步通知功能;应用程序通常假设只有套接字和终端才有异步通知能力;

    当进程收到SIGIO信号时,并不知道是那个输入文件有了新的输入,如果有多个文件可以异步通知输入进程,则应用程序仍然需要借助poll或者select来确定输入的源;

    从驱动程序角度

    驱动程序实现异步通知的步骤如下:

    1. F_SETOWN被调用时对filp->f_owner赋值;

    2. 在执行F_SETFL启用FASYNC时,调用驱动程序的fasync方法,只要filp->f_flags中的FASYNC标志发生了变化,就会调用该方法,以便把这个变化通知驱动程序,使其能正确响应;文件打开时,FASYNC标志被默认为是清除的;

    其中fasync方法即为file_operations中的fasync方法:

    1 int (*fasync) (int, struct file *, int);

    3. 当数据到达时,在所有注册为异步通知的进程都会被发送一个SIGIO信号;

    驱动程序需要调用下面两个函数来完成异步通知功能:

    1 int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
    1 void kill_fasync(struct fasync_struct **fp, int sig, int band)

    当一个打开的文件的FASYNC标志被修改时,调用fasync_helper以便从相关的进程列表中增加或者删除文件;除了最后一个参数之外,其他参数都是提供给fasync方法相同的参数,可以直接传递;

    在数据到达时,可以调用kill_fasync通知所有相关进程,它的参数包括要发送的信号(通常是SIGIO)和带宽(band),后者几乎总是POLL_IN,但是在网络待命中,可以用来发送紧急或者带外数据;

    当文件关闭时必须调用fasync方法,以便从活动的异步读取进程列表中删除该文件;尽管调用只在filp->f_flags设置了FASYNC标志时才是必须的,但不管什么情况,调用它不会有坏处,并且也是普遍的实现方法;

  • 相关阅读:
    windows常用命令行总结
    express安装
    MySQL去除外键关联关系
    c#实体转化
    C#之Clone
    mysql 将null转代为0(转)
    Mysql显示行号
    mysql存储过程游标加计划任务事件调度器
    mysql临时表
    Git学习笔记
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/11760821.html
Copyright © 2020-2023  润新知