Skip to content

Latest commit

 

History

History
173 lines (143 loc) · 6.71 KB

异步通知.md

File metadata and controls

173 lines (143 loc) · 6.71 KB

异步通知

适合于驱动文件主动向应用程序发出通知

信号

  1. 路径: arch/xtensa/include/uapi/asm/signal.h ,该文件定义了Linux所支持的所有信号

  2. 信号值:

        #define SIGHUP      1   //终端挂起或控制进程终止
        #define SIGINT      2   //终端中断(Ctrl+C组合键)
        #define SIGQUIT     3   //终端退出(Ctrl+\组合键)
        #define SIGILL      4   //非法指令
        #define SIGTRAP     5   /* debug 使用,有断点指令产生 */
        #define SIGABRT     6   /* 由 abort(3)发出的退出指令 */
        #define SIGIOT      6   /* IOT 指令 */
        #define SIGBUS      7   /* 总线错误 */
        #define SIGFPE      8   /* 浮点运算错误 */
        #define SIGKILL     9   /* 杀死、终止进程 */
        #define SIGUSR1     10  /* 用户自定义信号 1 */
        #define SIGSEGV     11  /* 段违例(无效的内存段) */
        #define SIGUSR2     12  /* 用户自定义信号 2 */
        #define SIGPIPE     13  /* 向非读管道写入数据 */
        #define SIGALRM     14  /* 闹钟 */
        #define SIGTERM     15  /* 软件终止 */
        #define SIGSTKFLT   16  /* 栈异常 */
        #define SIGCHLD     17  /* 子进程结束 */
        #define SIGCONT     18  /* 进程继续 */
        #define SIGSTOP     19  /* 停止进程的执行,只是暂停 */
        #define SIGTSTP     20  /* 停止进程的运行(Ctrl+Z 组合键) */
        #define SIGTTIN     21  /* 后台进程需要从终端读取数据 */
        #define SIGTTOU     22  /* 后台进程需要向终端写数据 */
        #define SIGURG      23  /* 有"紧急"数据 */
        #define SIGXCPU     24  /* 超过 CPU 资源限制 */
        #define SIGXFSZ     25  /* 文件大小超额 */
        #define SIGVTALRM   26  /* 虚拟时钟信号 */
        #define SIGPROF     27  /* 时钟信号描述 */
        #define SIGWINCH    28  /* 窗口大小改变 */
        #define SIGIO       29  /* 可以进行输入/输出操作 */
        #define SIGPOLL     SIGIO
        /* #define SIGLOS 29 */
        #define SIGPWR      30  /* 断点重启 */
        #define SIGSYS      31  /* 非法的系统调用 */
        #define SIGUNUSED   31  /* 未使用信号 */

    在这些信号中,除了 SIGKILL(9) 和 SIGSTOP(19) 这两个信号不能被忽略之外,其他信号都可以忽略。这些信号就相当于中断号,不同的中断号代表不同的中断。不同的中断所做的处理不同,因此,驱动程序可以通过向应用程序发送不同的信号来实现不同的功能。

  3. API

  • APP应用层

    1. 设置信号回调处理函数
        typedef void(*sighandler_t)(int sig);
    
        sighandler_t signal(int signum, sighandler_t handler)
    
        signum:     要设置处理函数的信号
        handler信号处理函数
        返回值成功返回信号的前一个处理函数
                    失败SIG_ERR
    
    
        typedef void (*sighandler_t)(int)
    1. 文件描述符控制接口 fcntl
        函数原型int fcntl(int fd, int cmd);
        int fcntl(int fd, int cmd, long arg);         
        int fcntl(int fd, int cmd, struct flock *lock);
    
        fcntl函数有5种功能1.复制一个现有的描述符cmd=F_DUPFD).

   2.获得/设置文件描述符标记 (cmd=F_GETFD或F_SETFD). 3.获得/设置文件状态标记 (cmd=F_GETFL或F_SETFL). 4.获得/设置异步I/O所有权 (cmd=F_GETOWN或F_SETOWN). 5.获得/设置记录锁 (cmd=F_GETLK,F_SETLK或F_SETLKW). ```

  • 驱动层

    • 数据结构
    struct fasync_struct {
                spinlock_t fa_lock;
                int magic;
                int fa_fd;
                struct fasync_struct *fa_next;
                struct file *fa_file;
                struct rcu_head fa_rcu;
            };

    驱动层如果要使用异步通知,则需在设备驱动中实现 file_operations 文件操作集合中的 fasync 函数

        int (*fasync) (int fd, struct file *filp, int on)   //该函数接口用于实现 指定app层进程,即 该驱动的信号发送到哪个进程
    • 初始化: 在驱动层定义(实现)该函数时,一般通过调用 fasync_helper 函数来 初始化 驱动层的 fasync_struct 结构体 fasync_helper 原型
        int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
    
        传参的前3个参数就是 fasync 函数传参的那3个参数第4个参数就是要初始化的 fasync_struct 结构
    
        补充功能是向谁哪个进程
    • 发送
        void kill_fasync(struct fasync_struct **fp, int sig, int band)
    
        fp要操作的 fasync_struct 数据结构
        sig要发送的信号band可读时设置为 POLL_IN可写时设置为 POLL_OUT补充功能是向应用程序发送可读信号
  • 场景 当应用程序通过 fcntl(fd, F_SETFL, flags | FASYNC) 来改变 fasync 标记是,驱动的 fasync 函数就会执行

    1. 驱动demo
        static struct fasync_struct * fasync_queque ;
    
        static int dev_fasync(int fd, struct file *filp, int on)
        {
            struct fasync_struct *p = (struct fasync_struct)filp->private_data;
    
            if(fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp))  //初始化
            {
                return -EIO ;
            }
            return 0 ;
    
            //或者
            return  fasync_helper(fd, filp, on, struct fasync_struct **fapp);
    
        }
    
        static struct file_operations xxx_ops = {
            ......
            .fasync = dev_fasync,
            ......
        };
    
        //中断回调
        void xx_irp_cd()
        {
            kill_fasync(&fasync_queque,SIGIO ,POLL_IN);
        }
    
        假如在 dev_fasync 申请了一些资源要在 xxx_ops.release 释放掉初始化的信号不用释放定义的 fasync_struct 数据结构在驱动中并没有真实成员赋值都是API的调用
    1. app demo
      • 流程(3次使用的 fcntl )
        1. 注册信号处理函数
            sighandler_t signal(int signum, sighandler_t handler)
        1. 将本应用程序的进程号告诉给内核
            fcntl(fd, F_SETOWN, getpid())
        1. 开启异步通知
            flags = fcntl(fd, F_GETFL); /* 获取当前的进程状态 */
            fcntl(fd, F_SETFL, flags | FASYNC); /* 开启当前进程异步通知功能 */