首页 > 代码库 > linux内核的tiny rcu, tree rcu

linux内核的tiny rcu, tree rcu

kernel中有两个rcu的实现,一个是tiny rcu,另一个是tree rcu。这两种rcu的前身都是classic rcu。
如果要阅读classic rcu的实现代码,必须找kernel 2.6.26,因为在kernel 2.6.27,classic rcu开始转型为使用tree node的scalable classic rcu,是现在的tree rcu趋形。
那么tiny rcu与classic rcu又是什么关系呢,tiny如其名,就是紧凑的classic rcu,专门为单cpu(uniproceesor)的嵌入系统(内存十分有限)而设计的。换句话说,相当于classic rcu的删减版。

classic rcu使用全局状态rcu_ctrblk,提供两个flaver的全局状态rcu_sched_ctrblk和rcu_bh_ctrblk。
tiny rcu沿用这两个全局状态,并将SMP部分的内容删减。
tree rcu则是将rcu_ctrblk演进成分层(hierarchical)结构,也就是树形。全局状态rcu_state,分层(树型)节点rcu_node,cpu独立状态rcu_data,以及cpu空闲变频状态rcu_dynticks。将原本在rcu_ctrblk的cpumask,以分层的方式分置到rcu_node的qsmask。

现在tree rcu包含了许多特性,初涉者不容易在庞大的结构体成员和众多特性功能的函数逻辑中分离出,与设计文档描述相吻合的(纯净或原始的)路径进行研究。
设计文档中描述了classic rcu就是kernel 2.6.16为止的rcu实现,而tree rcu的趋形就是从kernel 2.6.17开始。如果你对现在的kernel中的rcu实现感到迷惑的话,可以选择上面提到的两个版本的kernel的rcu进行比较来研究。
或者你可以参考第一份scalable classic rcu提交的日志文档,在LWN网站。文档以git diff的方式,更好地展现了classic rcu如何向tree rcu演进。
但是你不可能很好地从tiny rcu去研究classic rcu,虽然说tiny rcu是classic rcu的精简,但是已经将SMP部分实现基本去除(比如qsmask),而tree rcu和classic rcu同是基于SMP的实现。
因此如果你将tiny rcu作为classic rcu去同tree rcu进行比较时,你会根本找不到SMP相关部分的影子,差异巨大而找不出演进的连接点(相关性),从而迷惑。

classic rcu的rcu_ctrblk中有我们熟知的rcu文档描述的qsmask,用于维护(或感知)一个gp。而tree rcu则是将这个qsmask进行分层,tiny rcu却是将这个qsmask丢弃。如果你不清楚这一点,当你比较tree rcu和tiny rcu时,中间就会有断层,联系不上。
这是因为tiny rcu限定了单CPU(uniprocessor)的条件。在tiny rcu实现中并没有任何per cpu变量。并且在cpu提交一次qs的同时,就会发起rcu softirq,换句话说,gp并没有另外进行维护管理,只是简单地将gp等同于每次qs的提交。

classic rcu和tree rcu同样都使用nxtlist和nxttail来维护4段rcu callbacks的 batch处理。而tiny rcu将其精简为rcucblist,以及donetail和curtail这样形式的2段rcu batch,并且简化当中的维护。
当使用者调用synchronize_sched或call_rcu时,同步(或者说是延后)的回调就会链到cur段。当调度器scheduler提交一次qs时,就会将cur段的回调纳入done段,并发起rcu softirq。当内核kernel处理rcu softirq就会从done段将回调batch处理。
由此我们不容易发现tiny rcu在维护gp和qs。

tiny rcu和tree rcu是classic rcu不同方向的结果,tiny rcu为uniprocessor且资源有限的嵌入场合而去简化(剦切)了classic rcu,另外tree rcu则是使classic rcu向前朝超级多cpu(在rcu文档中,a few of hundren表示数百cpu还不值一提,起码也要成千上万,当时2008年)的场合,演进更高效更稳定。
kernel 2.6.27是分水岭,classic rcu向tree rcu演进。tiny rcu和tree rcu同是2008年的产物。
在kconfig中,tree rcu是默认的rcu。如果需要preempt rcu的话,必须使用tree rcu。换句话说,tiny rcu不支持preempt rcu。

 

《scalable classic RCU implementation》kernel 2.6.27 第一份基于tree node分层的classic rcu代码提交日志文档。

《Hierarchical RCU》

《RCU: The Bloatwatch Edition》tiny rcu的设计文档。

《Simplifying RCU》kernel 3.11 移去CONFIG_PREEMPT_TINY,即移去preempt tiny rcu。

 

linux内核的tiny rcu, tree rcu