非抢占式RCU实现(二),解释:为什么 RCU_NEXT_SIZE 宏值是4?
参考:2.6.34
一个很奇怪的问题。
没有查找到为什么 RCU_NEXT_SIZE的值为4的原因(包括Documentation),主要是在rcu_state中定义了一个四级的list,感到很有意思。
我给出自己的解释。
还是看下代码吧,容易解释:
=========================================================
引入nxtlist与 RCU_NEXT_RCU_DONE_TAIL
static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
|---->if(!cpu_has_callbacks_ready_to_invoke(rdp))
|----- return
|-----看下cpu_has_callbacks_ready_to_invoke的实现
|----- |---- return &rdp->nxtlist !=
|----- |----- rdp->nxttail[RCU_DONE_TAIL];
|-----......
|----rdp->nxtlist = *rdp->nxttail[RCU_DONE_TAIL];
|-----......
从rcu_do_batch的实现可以看出,首先rcu_do_batch在 RCU_SOFTIRQ的软中断是一定会被执行的,只是在入口处判定是否需要实质性地操作链表,如果 &rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL] 成立则不会继续运行,即该次软中断在rcu_do_batch中是不会执行实质性内容的(但是千万不要认为在该次软中断中,没有操作链表上的函数就没有执行关键任务,rcu_progress_gp_end, rcu_check_quiescent_state都在软中断被执行了)。
在rcu_data结构体中引入
nxtlist与 RCU_NEXT_RCU_DONE_TAIL的目的很清楚:
nxtlist保存待处理的链表头,而*nxttail[RCU_NEXT_RCU_DONE_TAIL]中还保存着下次本核结束某个grace period时需要操作
的链表的头,如果两者相等,则进入rcu_do_batch后将立即退出。
=========================================================
=========================================================
引入RCU_NEXT_TAIL
static __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
struct rcu_state *rsp)
|----......
|----*rdp->nxttail[RCU_NEXT_TAIL] = head;
|----rdp->nxttail[RCU_NEXT_TAIL] = &head->next;
|----......
作用:缓存!(单链表,存储最后可插入节点的位置)
=========================================================
=========================================================
引入RCU_NEXT_READY_TAIL和RCU_NEXT_TAIL
这两个很容易混淆。
static void __rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp)
|----......
|----rcu_check_quiescent_state(rsp, rdp);
|----......
|
|通过了quiescent state,调用rcu_report_qs_rdp
|----rcu_report_qs_rdp(rdp->cpu, rsp, rdp, rdp->passed_quiesc_completed)
|----......
|----rdp->nxttail[RCU_NEXT_READY_TAIL] =
|---- rdp->nxttail[RCU_NEXT_TAIL]
通过了rcu_check_quiecent_state()中的检查,知道该核通过了quiescent state,因此设置rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL],而RCU_NEXT_TAIL是每次添加链表的缓存地址,因此可以判定RCU_NEXT_READY_TAIL是存储该核下次通过grace period时需被调用的链表头的地址(有点不妥,见下文)(为什么是这样?虽然该核已经上报通过了quiescent state,但是该次grace period的运行结束是由最后一个通过quiescent state的所决定的,如果仍有其它核自开启该次grace period后没有通过quiescent state,那么只能返回,以后添加的的链表元数自然也就只能在下次grace period中被调用)。
不禁会问:RCU_NEXT_TAIL有什么用?
先说明:本核上rcu_data中挂接的链表元素,只有两种情况可被处理
(1)超时:
if(ULONG_CMP_LT(rsp->jiffies_force_qs), jiffies)
force_quiescent_state(rsp, );
(2)该核结束了由某个核开启的grace period:
rcu_node检测到该核是最后一个上报通过quiescent state的核.
描述个场景:A核开启了grace period,B核在系统初始化后上挂了好几个链表节点,A、C、D核先后通过了quiescent state,B核最后通过quiescent state,则B核是最终结束该grace period的核,B核最终将在rcu_do_batch()中处理链表。
问题:在于B核应该执行链表上的RCU_DONE_TAIL至RCU_NEXT_READY_TAIL的所有任务吗?
回答:不能。
原因:B核尽管在rcu_report_qs_rdp中执行了rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL],但是我们显然的看到由于该grace period并由非B核开启,因此我们无法判断在B核添加链表时其它核是否通过了quiescent state,如果其它核已经通过了quiescent state,对于此后在B核上挂接的链表,如果在该grace period被B核终止后即被调用处理显然是错的。
如何解决:引入RCU_WAIT_TAIL
B核终止了一个非本身开启的grace period,而后:
rcu_report_qs_rnp(unsigned long mask, struct rcu_state *rsp,
struct rcu_node *rnp, unsigned long flags)
|----......
|----rcu_report_qs_rsp(rsp, flags);
|----......
|----rcu_start_gp(rsp, flags);
| |----......
| |----rcu_start_gp_per_cpu(rsp, rnp, rdp);
| | |----_rcu_process_gp_end(rsp, rnp, rdp);
| | | |----......
| | | |----rdp->nxttail[RCU_DONE_TAIL] =
| | | | rdp->nxttail[RCU_WAIT_TAIL];
| | | |----rdp->nxttail[RCU_WAIT_TAIL] =
| | | | rdp->nxttail[RCU_NEXT_READY_TAIL];
| | | |----rdp->nxttail[RCU_NEXT_READY_TAIL] =
| | | | rdp->nxttail[RCU_NEXT_TAIL];
| | | |----.......
| | |----......
| |----......
|----.......
|----......
可以看出在rcu_process_per_cpu中置:rdp->nxttail[RCU_DONE_TAIL] = rdp->nxttail[RCU_WAIT_TAIL],而非rdp->nxttail[RCU_NEXT_READY_TAIL]。
个人认为,这样做可以防止——某个核终止了并非由该核开启的grace period,而且该核在grace period时间段内在自己的链表中的添加了链表元素——在该次rcu_do_batch中,这些链表元素却被处理了。
=========================================================
关注TAIL指针的重点,在于:
(1)主动开启grace period
(2)检测到有新的grace period,但是本核缺没有被动的开启grace period
(3)检测grace period是否结束,及处理
(4)向rcu_node上报本核已发生quiescent state
在这4点处将推动TAIL指针的变化。
记住一点:某个核开启了grace period,但并不一定是该核来结束grace period,可能是自己,也可能是其它核。
非抢占式RCU实现(二),解释:为什么 RCU_NEXT_SIZE 宏值是4?的更多相关文章
- 非抢占式RCU中的一些概念
该记录着重介绍下:2.6.34版本中非抢占式RCU的基本概念. RCU保护的是指针,因为指针的赋值可以使用原子操作完成: 在非抢占式RCU中: 对于读者,RCU仅需要抢占失效,因此获得读锁和释放读锁分 ...
- 非抢占式RCU实现(一)
关于RCU的实现,考虑如下情形: 1.非抢占式RCU 2.限于嵌入式系统4核.每核单线程 3.RCU_FANOUT = 32 此时,RCU_TREE退化为单节点,如下,针对rcu_sched_stat ...
- 非抢占式RCU中关于grace period的处理(限于方法)
参考自:http://blog.csdn.net/junguo/article/details/8244530 Documentation/RCU/* TREE_RCU将所有的 ...
- 抢占式内核与非抢占式内核中的自旋锁(spinlock)的差别
一.概括 (1)自旋锁适用于SMP系统,UP系统用spinlock是作死. (2)保护模式下禁止内核抢占的方法:1.运行终端服务例程时2.运行软中断和tasklet时3.设置本地CPU计数器preem ...
- chapter9_4 非抢占式的多线程
协同程序与常规的多线程不同之处:协同程序是非抢占式的. 当一个协同程序运行时,是无法从外部停止它的.只有当协同程序显式地调用yield时,它才会停止. 当不存在抢先时,编程会变得简单很多,无须为同步的 ...
- 一种基于C51单片机的非抢占式的操作系统架构
摘 要:从Keil C51的内存空间管理方式入手,着重讨论实时操作系统在任务调度时的重入问题,分析一些解决重入的基本方式与方法:分析实时操作系统任务调度的占先性,提出非占先的任务调度是能更适合于Kei ...
- keepalived的抢占与非抢占模式
目录 一:keepalived的抢占与非抢占模式 1.抢占模式 2.非抢占模式 二:接下来分4种情况说明 三:以上3种,只要级别高就会获取master,与state状态是无关的 一:keepalive ...
- Java基础——NIO(二)非阻塞式网络通信与NIO2新增类库
一.NIO非阻塞式网络通信 1.阻塞与非阻塞的概念 传统的 IO 流都是阻塞式的.也就是说,当一个线程调用 read() 或 write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在 ...
- ASM:《X86汇编语言-从实模式到保护模式》第17章:保护模式下中断和异常的处理与抢占式多任务
★PART1:中断和异常概述 1. 中断(Interrupt) 中断包括硬件中断和软中断.硬件中断是由外围设备发出的中断信号引发的,以请求处理器提供服务.当I/O接口发出中断请求的时候,会被像8259 ...
随机推荐
- Mybatis之工作原理
1.Mybatis的架构 1.1 Mybatis的框架分层 1.2 MyBatis的实现原理 mybatis底层还是采用原生jdbc来对数据库进行操作的,它支持定制化 SQL.存储过程以及高级映射的优 ...
- Laravel 5.4 Cache::put的一个小坑
使用的是Cache的file驱动,然而在\Cache::put($key,$value)时发现,并没有存入. 一开始以为是file驱动的问题,后来跟踪代码发现,居然源码里当过期时间不设置时,根本不保存 ...
- RedHat 6 yum 使用网易源
. . . . . 刚装好了 RedHat 6 系统,但是使用 yum 的时候总是提示 nothing to do,并且什么都做不了.后来经过一番搜索才知道,红帽的 yum 在线更新是收费的,而且必须 ...
- Mongodb网络好文章
http://blog.csdn.net/pi9nc/article/details/17722419 mongodb集群配置. http://blog.fens.me/mongodb-replica ...
- 使用FineReport打造考试分析系统
本系统的优点: 1.报表内容丰富:系统中包含总分分析.小分分析.作答错因分析.试卷命题分析和各类用户报告单五类报表.涵盖学校须要的各项分析数据,并提供丰富的图表,使分析数据更直观表现. 2.操作灵活简 ...
- 在虚拟机里面安装Linux操作系统
在这篇文章中以VMware14为例,Linux操作系统采用CentOS7进行讲解如何在虚拟机中安装Linux操作系统. 一.选择创建新的虚拟机 二.在选择虚拟机配置界面选择“自定义(高级)”选项,然后 ...
- Centos7.3防火墙配置
1.查看firewall服务状态 systemctl status firewalld 2.查看firewall的状态 firewall-cmd --state 3.开启.重启.关闭.firewall ...
- 解决DuplicateFileException: Duplicate files copied in APK META-INF/LICENSE(或META-INF/DEPENDENCIES)
导入eclipse项目时报 Error:Execution failed for task ':app:transformResourcesWithMergeJavaResForDebug'.> ...
- [maven] settings 文件 本地maven仓库
<?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to the Apache Soft ...
- why "Everything" is so fast?
Everything并不扫描整个磁盘,只是读取磁盘上的USN日志,所以速度飞快.但因此缺点也明显:1.只支持NTFS格式的分区,因为USN日志是NTFS专有的.在FAT.FAT32格式分区上无法使用E ...