函数read_seqretry():读者在访问完被顺序锁s1保护的共享资源后需要调用该函数来检查,在读访问期间是否有写者访问了该共享资源,该检查是通过判断当前顺序锁sl的顺序号与初始顺序号start是否相等实现的。如果不相等,则读访问期间有写者访问了共享资源,读者就需要重新进行读操作,否则,读者成功完成了读操作。
read_seqretry文件包含
#include <linux/seqlock.h>
read_seqretry函数定义
在内核源码中的位置:linux-3.19.3/include/linux/seqlock.h
函数定义格式:
static inline unsigned read_seqretry(const seqlock_t *sl, unsigned start)
read_seqretry输入参数说明
sl
:指向顺序锁结构体的指针。关于顺序锁结构体seqlock _t的定义及顺序锁的概念参考极客笔记中宏seqlock_init()的分析。start
:表示顺序锁的初始顺序号。
read_seqretry返回参数说明
- 函数
read_seqretry()
返回一个无符号整型值,该值一般为1或者0,如果返回1,则读者需要重新进行读操作,返回0,则读者成功完成了读操作。
read_seqretry实例解析
编写测试文件:read_seqretry.c
头文件及全局变量声明如下:
#include <linux/seqlock.h>
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
static int __init read_seqretry_init(void);
static void __exit read_seqretry_exit(void);
seqlock_t seqlock ;
模块初始化函数:
int __init read_seqretry_init(void)
{
int ret;
seqlock_init( &seqlock ); //初始化顺序锁
/*一下两行输出顺序锁中自旋锁字段值和顺序锁当前的顺序号*/
printk("after seqlock_init, sequence: %d\n\n", seqlock.seqcount.sequence);
write_seqlock( &seqlock ); //写者申请顺序锁
printk("after write_seqlock, sequence: %d\n\n", seqlock.seqcount.sequence);
write_sequnlock( &seqlock ); //写者释放顺序锁
printk("after write_sequnlock, sequence: %d\n\n", seqlock.seqcount.sequence);
do{
ret = read_seqbegin( &seqlock );
printk("ret = %d\n", ret );
}while( read_seqretry(&seqlock, ret) ); //读操作代码块
return 0;
}
模块退出函数:
void __exit read_seqretry_exit(void)
{
printk("exit! \n");
}
模块初始化及退出函数调用:
module_init(read_seqretry_init);
module_exit(read_seqretry_exit);
实例运行结果及分析:
首先编译模块,执行命令insmod read_seqretry.ko插入模块,然后执行命令dmesg -c,会出现如图所示的结果。
结果分析:
测试程序中调用了宏seqlock_init()和函数write_seqlock()、函数write_sequnlock(),其功能参考极客笔记中关于它们的分析。
读者使用顺序锁的模式一般为:
do{
ret = read_seqbegin( &seqlock );
printk("ret = %d\n", ret );
// 在这里执行读操作…
}while( read_seqretry(&seqlock, ret) );
读者从ret_seqbegin()返回后,得到顺序锁的当前顺序号,并开始执行对共享资源的读操作。如果期间有写者修改了共享资源,则read_seqretry()将返回真,从而使读者重新执行读操作以确保数据的一致性。
在测试程序中读操作代码块缺省,即没有共享资源会被写者获取,因此read_seqretry()返回假,即读者执行一次读操作即成功。另外,对于单处理器体系结构的机器,在执行程序代码中的do…while循环体时,不会出现其他写者修改共享资源的情况,read_seqretry()返回假,读者执行一次读操作即成功。