设备驱动之异步通知机制

异步通知:意思就是,一旦设备就绪,则主动通知应用程序,这样应用程序根本不需要查询设备状态,非常类似于硬件上"中断的概念"

准确一点就叫:信号驱动(SIGIO)的异步I/O

实现异步通知,内核需要知道几个东西:哪个文件(filp),什么信号(SIGIIO),发给哪个进程(pid),收到信号后做什么(sig_handler)。这些都由上述前两个步骤完成了,而这前两个步骤内核帮忙实现了,所以,我们只需要实现第三个步骤的一个简单的传参。

设置异步通知的步骤(针对应用层来说的):
1.首先指定一个进程作为文件的属主。通过使用fcntl系统调用执行F_SETOWN命令时,属主进程的ID号就会保存在filp->f_owner中,目的是为了让内核知道应该通知哪个进程。
2.在设备中设置FASYNC标志。通过fcntl调用的F_SETFL来完成。
设置晚以上两步后,输入文件就可以在新数据到达时请求发送一个SIGIO信号,该信号被发送到存放在filp->f_owner中的进程。

通过signal(SIGIO,input_handler)对STDIN_FILENO启动信号机制,

/*
异步通知3个步骤:
1,signal(SIGIO, input_handler); 
调用signal函数,让指定的信号SIGIO与处理函数input_handler对应;
2,fcntl(STDIN_FILENO, F_SETOWN, getpid()); 
指定一个进程作为文件的属主(filp->owner),这样内核才知道信号要发给哪个进程
3,   oflags = fcntl(STDIN_FILENO, F_GETFL); //F_GETFL读取文件状态标识
    fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC); //F_SETFL:设置文件状态标识
在设备文件中添加FASYNC标识,驱动中就会调用将要实现的input_handler函数
这3个步骤执行后,一旦有信号产生,相应的进程就会收到


*/


#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; 
 //函数原型:sig_t signal(int signum,sig_t handler); 
 //signum:指明要处理的信号类型
 //handler:描述了与信号关联的动作,可以取以下3种值:
 //1,一个返回值为正数的函数地址,此函数必须在signal被调用前申明,handler中为这个函数的名字
 //当接收到一个类型为sig的信号时,就执行handler所指定的函数,这个函数的定义形式应该为:
 //int func(int sig),sig是传递给它的唯一参数,执行了signal调用之后,进程只要收到类型为sig的信号
 //不管其正在执行程序的哪一部分,就立即执行func()函数,当func()函数执行结束后,控制权返回进程被中断的那一点继续执行
 //2,SIGIGN:表示忽略该信号,执行了相应的signal()调用后,进程忽略类型为sig的信号
 //3,SIGDFL 这个符号表示恢复系统对信号的默认处理
  //函数说明:signal()会依参数signum指定的信号编号来设置该信号的处理函数,当指定的信号到达时就会跳转到函数handler指定的函数执行
  //当一个信号的信号处理函数执行时,如果进程又接收到了该信号,该信号会自动被储存而不会中断信号处理函数的执行
  //直到信号处理函数执行完毕再重新调用相应的处理函数,但是如果在信号处理函数执行时进程收到了其它类型的信号,该函数的执行就会被中断
  //返回值;返回先前的信号处理函数指针,如果有错误则返回SIG_ERR(-1).  
    //启动信号驱动机制 
    signal(SIGIO, input_handler); 
    
    //fcntl:根据文件描述词来操作文件的特性
    //通过这个函数改变一个已打开的文件的属性,可以重新设置读,写,追加,非阻塞等标识


    /*
    用法:   
int fcntl(int fd, int cmd); 
int fcntl(int fd, int cmd, long arg); 
int fcntl(int fd, int cmd, struct flock *lock); 
参数:
fd:文件描述词。 
cmd:操作命令。 
arg:供命令使用的参数。 
lock:同上。


    */
    //getpid()用于取得目前进程的进程ID
    //STDIN_FILENO:系统级API接口库
    //F_SETOWN:设置将要在文件描述词fd上接收SIGIO或SIGURG事件信号的进程或进程组标识
    fcntl(STDIN_FILENO, F_SETOWN, getpid()); 
    oflags = fcntl(STDIN_FILENO, F_GETFL); //F_GETFL读取文件状态标识
    fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC); //F_SETFL:设置文件状态标识
  //其中O_RDONLY, O_WRONLY, O_RDWR, O_CREAT,  O_EXCL, O_NOCTTY 和 O_TRUNC不受影响,可以更改的标志有 O_APPEND,O_ASYNC, O_DIRECT, O_NOATIME 和 O_NONBLOCK。 
    //最后进入一个死循环,程序什么都不干了,只有信号能激发 input_handler 的运行 
    //如果程序中没有这个死循环,会立即执行完毕 
    while (1); 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值