目录
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 判断这个是否为真,即是否存在,如果存在就调用到底层fasync
if (((arg ^ filp->f_flags) & FASYNC) && filp->f_op->fasync) {
error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
}
}