之前说的几个模型都是主动去监控的,那么这个异步通知就和之前说的不一样,是被动的,当中断发生时候去通知CPU,CPU就会过来做这件事,然后昨晚再跳回去做原来的事
从张图可以看出,需要有个发送信号(驱动),一个接收信号(app)
下面我们来实现发送和接收信号的功能
接收信号功能(app):
signal(SIGIO,catch_signal);//设置信号处理函数
fcntl(fd,F_SETOWN,getpid());
int flags=fcntl(fd,F_GETFL);//拿到open时候的flags
fcntl(fd,F_SETFL,flags | FASYNC);
在信号处理函数中,只要收到SIGIO函数就会执行对应的信号处理函数catch_signal,
fcntl(fd,F_SETOWN,getpid())将当前进程设置成SIGIO的属主进程,getpid()获取进程号
fcntl(fd,F_SETFL,flags | FASYNC);将打开文件时候获取的flags设置成FASYNC,
总结:需要做好这三件事
现在已经将接受驱动发送信号的事情做好了,接下来做收到信号以后需要做出相应的操作,在catch_signal函数中实现
void catch_signal(int s){
if(s==SIGIO)
{
printf("\nWe got signo!!\n");
read(fd,&key,sizeof(struct key_event));
if(key.code==KEY_ENTER)
{
if(key.value==0)
{
printf("\n key up!!!!!!!!!! \n");
}
if(key.value==1)
{
printf("\n key down!!!!!!!!!! \n");
}
}
}
}
发送信号的驱动程序:
什么时候发送信号呢?当然是按下按键,中断发生的时候,所以在中断处理函数中.
kill_fasync(&my_key.fapp,SIGIO,POLLIN);//发送信号
此外还要在file_operations结构体中实现fsync函数
static struct file_operations myfops={
.owner=THIS_MODULE,
.open=key_open,
.release=key_close,
.write=key_write,
.read=key_read,
.poll=key_poll,
.fsync=key_fsync,
};
同时去实现这个函数
fasync_helper作用就是初始化fasync,包括分配内存和设置属性,最后在驱动的release里把fasync_helper初始化的东西free掉。
int key_fsync (int fd,struct file *file, int on)
{
return fasync_helper(fd,file,on, &my_key.fapp);
//fasync_helper中前三个函数是调用app调用fcntl函数时候自己传参的
//然后将这三个参数处理后存到最后一个参数
}
我们来看看这个函数的原型
int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
最后一个参数的类型是struct fasync_struct **
所以我们要将一个这样的类型传进去,为了好惯例,在结构中定义
struct fasync_struct *fapp;
这样就可以实现异步通知了