> 文章列表 > Linux驱动开发 IO模型:异步通知IO

Linux驱动开发 IO模型:异步通知IO

Linux驱动开发 IO模型:异步通知IO

目录

1、异步通知IO模型是什么

2、应用程序

2.1 应用程序的步骤

2.2 应用程序编写

3、驱动程序

3.1 fasync()函数:完成发信号前的初始化

3.2  fasync_helpe()函数解析

3.3 虚拟文件系统层的实现


1、异步通知IO模型是什么

        在进程中注册一个信号处理函数,如果硬件的数据准备好的时候,会产生中断,在中断处理函数中给这个进程发送信号即可。如果内核没有发出信号应用程序,不需要阻塞,运行自己特有的代码即可。

2、应用程序

2.1 应用程序的步骤

1、注册信号处理函数

signal(SIGIO,signal_handle)

2、通过fcntl调用到底层的fasync函数

flag = fcntl(fd, F_GETFL);

fcntl(fd, F_SETFL, flag | FASYNC);

3、将当前进程号告诉内核

fcntl(fd,F_SETOWN,getpid());

2.2 应用程序编写

int fd;
char buf[128] = {0};void signal_handle(int signo)
{if(signo == SIGIO) {memset(buf,0,sizeof(buf));read(fd,buf,sizeof(buf));  printf("buf = %s\\n", buf);}
}int main(int argc, char argv)
{fd = open("/dev/mycdev", O_RDWR);if(signal(SIGIO,signal_handle) == SIG_ERR)PRINT_ERR("signal error");fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)|FASYNC);fcntl(fd,F_SETOWN,getpid());close(fd);return 0;
}

3、驱动程序

3.1 fasync()函数:完成发信号前的初始化

本来也要在中断处理函数中发送,此处同样的也是在write函数中发信号

ssize_t mycdev_write(struct file *file, const char __user * ubuf, size_t size, loff_t * offs)
{kill_fasync(&fapp, SIGIO, POLL_IN);
}int mycdev_fasync(int fd, struct file *file, int on)
{return fasync_helper(fd, file, on, &fapp);
}const struct file_operations fops = {.write = mycdev_write,.fasync = mycdev_fasync,
};

3.2  fasync_helpe()函数解析

int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct fapp)
{if (!on)return fasync_remove_entry(filp, fapp);return fasync_add_entry(fd, filp, fapp);
}static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct fapp)
{struct fasync_struct *new;new = fasync_alloc();if (fasync_insert_entry(fd, filp, fapp, new)) {fasync_free(new);return 0;}
}struct fasync_struct *fasync_insert_entry(int fd, struct file *filp, struct fasync_struct fapp, struct fasync_struct *new)
{struct fasync_struct *fa, fp;    //遍历队列,找到队尾for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {if (fa->fa_file != filp)continue;fa->fa_fd = fd;}//填充这个结构体new->magic = FASYNC_MAGIC;new->fa_file = filp;new->fa_fd = fd;//放到队尾new->fa_next = *fapp;rcu_assign_pointer(*fapp, new);filp->f_flags |= FASYNC;
}

3.3 虚拟文件系统层的实现

SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
{	do_fcntl(fd, cmd, arg, f.file);
}static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,struct file *filp)
{long err = -EINVAL;switch (cmd) {    case F_GETFL:err = filp->f_flags;break;case F_SETFL:err = setfl(fd, filp, arg);break;
}static int setfl(int fd, struct file * filp, unsigned long arg)
{//arg = filp->f_flags | FASYNC//所以这句话(arg ^ filp->f_flags) & FASYNC 代表检查是否设置为FASYNC,是为真//filp->f_op->fasync 判断这个是否为真,即是否存在,如果存在就调用到底层fasyncif (((arg ^ filp->f_flags) & FASYNC) && filp->f_op->fasync) {error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);}}