Linux驱动中的fasync(异步通知)和fsync
创始人
2024-05-31 14:26:56
0

一、fsync

用来同步设备的写入操作,考虑把一块设局写入到硬盘的操作,如果使用write函数,函数返回后只能保证数据被写入到驱动程序或者内核管理的数据缓存中,而无法保证数据被真正写入到硬盘的存储块里。但是fync可以做到这一点,函数在数据块没有真正写道硬盘的存储卡里时不会返回,若返回则意味着要么设备在写入过程发生错误,要么数据已经写入到了设备的存储块。

显然大量的工作都在驱动程序这边,驱动程序需要针对不同的设备实现wirte和fsync例程,以满足应用程序的需求。

对于字符设备而言,大部分驱动程序都没有实现这个例程,只是简单将它们的struct file_operations对象的fsync指针赋值为NULL;对于块设备而言,则需要实现fsync。

    int (*fsync) (struct file *, loff_t, loff_t, int datasync);

二、fasync(异步通知)

在异步非阻塞型I/O(AIO)中,基于驱动程序poll例程之上的应用层的三个函数poll、select、epoll,它们在与驱动程序沟通数据是否就绪时,本质是采用了轮询的方式:应用程序在一组由设备文件描述符的集合上调用poll,由此获得设备可否进行无阻塞操作的信息。

其实除了轮询的方式,应用程序与设备驱动的沟通还有一种类似中断的方式;当设备中的数据就绪时,作为通知的方式,驱动程序给应用程序发送一个signal。

异步通知使用了系统调用的signal()和sigcation()函数。signal()函数会让一个信号和一个函数对应,每当接收到这个信号时就会调用相应的函数来处理。异步通知处理过程中用户空间和设备驱动的交互如下:

应用层的处理

1)设置信号处理函数:

我们使用中断的时候需要设置中断处理函数,同样的,如果要在应用程序中使用信号,那么就必须设置信号所使用的信号处理函数。在应用程序中使用 signal 函数来设置指定信号的处理函数:

//signum:要设置处理函数的信号。
//handler: 信号的处理函数。
//返回值: 设置成功的话返回信号的前一个处理函数,设置失败的话返回 SIG_ERR。
sighandler_t signal(int signum, sighandler_t handler);

2)fcntl函数需要做二件事:

将本应用程序的进程号告诉给内核使用:

/*通过fcntl函数的F_SETOWN命令将进程的ID告诉驱动程序,这样当驱动发现设备的数据就绪时才
直到要通知哪个进程*/
fcntl(fd, F_SETOWN, getpid());

使用如下两行程序开启异步通知:

/*获取当前的进程状态*/
flags = fcntl(fd, F_GETFL);
/*
通过F_SETFL命令设置FASYNC标志让驱动程序启动异步通知机制(开启当前进程异步通知功能),
经过这一步,驱动程序中的 fasync 函数就会执行。
*/                     
fcntl(fd, F_SETFL, flags | FASYNC);        

下面是内核的系统调用接口,从中可以看到会调用驱动程序提供的fasync例程:

static int setfl(int fd, struct file * filp, unsigned long arg)
{...if (((arg ^ filp->f_flags) & FASYNC) && filp->f_op->fasync) {error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);...}...
}static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,struct file *filp)
{long err = -EINVAL;...switch (cmd) {...case F_SETFL:/*会在内部直接调用驱动程序提供的fasync例程*/err = setfl(fd, filp, arg);break;...case F_SETOWN:/*将要通知进程的ID相关信息记录在filp->f_owner中,驱动程序无需对此做出回应*/err = f_setown(filp, arg, 1);break;...default:break;}return err;
}

内核层的处理

在设备驱动和应用程序的异步通知交互中, 仅仅在应用程序端捕获信号是不够的, 因为信号的源头在设备驱动端。 因此, 应该在合适的时机让设备驱动释放信号, 在设备驱动程序中增加信号释放的相关代码。

设备驱动中异步通知编程比较简单, 主要用到一项数据结构和两个函数。使用时,首先需要定义一个struct fasync_struct类型的指针,当用户程序调用fcntl用F_SETFL命令来设置或者清除FASYNC标志时,驱动程序应该在其fasync例程中调用内核提供的fasync_helper函数在struct fasync_struct指针所指向的链表中增加或者删除一个节点,每个节点代表一个需要通知的进程。其次,当进程所需的数据就绪或者关注的某个事件发生时,驱动程序使用内核提供的kill_fasync函数负责向维护的struct fasync_struct链表中的每个进程发送通知信号。

数据结构是fasync_struct结构体:

支持异步通知的设备结构体模板如下:

struct fasync_struct {rwlock_t        fa_lock;int            magic;int            fa_fd;struct fasync_struct    *fa_next; /* singly linked list */struct file        *fa_file;struct rcu_head        fa_rcu;
};struct xxx_dev {struct cdev cdev;...struct fasync_struct *fasync_queue  //异步结构体指针
}

两个函数分别是:

1)需要在设备驱动中实现 file_operations 操作集中的 fasync 函数:

    int (*fasync) (int, struct file *, int);

该函数一般通过调用 fasync_helper 函数来初始化前面定义的 fasync_struct结构体指针。fasync_helper主要将当前要通知的进程加入一个链表或者从链表中移除,这取决于应用程序调用fcntl时是否设置了FASYNC标志。

