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();}
}

使用模板:

相关内容

热门资讯

常用商务英语口语   商务英语是以适应职场生活的语言要求为目的,内容涉及到商务活动的方方面面。下面是小编收集的常用商务...
六年级上册英语第一单元练习题   一、根据要求写单词。  1.dry(反义词)__________________  2.writ...
复活节英文怎么说 复活节英文怎么说?复活节的英语翻译是什么?复活节:Easter;"Easter,anniversar...
2008年北京奥运会主题曲 2008年北京奥运会(第29届夏季奥林匹克运动会),2008年8月8日到2008年8月24日在中华人...
英语道歉信 英语道歉信15篇  在日常生活中,道歉信的使用频率越来越高,通过道歉信,我们可以更好地解释事情发生的...
六年级英语专题训练(连词成句... 六年级英语专题训练(连词成句30题)  1. have,playhouse,many,I,toy,i...
上班迟到情况说明英语   每个人都或多或少的迟到过那么几次,因为各种原因,可能生病,可能因为交通堵车,可能是因为天气冷,有...
小学英语教学论文 小学英语教学论文范文  引导语:英语教育一直都是每个家长所器重的,那么有关小学英语教学论文要怎么写呢...
英语口语学习必看的方法技巧 英语口语学习必看的方法技巧如何才能说流利的英语? 说外语时,我们主要应做到四件事:理解、回答、提问、...
四级英语作文选:Birth ... 四级英语作文范文选:Birth controlSince the Chinese Governmen...
金融专业英语面试自我介绍 金融专业英语面试自我介绍3篇  金融专业的学生面试时,面试官要求用英语做自我介绍该怎么说。下面是小编...
我的李老师走了四年级英语日记... 我的李老师走了四年级英语日记带翻译  我上了五个学期的小学却换了六任老师,李老师是带我们班最长的语文...
小学三年级英语日记带翻译捡玉... 小学三年级英语日记带翻译捡玉米  今天,我和妈妈去外婆家,外婆家有刚剥的`玉米棒上带有玉米籽,好大的...
七年级英语优秀教学设计 七年级英语优秀教学设计  作为一位兢兢业业的人民教师,常常要写一份优秀的教学设计,教学设计是把教学原...
我的英语老师作文 我的英语老师作文(通用21篇)  在日常生活或是工作学习中,大家都有写作文的经历,对作文很是熟悉吧,...
英语老师教学经验总结 英语老师教学经验总结(通用19篇)  总结是指社会团体、企业单位和个人对某一阶段的学习、工作或其完成...
初一英语暑假作业答案 初一英语暑假作业答案  英语练习一(基础训练)第一题1.D2.H3.E4.F5.I6.A7.J8.C...
大学生的英语演讲稿 大学生的英语演讲稿范文(精选10篇)  使用正确的写作思路书写演讲稿会更加事半功倍。在现实社会中,越...
VOA美国之音英语学习网址 VOA美国之音英语学习推荐网址 美国之音网站已经成为语言学习最重要的资源站点,在互联网上还有若干网站...
商务英语期末试卷 Part I Term Translation (20%)Section A: Translate ...