/*
1)第二个参数on:上面提到的setfl()函数中,传递给它的是一个条件表达式(arg & FASYNC) != 0,
这意味着如果应用程序在调用fcntl时,对于F_SETFL命令使用的参数arg设置了FASYNC,那么
(arg & FASYNC) != 0结果为1,所以参数on将为1,这表明应用程序正在启用驱动程序的异步通知
机制;反之,当对fcntl函数使用F_SETFL命令时清除了FASYNC标志,将导致驱动程序的fasync例程
关闭异步通知特性。
2)所以fasync_helper的主要作用是维护一个需要通知的进程链表fapp,如果应用程序需要获得异步通知
的能力,那么需要通过fcntl的F_SETFL命令设置FASYNC标志,如果设置了该标志,驱动程序的fasync例程
在调用fasync_helper时将用fasync_add_entry将需要通知的进程加入到驱动程序维护的一个链表中,
否则使用fasync_remove_entry将其从链表中移除。
3)链表的类型为struct fasync_struct,链表中的每个节点对象代表着一个需要通知的进程,进程ID
信息存放再节点对象的fa_file->f_owner中。例如当有二个用户进程需要得到设备驱动程序的异步通知时,
内核在实现fasync_helper函数时,对于一个新加入的struct fasync_struct对象节点,会将其放到
链表的头部,这就意味着应用层后调用fcntl(fd, F_SETFL, FASYNC)的应用程序反而先得到通知。
*/
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);
}

使用模板:

在设备驱动的fasync函数中, 只需要简单地将该函数的3个参数以及fasync_struct结构体指针的指针作为第4个参数传入fasync_helper函数即可。

//在关闭驱动文件的时候需要在 file_operations 操作集中的 release 函数中释放fasync_struct

2)kill_fasync则在设备中的某一事件发生时负责通知链表中的所有相关的进程。

现在,驱动程序已经将需要通知的进程所在的节点加入了fasync链表。当需要的条件满足时,比如进程所请求的数据已经就绪,驱动程序需要使用kill_fasync来向fasync链表中的每个等待通知的进程发送通知信号。

/*通过while循环遍历fasync链表,定义每个进程调用send_sigio来向其发送信号SIGIO以通知进程*/
static void kill_fasync_rcu(struct fasync_struct *fa, int sig, int band)
{while (fa) {struct fown_struct *fown;unsigned long flags;if (fa->magic != FASYNC_MAGIC) {printk(KERN_ERR "kill_fasync: bad magic number in ""fasync_struct!\n");return;}read_lock_irqsave(&fa->fa_lock, flags);if (fa->fa_file) {fown = &fa->fa_file->f_owner;/* Don't send SIGURG to processes which have not set aqueued signum: SIGURG has its own default signallingmechanism. */if (!(sig == SIGURG && fown->signum == 0))send_sigio(fown, fa->fa_fd, band);}read_unlock_irqrestore(&fa->fa_lock, flags);fa = rcu_dereference(fa->fa_next);}
}void kill_fasync(struct fasync_struct **fp, int sig, int band)
{if (*fp) {rcu_read_lock();kill_fasync_rcu(rcu_dereference(*fp), sig, band);rcu_read_unlock();}
}

使用模板:

相关内容

热门资讯

梦想的意义作文400字【精简... 梦想的意义作文400字 篇一梦想的意义每个人都有自己的梦想,无论大小,梦想对于一个人来说都有着深远的...
《三怪客泛舟记》英文读后感(... 《三怪客泛舟记》英文读后感 篇一After reading "The Adventures of t...
健身英语作文【最新6篇】 健身英语作文 篇一:健身的好处健身英语作文 篇二:如何制定健身计划健身英语作文 篇三   Sport...
初中英语作文(精选3篇) 初中英语作文 篇一My Favorite HobbyHobbies are an important...
英语作文Basketball... 英语作文Basketball 篇一Basketball is not just a sport, b...
娱乐活动的英语作文(经典6篇... 娱乐活动的英语作文 篇一Title: The Importance of Participating...
我的梦想英语作文【精彩6篇】 我的梦想英语作文 篇一My DreamEveryone has dreams. Dreams are...
英文寻物启事格式【精彩6篇】 Lost: Black Leather WalletLost on September 15th, ...
袁隆平英语作文(优选5篇) 袁隆平英语作文 篇一The Life and Achievements of Yuan Longpi...
介绍我自己英语作文 介绍我自己英语作文(精选24篇)  无论是身处学校还是步入社会,许多人都有过写作文的经历,对作文都不...
生活中的邮政英语作文【精选3... 生活中的邮政英语作文 篇一The Importance of Postal Services in ...
介绍朋友的英语作文【最新6篇... Introduction of My FriendEssay OneMy Friend LilyI ...
我的未来计划的英语作文【优秀... 我的未来计划的英语作文 篇一Title: My Future PlanAs a high schoo...
有关朋友的英语句子【优质3篇... 有关朋友的英语句子 篇一Friendship is one of the most precious...
各时态词语表示强调的英语例句... 各时态词语表示强调的英语例句 篇一In the English language, differen...
小学想象作文200字 小学想象作文200字  【篇一:未来世界】  我对未来世界总是充满幻想的。  假如在未采世界你想去天...
冬至的:冬至的介绍英语作文【... 冬至的:冬至的介绍英语作文 篇一Title: The Significance of Winter ...
作文 未来的电子书(经典3篇... 作文 未来的电子书 篇一随着科技的不断发展,电子书逐渐成为人们阅读的新选择。未来的电子书将会带来怎样...
写加拿大的英语作文100字(... 写加拿大的英语作文100字 篇一Canada: A Land of Diversity and Op...
学校英语作文 学校英语作文(7篇)  在学习、工作乃至生活中,大家或多或少都会接触过作文吧,作文是经过人的思想考虑...