€• Œsphinx.addnodes”Œdocument”“”)�”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)�”}”(hhh]”(hŒ pending_xref”“”)�”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…”�”}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”ŒG/translations/zh_CN/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)�”}”(hhh]”hŒChinese (Traditional)”…”�”}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”ŒG/translations/zh_TW/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒItalian”…”�”}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”ŒG/translations/it_IT/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒJapanese”…”�”}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”ŒG/translations/ja_JP/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒKorean”…”�”}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”ŒG/translations/ko_KR/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒPortuguese (Brazilian)”…”�”}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”ŒG/translations/pt_BR/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒSpanish”…”�”}”hh–sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”ŒG/translations/sp_SP/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒsection”“”)�”}”(hhh]”(hŒtitle”“”)�”}”(hŒ6A Tour Through TREE_RCU's Grace-Period Memory Ordering”h]”hŒ8A Tour Through TREE_RCU’s Grace-Period Memory Ordering”…”�”}”(hh¼h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhh·h²hh³Œa/var/lib/git/docbuild/linux/Documentation/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering.rst”h´KubhŒ paragraph”“”)�”}”(hŒAugust 8, 2017”h]”hŒAugust 8, 2017”…”�”}”(hhÍh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khh·h²hubhÌ)�”}”(hŒ0This article was contributed by Paul E. McKenney”h]”hŒ0This article was contributed by Paul E. McKenney”…”�”}”(hhÛh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khh·h²hubh¶)�”}”(hhh]”(h»)�”}”(hŒ Introduction”h]”hŒ Introduction”…”�”}”(hhìh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhhéh²hh³hÊh´K ubhÌ)�”}”(hŒqThis document gives a rough visual overview of how Tree RCU's grace-period memory ordering guarantee is provided.”h]”hŒsThis document gives a rough visual overview of how Tree RCU’s grace-period memory ordering guarantee is provided.”…”�”}”(hhúh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K hhéh²hubeh}”(h]”Œ introduction”ah ]”h"]”Œ introduction”ah$]”h&]”uh1hµhh·h²hh³hÊh´K ubh¶)�”}”(hhh]”(h»)�”}”(hŒ:What Is Tree RCU's Grace Period Memory Ordering Guarantee?”h]”hŒlock``. These critical sections use helper functions for lock acquisition, including ``raw_spin_lock_rcu_node()``, ``raw_spin_lock_irq_rcu_node()``, and ``raw_spin_lock_irqsave_rcu_node()``. Their lock-release counterparts are ``raw_spin_unlock_rcu_node()``, ``raw_spin_unlock_irq_rcu_node()``, and ``raw_spin_unlock_irqrestore_rcu_node()``, respectively. For completeness, a ``raw_spin_trylock_rcu_node()`` is also provided. The key point is that the lock-acquisition functions, including ``raw_spin_trylock_rcu_node()``, all invoke ``smp_mb__after_unlock_lock()`` immediately after successful acquisition of the lock.”h]”(hŒWThe workhorse for RCU’s grace-period memory ordering is the critical section for the ”…”�”}”(hj˜h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj˜ubhŒ structure’s ”…”�”}”(hj˜h²hh³Nh´Nubj8)�”}”(hŒ ``->lock``”h]”hŒ->lock”…”�”}”(hj²h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj˜ubhŒO. These critical sections use helper functions for lock acquisition, including ”…”�”}”(hj˜h²hh³Nh´Nubj8)�”}”(hŒ``raw_spin_lock_rcu_node()``”h]”hŒraw_spin_lock_rcu_node()”…”�”}”(hjÄh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj˜ubhŒ, ”…”�”}”(hj˜h²hh³Nh´Nubj8)�”}”(hŒ ``raw_spin_lock_irq_rcu_node()``”h]”hŒraw_spin_lock_irq_rcu_node()”…”�”}”(hjÖh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj˜ubhŒ, and ”…”�”}”(hj˜h²hh³Nh´Nubj8)�”}”(hŒ$``raw_spin_lock_irqsave_rcu_node()``”h]”hŒ raw_spin_lock_irqsave_rcu_node()”…”�”}”(hjèh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj˜ubhŒ&. Their lock-release counterparts are ”…”�”}”(hj˜h²hh³Nh´Nubj8)�”}”(hŒ``raw_spin_unlock_rcu_node()``”h]”hŒraw_spin_unlock_rcu_node()”…”�”}”(hjúh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj˜ubhŒ, ”…”�”}”hj˜sbj8)�”}”(hŒ"``raw_spin_unlock_irq_rcu_node()``”h]”hŒraw_spin_unlock_irq_rcu_node()”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj˜ubhŒ, and ”…”�”}”(hj˜h²hh³Nh´Nubj8)�”}”(hŒ)``raw_spin_unlock_irqrestore_rcu_node()``”h]”hŒ%raw_spin_unlock_irqrestore_rcu_node()”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj˜ubhŒ$, respectively. For completeness, a ”…”�”}”(hj˜h²hh³Nh´Nubj8)�”}”(hŒ``raw_spin_trylock_rcu_node()``”h]”hŒraw_spin_trylock_rcu_node()”…”�”}”(hj0h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj˜ubhŒS is also provided. The key point is that the lock-acquisition functions, including ”…”�”}”(hj˜h²hh³Nh´Nubj8)�”}”(hŒ``raw_spin_trylock_rcu_node()``”h]”hŒraw_spin_trylock_rcu_node()”…”�”}”(hjBh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj˜ubhŒ , all invoke ”…”�”}”(hj˜h²hh³Nh´Nubj8)�”}”(hŒ``smp_mb__after_unlock_lock()``”h]”hŒsmp_mb__after_unlock_lock()”…”�”}”(hjTh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj˜ubhŒ6 immediately after successful acquisition of the lock.”…”�”}”(hj˜h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K1hj‡h²hubhÌ)�”}”(hX9Therefore, for any given ``rcu_node`` structure, any access happening before one of the above lock-release functions will be seen by all CPUs as happening before any access happening after a later one of the above lock-acquisition functions. Furthermore, any access happening before one of the above lock-release function on any given CPU will be seen by all CPUs as happening before any access happening after a later one of the above lock-acquisition functions executing on that same CPU, even if the lock-release and lock-acquisition functions are operating on different ``rcu_node`` structures. Tree RCU uses these two ordering guarantees to form an ordering network among all CPUs that were in any way involved in the grace period, including any CPUs that came online or went offline during the grace period in question.”h]”(hŒTherefore, for any given ”…”�”}”(hjlh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjth²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjlubhX structure, any access happening before one of the above lock-release functions will be seen by all CPUs as happening before any access happening after a later one of the above lock-acquisition functions. Furthermore, any access happening before one of the above lock-release function on any given CPU will be seen by all CPUs as happening before any access happening after a later one of the above lock-acquisition functions executing on that same CPU, even if the lock-release and lock-acquisition functions are operating on different ”…”�”}”(hjlh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj†h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjlubhŒï structures. Tree RCU uses these two ordering guarantees to form an ordering network among all CPUs that were in any way involved in the grace period, including any CPUs that came online or went offline during the grace period in question.”…”�”}”(hjlh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K>hj‡h²hubhÌ)�”}”(hŒnThe following litmus test exhibits the ordering effects of these lock-acquisition and lock-release functions::”h]”hŒmThe following litmus test exhibits the ordering effects of these lock-acquisition and lock-release functions:”…”�”}”(hjžh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KMhj‡h²hubhŒ literal_block”“”)�”}”(hXÈ 1 int x, y, z; 2 3 void task0(void) 4 { 5 raw_spin_lock_rcu_node(rnp); 6 WRITE_ONCE(x, 1); 7 r1 = READ_ONCE(y); 8 raw_spin_unlock_rcu_node(rnp); 9 } 10 11 void task1(void) 12 { 13 raw_spin_lock_rcu_node(rnp); 14 WRITE_ONCE(y, 1); 15 r2 = READ_ONCE(z); 16 raw_spin_unlock_rcu_node(rnp); 17 } 18 19 void task2(void) 20 { 21 WRITE_ONCE(z, 1); 22 smp_mb(); 23 r3 = READ_ONCE(x); 24 } 25 26 WARN_ON(r1 == 0 && r2 == 0 && r3 == 0);”h]”hXÈ 1 int x, y, z; 2 3 void task0(void) 4 { 5 raw_spin_lock_rcu_node(rnp); 6 WRITE_ONCE(x, 1); 7 r1 = READ_ONCE(y); 8 raw_spin_unlock_rcu_node(rnp); 9 } 10 11 void task1(void) 12 { 13 raw_spin_lock_rcu_node(rnp); 14 WRITE_ONCE(y, 1); 15 r2 = READ_ONCE(z); 16 raw_spin_unlock_rcu_node(rnp); 17 } 18 19 void task2(void) 20 { 21 WRITE_ONCE(z, 1); 22 smp_mb(); 23 r3 = READ_ONCE(x); 24 } 25 26 WARN_ON(r1 == 0 && r2 == 0 && r3 == 0);”…”�”}”hj®sbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1j¬h³hÊh´KPhj‡h²hubhÌ)�”}”(hXVThe ``WARN_ON()`` is evaluated at "the end of time", after all changes have propagated throughout the system. Without the ``smp_mb__after_unlock_lock()`` provided by the acquisition functions, this ``WARN_ON()`` could trigger, for example on PowerPC. The ``smp_mb__after_unlock_lock()`` invocations prevent this ``WARN_ON()`` from triggering.”h]”(hŒThe ”…”�”}”(hj¾h²hh³Nh´Nubj8)�”}”(hŒ ``WARN_ON()``”h]”hŒ WARN_ON()”…”�”}”(hjÆh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj¾ubhŒm is evaluated at “the end of timeâ€�, after all changes have propagated throughout the system. Without the ”…”�”}”(hj¾h²hh³Nh´Nubj8)�”}”(hŒ``smp_mb__after_unlock_lock()``”h]”hŒsmp_mb__after_unlock_lock()”…”�”}”(hjØh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj¾ubhŒ- provided by the acquisition functions, this ”…”�”}”(hj¾h²hh³Nh´Nubj8)�”}”(hŒ ``WARN_ON()``”h]”hŒ WARN_ON()”…”�”}”(hjêh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj¾ubhŒ, could trigger, for example on PowerPC. The ”…”�”}”(hj¾h²hh³Nh´Nubj8)�”}”(hŒ``smp_mb__after_unlock_lock()``”h]”hŒsmp_mb__after_unlock_lock()”…”�”}”(hjüh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj¾ubhŒ invocations prevent this ”…”�”}”(hj¾h²hh³Nh´Nubj8)�”}”(hŒ ``WARN_ON()``”h]”hŒ WARN_ON()”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj¾ubhŒ from triggering.”…”�”}”(hj¾h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Kkhj‡h²hubhŒtable”“”)�”}”(hhh]”hŒtgroup”“”)�”}”(hhh]”(hŒcolspec”“”)�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”KGuh1j0hj-ubhŒtbody”“”)�”}”(hhh]”(hŒrow”“”)�”}”(hhh]”hŒentry”“”)�”}”(hhh]”hÌ)�”}”(hŒ**Quick Quiz**:”h]”(hŒstrong”“”)�”}”(hŒ**Quick Quiz**”h]”hŒ Quick Quiz”…”�”}”(hjQh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jOhjKubhŒ:”…”�”}”(hjKh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KthjHubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjCubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhj>ubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hX<But the chain of rcu_node-structure lock acquisitions guarantees that new readers will see all of the updater's pre-grace-period accesses and also guarantees that the updater's post-grace-period accesses will see all of the old reader's accesses. So why do we need all of those calls to smp_mb__after_unlock_lock()?”h]”hXBBut the chain of rcu_node-structure lock acquisitions guarantees that new readers will see all of the updater’s pre-grace-period accesses and also guarantees that the updater’s post-grace-period accesses will see all of the old reader’s accesses. So why do we need all of those calls to smp_mb__after_unlock_lock()?”…”�”}”(hj{h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Kvhjxubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjuubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhj>ubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ **Answer**:”h]”(jP)�”}”(hŒ **Answer**”h]”hŒAnswer”…”�”}”(hjŸh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jOhj›ubhŒ:”…”�”}”(hj›h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K|hj˜ubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhj•ubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhj>ubjB)�”}”(hhh]”jG)�”}”(hhh]”(hÌ)�”}”(hŒ¬Because we must provide ordering for RCU's polling grace-period primitives, for example, get_state_synchronize_rcu() and poll_state_synchronize_rcu(). Consider this code::”h]”hŒ­Because we must provide ordering for RCU’s polling grace-period primitives, for example, get_state_synchronize_rcu() and poll_state_synchronize_rcu(). Consider this code:”…”�”}”(hjÉh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K~hjÆubj­)�”}”(hX,CPU 0 CPU 1 ---- ---- WRITE_ONCE(X, 1) WRITE_ONCE(Y, 1) g = get_state_synchronize_rcu() smp_mb() while (!poll_state_synchronize_rcu(g)) r1 = READ_ONCE(X) continue; r0 = READ_ONCE(Y)”h]”hX,CPU 0 CPU 1 ---- ---- WRITE_ONCE(X, 1) WRITE_ONCE(Y, 1) g = get_state_synchronize_rcu() smp_mb() while (!poll_state_synchronize_rcu(g)) r1 = READ_ONCE(X) continue; r0 = READ_ONCE(Y)”…”�”}”hj×sbah}”(h]”h ]”h"]”h$]”h&]”j¼j½uh1j¬h³hÊh´K‚hjÆubhÌ)�”}”(hŒÏRCU guarantees that the outcome r0 == 0 && r1 == 0 will not happen, even if CPU 1 is in an RCU extended quiescent state (idle or offline) and thus won't interact directly with the RCU core processing at all.”h]”hŒÑRCU guarantees that the outcome r0 == 0 && r1 == 0 will not happen, even if CPU 1 is in an RCU extended quiescent state (idle or offline) and thus won’t interact directly with the RCU core processing at all.”…”�”}”(hjåh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KŠhjÆubeh}”(h]”h ]”h"]”h$]”h&]”uh1jFhjÃubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhj>ubeh}”(h]”h ]”h"]”h$]”h&]”uh1j<hj-ubeh}”(h]”h ]”h"]”h$]”h&]”Œcols”Kuh1j+hj(ubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hj‡h²hh³hÊh´NubhÌ)�”}”(hX•This approach must be extended to include idle CPUs, which need RCU's grace-period memory ordering guarantee to extend to any RCU read-side critical sections preceding and following the current idle sojourn. This case is handled by calls to the strongly ordered ``atomic_add_return()`` read-modify-write atomic operation that is invoked within ``ct_kernel_exit_state()`` at idle-entry time and within ``ct_kernel_enter_state()`` at idle-exit time. The grace-period kthread invokes first ``ct_rcu_watching_cpu_acquire()`` (preceded by a full memory barrier) and ``rcu_watching_snap_stopped_since()`` (both of which rely on acquire semantics) to detect idle CPUs.”h]”(hXThis approach must be extended to include idle CPUs, which need RCU’s grace-period memory ordering guarantee to extend to any RCU read-side critical sections preceding and following the current idle sojourn. This case is handled by calls to the strongly ordered ”…”�”}”(hjh²hh³Nh´Nubj8)�”}”(hŒ``atomic_add_return()``”h]”hŒatomic_add_return()”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjubhŒ; read-modify-write atomic operation that is invoked within ”…”�”}”(hjh²hh³Nh´Nubj8)�”}”(hŒ``ct_kernel_exit_state()``”h]”hŒct_kernel_exit_state()”…”�”}”(hj,h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjubhŒ at idle-entry time and within ”…”�”}”(hjh²hh³Nh´Nubj8)�”}”(hŒ``ct_kernel_enter_state()``”h]”hŒct_kernel_enter_state()”…”�”}”(hj>h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjubhŒ; at idle-exit time. The grace-period kthread invokes first ”…”�”}”(hjh²hh³Nh´Nubj8)�”}”(hŒ!``ct_rcu_watching_cpu_acquire()``”h]”hŒct_rcu_watching_cpu_acquire()”…”�”}”(hjPh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjubhŒ) (preceded by a full memory barrier) and ”…”�”}”(hjh²hh³Nh´Nubj8)�”}”(hŒ%``rcu_watching_snap_stopped_since()``”h]”hŒ!rcu_watching_snap_stopped_since()”…”�”}”(hjbh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjubhŒ? (both of which rely on acquire semantics) to detect idle CPUs.”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K�hj‡h²hubj')�”}”(hhh]”j,)�”}”(hhh]”(j1)�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”KGuh1j0hj}ubj=)�”}”(hhh]”(jB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ**Quick Quiz**:”h]”(jP)�”}”(hŒ**Quick Quiz**”h]”hŒ Quick Quiz”…”�”}”(hj—h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jOhj“ubhŒ:”…”�”}”(hj“h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K�hj�ubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhj�ubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjŠubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒDBut what about CPUs that remain offline for the entire grace period?”h]”hŒDBut what about CPUs that remain offline for the entire grace period?”…”�”}”(hjÁh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KŸhj¾ubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhj»ubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjŠubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ **Answer**:”h]”(jP)�”}”(hŒ **Answer**”h]”hŒAnswer”…”�”}”(hjåh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jOhjáubhŒ:”…”�”}”(hjáh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K¡hjÞubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjÛubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjŠubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hXSuch CPUs will be offline at the beginning of the grace period, so the grace period won't expect quiescent states from them. Races between grace-period start and CPU-hotplug operations are mediated by the CPU's leaf ``rcu_node`` structure's ``->lock`` as described above.”h]”(hŒÜSuch CPUs will be offline at the beginning of the grace period, so the grace period won’t expect quiescent states from them. Races between grace-period start and CPU-hotplug operations are mediated by the CPU’s leaf ”…”�”}”(hjh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjubhŒ structure’s ”…”�”}”(hjh²hh³Nh´Nubj8)�”}”(hŒ ``->lock``”h]”hŒ->lock”…”�”}”(hj)h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjubhŒ as described above.”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K£hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhj ubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjŠubeh}”(h]”h ]”h"]”h$]”h&]”uh1j<hj}ubeh}”(h]”h ]”h"]”h$]”h&]”Œcols”Kuh1j+hjzubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hj‡h²hh³hÊh´NubhÌ)�”}”(hX�The approach must be extended to handle one final case, that of waking a task blocked in ``synchronize_rcu()``. This task might be affined to a CPU that is not yet aware that the grace period has ended, and thus might not yet be subject to the grace period's memory ordering. Therefore, there is an ``smp_mb()`` after the return from ``wait_for_completion()`` in the ``synchronize_rcu()`` code path.”h]”(hŒYThe approach must be extended to handle one final case, that of waking a task blocked in ”…”�”}”(hj`h²hh³Nh´Nubj8)�”}”(hŒ``synchronize_rcu()``”h]”hŒsynchronize_rcu()”…”�”}”(hjhh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj`ubhŒ¿. This task might be affined to a CPU that is not yet aware that the grace period has ended, and thus might not yet be subject to the grace period’s memory ordering. Therefore, there is an ”…”�”}”(hj`h²hh³Nh´Nubj8)�”}”(hŒ ``smp_mb()``”h]”hŒsmp_mb()”…”�”}”(hjzh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj`ubhŒ after the return from ”…”�”}”(hj`h²hh³Nh´Nubj8)�”}”(hŒ``wait_for_completion()``”h]”hŒwait_for_completion()”…”�”}”(hjŒh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj`ubhŒ in the ”…”�”}”(hj`h²hh³Nh´Nubj8)�”}”(hŒ``synchronize_rcu()``”h]”hŒsynchronize_rcu()”…”�”}”(hjžh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj`ubhŒ code path.”…”�”}”(hj`h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Kªhj‡h²hubj')�”}”(hhh]”j,)�”}”(hhh]”(j1)�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”KGuh1j0hj¹ubj=)�”}”(hhh]”(jB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ**Quick Quiz**:”h]”(jP)�”}”(hŒ**Quick Quiz**”h]”hŒ Quick Quiz”…”�”}”(hjÓh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jOhjÏubhŒ:”…”�”}”(hjÏh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K²hjÌubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjÉubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjÆubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ^What? Where??? I don't see any ``smp_mb()`` after the return from ``wait_for_completion()``!!!”h]”(hŒ!What? Where??? I don’t see any ”…”�”}”(hjýh²hh³Nh´Nubj8)�”}”(hŒ ``smp_mb()``”h]”hŒsmp_mb()”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjýubhŒ after the return from ”…”�”}”(hjýh²hh³Nh´Nubj8)�”}”(hŒ``wait_for_completion()``”h]”hŒwait_for_completion()”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjýubhŒ!!!”…”�”}”(hjýh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K´hjúubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhj÷ubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjÆubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ **Answer**:”h]”(jP)�”}”(hŒ **Answer**”h]”hŒAnswer”…”�”}”(hjEh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jOhjAubhŒ:”…”�”}”(hjAh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K·hj>ubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhj;ubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjÆubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hXpThat would be because I spotted the need for that ``smp_mb()`` during the creation of this documentation, and it is therefore unlikely to hit mainline before v4.14. Kudos to Lance Roy, Will Deacon, Peter Zijlstra, and Jonathan Cameron for asking questions that sensitized me to the rather elaborate sequence of events that demonstrate the need for this memory barrier.”h]”(hŒ2That would be because I spotted the need for that ”…”�”}”(hjoh²hh³Nh´Nubj8)�”}”(hŒ ``smp_mb()``”h]”hŒsmp_mb()”…”�”}”(hjwh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjoubhX2 during the creation of this documentation, and it is therefore unlikely to hit mainline before v4.14. Kudos to Lance Roy, Will Deacon, Peter Zijlstra, and Jonathan Cameron for asking questions that sensitized me to the rather elaborate sequence of events that demonstrate the need for this memory barrier.”…”�”}”(hjoh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K¹hjlubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjiubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjÆubeh}”(h]”h ]”h"]”h$]”h&]”uh1j<hj¹ubeh}”(h]”h ]”h"]”h$]”h&]”Œcols”Kuh1j+hj¶ubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hj‡h²hh³hÊh´NubhÌ)�”}”(hX—Tree RCU's grace--period memory-ordering guarantees rely most heavily on the ``rcu_node`` structure's ``->lock`` field, so much so that it is necessary to abbreviate this pattern in the diagrams in the next section. For example, consider the ``rcu_prepare_for_idle()`` function shown below, which is one of several functions that enforce ordering of newly arrived RCU callbacks against future grace periods:”h]”(hŒOTree RCU’s grace--period memory-ordering guarantees rely most heavily on the ”…”�”}”(hj®h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj¶h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj®ubhŒ structure’s ”…”�”}”(hj®h²hh³Nh´Nubj8)�”}”(hŒ ``->lock``”h]”hŒ->lock”…”�”}”(hjÈh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj®ubhŒ‚ field, so much so that it is necessary to abbreviate this pattern in the diagrams in the next section. For example, consider the ”…”�”}”(hj®h²hh³Nh´Nubj8)�”}”(hŒ``rcu_prepare_for_idle()``”h]”hŒrcu_prepare_for_idle()”…”�”}”(hjÚh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj®ubhŒ‹ function shown below, which is one of several functions that enforce ordering of newly arrived RCU callbacks against future grace periods:”…”�”}”(hj®h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KÁhj‡h²hubj­)�”}”(hXj 1 static void rcu_prepare_for_idle(void) 2 { 3 bool needwake; 4 struct rcu_data *rdp = this_cpu_ptr(&rcu_data); 5 struct rcu_node *rnp; 6 int tne; 7 8 lockdep_assert_irqs_disabled(); 9 if (rcu_rdp_is_offloaded(rdp)) 10 return; 11 12 /* Handle nohz enablement switches conservatively. */ 13 tne = READ_ONCE(tick_nohz_active); 14 if (tne != rdp->tick_nohz_enabled_snap) { 15 if (!rcu_segcblist_empty(&rdp->cblist)) 16 invoke_rcu_core(); /* force nohz to see update. */ 17 rdp->tick_nohz_enabled_snap = tne; 18 return; 19 } 20 if (!tne) 21 return; 22 23 /* 24 * If we have not yet accelerated this jiffy, accelerate all 25 * callbacks on this CPU. 26 */ 27 if (rdp->last_accelerate == jiffies) 28 return; 29 rdp->last_accelerate = jiffies; 30 if (rcu_segcblist_pend_cbs(&rdp->cblist)) { 31 rnp = rdp->mynode; 32 raw_spin_lock_rcu_node(rnp); /* irqs already disabled. */ 33 needwake = rcu_accelerate_cbs(rnp, rdp); 34 raw_spin_unlock_rcu_node(rnp); /* irqs remain disabled. */ 35 if (needwake) 36 rcu_gp_kthread_wake(); 37 } 38 }”h]”hXj 1 static void rcu_prepare_for_idle(void) 2 { 3 bool needwake; 4 struct rcu_data *rdp = this_cpu_ptr(&rcu_data); 5 struct rcu_node *rnp; 6 int tne; 7 8 lockdep_assert_irqs_disabled(); 9 if (rcu_rdp_is_offloaded(rdp)) 10 return; 11 12 /* Handle nohz enablement switches conservatively. */ 13 tne = READ_ONCE(tick_nohz_active); 14 if (tne != rdp->tick_nohz_enabled_snap) { 15 if (!rcu_segcblist_empty(&rdp->cblist)) 16 invoke_rcu_core(); /* force nohz to see update. */ 17 rdp->tick_nohz_enabled_snap = tne; 18 return; 19 } 20 if (!tne) 21 return; 22 23 /* 24 * If we have not yet accelerated this jiffy, accelerate all 25 * callbacks on this CPU. 26 */ 27 if (rdp->last_accelerate == jiffies) 28 return; 29 rdp->last_accelerate = jiffies; 30 if (rcu_segcblist_pend_cbs(&rdp->cblist)) { 31 rnp = rdp->mynode; 32 raw_spin_lock_rcu_node(rnp); /* irqs already disabled. */ 33 needwake = rcu_accelerate_cbs(rnp, rdp); 34 raw_spin_unlock_rcu_node(rnp); /* irqs remain disabled. */ 35 if (needwake) 36 rcu_gp_kthread_wake(); 37 } 38 }”…”�”}”hjòsbah}”(h]”h ]”h"]”h$]”h&]”j¼j½uh1j¬h³hÊh´KÊhj‡h²hubhÌ)�”}”(hŒ¢But the only part of ``rcu_prepare_for_idle()`` that really matters for this discussion are lines 32–34. We will therefore abbreviate this function as follows:”h]”(hŒBut the only part of ”…”�”}”(hjh²hh³Nh´Nubj8)�”}”(hŒ``rcu_prepare_for_idle()``”h]”hŒrcu_prepare_for_idle()”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjubhŒs that really matters for this discussion are lines 32–34. We will therefore abbreviate this function as follows:”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Kñhj‡h²hubŒkfigure”Œ kernel_figure”“”)�”}”(hhh]”hŒfigure”“”)�”}”(hhh]”hŒimage”“”)�”}”(hŒ%.. kernel-figure:: rcu_node-lock.svg ”h]”h}”(h]”h ]”h"]”h$]”h&]”Œuri”Œ,RCU/Design/Memory-Ordering/rcu_node-lock.svg”Œ candidates”}”Œ*”j8suh1j+hj(h³hÊh´Kubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hj#ubah}”(h]”h ]”h"]”h$]”h&]”uh1j!hj‡h²hh³hÊh´KöubhÌ)�”}”(hŒ¥The box represents the ``rcu_node`` structure's ``->lock`` critical section, with the double line on top representing the additional ``smp_mb__after_unlock_lock()``.”h]”(hŒThe box represents the ”…”�”}”(hjHh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjPh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjHubhŒ structure’s ”…”�”}”(hjHh²hh³Nh´Nubj8)�”}”(hŒ ``->lock``”h]”hŒ->lock”…”�”}”(hjbh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjHubhŒK critical section, with the double line on top representing the additional ”…”�”}”(hjHh²hh³Nh´Nubj8)�”}”(hŒ``smp_mb__after_unlock_lock()``”h]”hŒsmp_mb__after_unlock_lock()”…”�”}”(hjth²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjHubhŒ.”…”�”}”(hjHh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K÷hj‡h²hubh¶)�”}”(hhh]”(h»)�”}”(hŒ0Tree RCU Grace Period Memory Ordering Components”h]”hŒ0Tree RCU Grace Period Memory Ordering Components”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjŒh²hh³hÊh´KüubhÌ)�”}”(hŒ\Tree RCU's grace-period memory-ordering guarantee is provided by a number of RCU components:”h]”hŒ^Tree RCU’s grace-period memory-ordering guarantee is provided by a number of RCU components:”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KþhjŒh²hubhŒenumerated_list”“”)�”}”(hhh]”(hŒ list_item”“”)�”}”(hŒ`Callback Registry`_”h]”hÌ)�”}”(hj´h]”hŒ reference”“”)�”}”(hj´h]”hŒCallback Registry”…”�”}”(hj»h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œname”ŒCallback Registry”Œrefid”Œcallback-registry”uh1j¹hj¶Œresolved”Kubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Mhj²ubah}”(h]”h ]”h"]”h$]”h&]”uh1j°hj­h²hh³hÊh´Nubj±)�”}”(hŒ`Grace-Period Initialization`_”h]”hÌ)�”}”(hjÛh]”jº)�”}”(hjÛh]”hŒGrace-Period Initialization”…”�”}”(hjàh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œname”ŒGrace-Period Initialization”jÊŒgrace-period-initialization”uh1j¹hjÝjÌKubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MhjÙubah}”(h]”h ]”h"]”h$]”h&]”uh1j°hj­h²hh³hÊh´Nubj±)�”}”(hŒ!`Self-Reported Quiescent States`_”h]”hÌ)�”}”(hjþh]”jº)�”}”(hjþh]”hŒSelf-Reported Quiescent States”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œname”ŒSelf-Reported Quiescent States”jÊŒself-reported-quiescent-states”uh1j¹hjjÌKubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Mhjüubah}”(h]”h ]”h"]”h$]”h&]”uh1j°hj­h²hh³hÊh´Nubj±)�”}”(hŒ`Dynamic Tick Interface`_”h]”hÌ)�”}”(hj!h]”jº)�”}”(hj!h]”hŒDynamic Tick Interface”…”�”}”(hj&h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œname”ŒDynamic Tick Interface”jÊŒdynamic-tick-interface”uh1j¹hj#jÌKubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Mhjubah}”(h]”h ]”h"]”h$]”h&]”uh1j°hj­h²hh³hÊh´Nubj±)�”}”(hŒ`CPU-Hotplug Interface`_”h]”hÌ)�”}”(hjDh]”jº)�”}”(hjDh]”hŒCPU-Hotplug Interface”…”�”}”(hjIh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œname”ŒCPU-Hotplug Interface”jÊŒcpu-hotplug-interface”uh1j¹hjFjÌKubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MhjBubah}”(h]”h ]”h"]”h$]”h&]”uh1j°hj­h²hh³hÊh´Nubj±)�”}”(hŒ`Forcing Quiescent States`_”h]”hÌ)�”}”(hjgh]”jº)�”}”(hjgh]”hŒForcing Quiescent States”…”�”}”(hjlh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œname”ŒForcing Quiescent States”jÊŒforcing-quiescent-states”uh1j¹hjijÌKubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Mhjeubah}”(h]”h ]”h"]”h$]”h&]”uh1j°hj­h²hh³hÊh´Nubj±)�”}”(hŒ`Grace-Period Cleanup`_”h]”hÌ)�”}”(hjŠh]”jº)�”}”(hjŠh]”hŒGrace-Period Cleanup”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œname”ŒGrace-Period Cleanup”jÊŒgrace-period-cleanup”uh1j¹hjŒjÌKubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Mhjˆubah}”(h]”h ]”h"]”h$]”h&]”uh1j°hj­h²hh³hÊh´Nubj±)�”}”(hŒ`Callback Invocation`_ ”h]”hÌ)�”}”(hŒ`Callback Invocation`_”h]”jº)�”}”(hj±h]”hŒCallback Invocation”…”�”}”(hj³h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œname”ŒCallback Invocation”jÊŒcallback-invocation”uh1j¹hj¯jÌKubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Mhj«ubah}”(h]”h ]”h"]”h$]”h&]”uh1j°hj­h²hh³hÊh´Nubeh}”(h]”h ]”h"]”h$]”h&]”Œenumtype”Œarabic”Œprefix”hŒsuffix”Œ.”uh1j«hjŒh²hh³hÊh´MubhÌ)�”}”(hŒMEach of the following section looks at the corresponding component in detail.”h]”hŒMEach of the following section looks at the corresponding component in detail.”…”�”}”(hjÚh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M hjŒh²hubh¶)�”}”(hhh]”(h»)�”}”(hŒCallback Registry”h]”hŒCallback Registry”…”�”}”(hjëh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjèh²hh³hÊh´MubhÌ)�”}”(hXIf RCU's grace-period guarantee is to mean anything at all, any access that happens before a given invocation of ``call_rcu()`` must also happen before the corresponding grace period. The implementation of this portion of RCU's grace period guarantee is shown in the following figure:”h]”(hŒsIf RCU’s grace-period guarantee is to mean anything at all, any access that happens before a given invocation of ”…”�”}”(hjùh²hh³Nh´Nubj8)�”}”(hŒ``call_rcu()``”h]”hŒ call_rcu()”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjùubhŒŸ must also happen before the corresponding grace period. The implementation of this portion of RCU’s grace period guarantee is shown in the following figure:”…”�”}”(hjùh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Mhjèh²hubj")�”}”(hhh]”j')�”}”(hhh]”j,)�”}”(hŒ1.. kernel-figure:: TreeRCU-callback-registry.svg ”h]”h}”(h]”h ]”h"]”h$]”h&]”Œuri”Œ8RCU/Design/Memory-Ordering/TreeRCU-callback-registry.svg”j9}”j;j* suh1j+hj h³hÊh´Kubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1j!hjèh²hh³hÊh´MubhÌ)�”}”(hX¯Because ``call_rcu()`` normally acts only on CPU-local state, it provides no ordering guarantees, either for itself or for phase one of the update (which again will usually be removal of an element from an RCU-protected data structure). It simply enqueues the ``rcu_head`` structure on a per-CPU list, which cannot become associated with a grace period until a later call to ``rcu_accelerate_cbs()``, as shown in the diagram above.”h]”(hŒBecause ”…”�”}”(hj8 h²hh³Nh´Nubj8)�”}”(hŒ``call_rcu()``”h]”hŒ call_rcu()”…”�”}”(hj@ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj8 ubhŒî normally acts only on CPU-local state, it provides no ordering guarantees, either for itself or for phase one of the update (which again will usually be removal of an element from an RCU-protected data structure). It simply enqueues the ”…”�”}”(hj8 h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_head``”h]”hŒrcu_head”…”�”}”(hjR h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj8 ubhŒg structure on a per-CPU list, which cannot become associated with a grace period until a later call to ”…”�”}”(hj8 h²hh³Nh´Nubj8)�”}”(hŒ``rcu_accelerate_cbs()``”h]”hŒrcu_accelerate_cbs()”…”�”}”(hjd h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj8 ubhŒ , as shown in the diagram above.”…”�”}”(hj8 h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Mhjèh²hubhÌ)�”}”(hXûOne set of code paths shown on the left invokes ``rcu_accelerate_cbs()`` via ``note_gp_changes()``, either directly from ``call_rcu()`` (if the current CPU is inundated with queued ``rcu_head`` structures) or more likely from an ``RCU_SOFTIRQ`` handler. Another code path in the middle is taken only in kernels built with ``CONFIG_RCU_FAST_NO_HZ=y``, which invokes ``rcu_accelerate_cbs()`` via ``rcu_prepare_for_idle()``. The final code path on the right is taken only in kernels built with ``CONFIG_HOTPLUG_CPU=y``, which invokes ``rcu_accelerate_cbs()`` via ``rcu_advance_cbs()``, ``rcu_migrate_callbacks``, ``rcutree_migrate_callbacks()``, and ``takedown_cpu()``, which in turn is invoked on a surviving CPU after the outgoing CPU has been completely offlined.”h]”(hŒ0One set of code paths shown on the left invokes ”…”�”}”(hj| h²hh³Nh´Nubj8)�”}”(hŒ``rcu_accelerate_cbs()``”h]”hŒrcu_accelerate_cbs()”…”�”}”(hj„ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj| ubhŒ via ”…”�”}”(hj| h²hh³Nh´Nubj8)�”}”(hŒ``note_gp_changes()``”h]”hŒnote_gp_changes()”…”�”}”(hj– h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj| ubhŒ, either directly from ”…”�”}”(hj| h²hh³Nh´Nubj8)�”}”(hŒ``call_rcu()``”h]”hŒ call_rcu()”…”�”}”(hj¨ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj| ubhŒ. (if the current CPU is inundated with queued ”…”�”}”(hj| h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_head``”h]”hŒrcu_head”…”�”}”(hjº h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj| ubhŒ$ structures) or more likely from an ”…”�”}”(hj| h²hh³Nh´Nubj8)�”}”(hŒ``RCU_SOFTIRQ``”h]”hŒ RCU_SOFTIRQ”…”�”}”(hjÌ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj| ubhŒN handler. Another code path in the middle is taken only in kernels built with ”…”�”}”(hj| h²hh³Nh´Nubj8)�”}”(hŒ``CONFIG_RCU_FAST_NO_HZ=y``”h]”hŒCONFIG_RCU_FAST_NO_HZ=y”…”�”}”(hjÞ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj| ubhŒ, which invokes ”…”�”}”(hj| h²hh³Nh´Nubj8)�”}”(hŒ``rcu_accelerate_cbs()``”h]”hŒrcu_accelerate_cbs()”…”�”}”(hjð h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj| ubhŒ via ”…”�”}”(hj| h²hh³Nh´Nubj8)�”}”(hŒ``rcu_prepare_for_idle()``”h]”hŒrcu_prepare_for_idle()”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj| ubhŒG. The final code path on the right is taken only in kernels built with ”…”�”}”(hj| h²hh³Nh´Nubj8)�”}”(hŒ``CONFIG_HOTPLUG_CPU=y``”h]”hŒCONFIG_HOTPLUG_CPU=y”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj| ubhŒ, which invokes ”…”�”}”(hj| h²hh³Nh´Nubj8)�”}”(hŒ``rcu_accelerate_cbs()``”h]”hŒrcu_accelerate_cbs()”…”�”}”(hj& h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj| ubhŒ via ”…”�”}”(hj| h²hh³Nh´Nubj8)�”}”(hŒ``rcu_advance_cbs()``”h]”hŒrcu_advance_cbs()”…”�”}”(hj8 h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj| ubhŒ, ”…”�”}”(hj| h²hh³Nh´Nubj8)�”}”(hŒ``rcu_migrate_callbacks``”h]”hŒrcu_migrate_callbacks”…”�”}”(hjJ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj| ubhŒ, ”…”�”}”(hj| h²hh³Nh´Nubj8)�”}”(hŒ``rcutree_migrate_callbacks()``”h]”hŒrcutree_migrate_callbacks()”…”�”}”(hj\ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj| ubhŒ, and ”…”�”}”(hj| h²hh³Nh´Nubj8)�”}”(hŒ``takedown_cpu()``”h]”hŒtakedown_cpu()”…”�”}”(hjn h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj| ubhŒb, which in turn is invoked on a surviving CPU after the outgoing CPU has been completely offlined.”…”�”}”(hj| h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M hjèh²hubhÌ)�”}”(hXDThere are a few other code paths within grace-period processing that opportunistically invoke ``rcu_accelerate_cbs()``. However, either way, all of the CPU's recently queued ``rcu_head`` structures are associated with a future grace-period number under the protection of the CPU's lead ``rcu_node`` structure's ``->lock``. In all cases, there is full ordering against any prior critical section for that same ``rcu_node`` structure's ``->lock``, and also full ordering against any of the current task's or CPU's prior critical sections for any ``rcu_node`` structure's ``->lock``.”h]”(hŒ^There are a few other code paths within grace-period processing that opportunistically invoke ”…”�”}”(hj† h²hh³Nh´Nubj8)�”}”(hŒ``rcu_accelerate_cbs()``”h]”hŒrcu_accelerate_cbs()”…”�”}”(hjŽ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj† ubhŒ:. However, either way, all of the CPU’s recently queued ”…”�”}”(hj† h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_head``”h]”hŒrcu_head”…”�”}”(hj  h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj† ubhŒf structures are associated with a future grace-period number under the protection of the CPU’s lead ”…”�”}”(hj† h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj² h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj† ubhŒ structure’s ”…”�”}”(hj† h²hh³Nh´Nubj8)�”}”(hŒ ``->lock``”h]”hŒ->lock”…”�”}”(hjÄ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj† ubhŒX. In all cases, there is full ordering against any prior critical section for that same ”…”�”}”(hj† h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjÖ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj† ubhŒ structure’s ”…”�”}”(hj† h²hh³Nh´Nubj8)�”}”(hŒ ``->lock``”h]”hŒ->lock”…”�”}”(hjè h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj† ubhŒh, and also full ordering against any of the current task’s or CPU’s prior critical sections for any ”…”�”}”(hj† h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjú h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj† ubhŒ structure’s ”…”�”}”(hj† h²hh³Nh´Nubj8)�”}”(hŒ ``->lock``”h]”hŒ->lock”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj† ubhŒ.”…”�”}”(hj† h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M-hjèh²hubhÌ)�”}”(hŒÎThe next section will show how this ordering ensures that any accesses prior to the ``call_rcu()`` (particularly including phase one of the update) happen before the start of the corresponding grace period.”h]”(hŒTThe next section will show how this ordering ensures that any accesses prior to the ”…”�”}”(hj$ h²hh³Nh´Nubj8)�”}”(hŒ``call_rcu()``”h]”hŒ call_rcu()”…”�”}”(hj, h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj$ ubhŒl (particularly including phase one of the update) happen before the start of the corresponding grace period.”…”�”}”(hj$ h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M7hjèh²hubj')�”}”(hhh]”j,)�”}”(hhh]”(j1)�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”KGuh1j0hjG ubj=)�”}”(hhh]”(jB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ**Quick Quiz**:”h]”(jP)�”}”(hŒ**Quick Quiz**”h]”hŒ Quick Quiz”…”�”}”(hja h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jOhj] ubhŒ:”…”�”}”(hj] h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M<hjZ ubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjW ubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjT ubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ%But what about ``synchronize_rcu()``?”h]”(hŒBut what about ”…”�”}”(hj‹ h²hh³Nh´Nubj8)�”}”(hŒ``synchronize_rcu()``”h]”hŒsynchronize_rcu()”…”�”}”(hj“ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj‹ ubhŒ?”…”�”}”(hj‹ h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M>hjˆ ubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhj… ubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjT ubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ **Answer**:”h]”(jP)�”}”(hŒ **Answer**”h]”hŒAnswer”…”�”}”(hjÁ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jOhj½ ubhŒ:”…”�”}”(hj½ h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M@hjº ubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhj· ubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjT ubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ’The ``synchronize_rcu()`` passes ``call_rcu()`` to ``wait_rcu_gp()``, which invokes it. So either way, it eventually comes down to ``call_rcu()``.”h]”(hŒThe ”…”�”}”(hjë h²hh³Nh´Nubj8)�”}”(hŒ``synchronize_rcu()``”h]”hŒsynchronize_rcu()”…”�”}”(hjó h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjë ubhŒ passes ”…”�”}”(hjë h²hh³Nh´Nubj8)�”}”(hŒ``call_rcu()``”h]”hŒ call_rcu()”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjë ubhŒ to ”…”�”}”(hjë h²hh³Nh´Nubj8)�”}”(hŒ``wait_rcu_gp()``”h]”hŒ wait_rcu_gp()”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjë ubhŒ?, which invokes it. So either way, it eventually comes down to ”…”�”}”(hjë h²hh³Nh´Nubj8)�”}”(hŒ``call_rcu()``”h]”hŒ call_rcu()”…”�”}”(hj) h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjë ubhŒ.”…”�”}”(hjë h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MBhjè ubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjå ubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjT ubeh}”(h]”h ]”h"]”h$]”h&]”uh1j<hjG ubeh}”(h]”h ]”h"]”h$]”h&]”Œcols”Kuh1j+hjD ubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hjèh²hh³hÊh´Nubeh}”(h]”jËah ]”h"]”Œcallback registry”ah$]”h&]”uh1hµhjŒh²hh³hÊh´MŒ referenced”Kubh¶)�”}”(hhh]”(h»)�”}”(hŒGrace-Period Initialization”h]”hŒGrace-Period Initialization”…”�”}”(hjk h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjh h²hh³hÊh´MHubhÌ)�”}”(hXrGrace-period initialization is carried out by the grace-period kernel thread, which makes several passes over the ``rcu_node`` tree within the ``rcu_gp_init()`` function. This means that showing the full flow of ordering through the grace-period computation will require duplicating this tree. If you find this confusing, please note that the state of the ``rcu_node`` changes over time, just like Heraclitus's river. However, to keep the ``rcu_node`` river tractable, the grace-period kernel thread's traversals are presented in multiple parts, starting in this section with the various phases of grace-period initialization.”h]”(hŒrGrace-period initialization is carried out by the grace-period kernel thread, which makes several passes over the ”…”�”}”(hjy h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj� h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjy ubhŒ tree within the ”…”�”}”(hjy h²hh³Nh´Nubj8)�”}”(hŒ``rcu_gp_init()``”h]”hŒ rcu_gp_init()”…”�”}”(hj“ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjy ubhŒÄ function. This means that showing the full flow of ordering through the grace-period computation will require duplicating this tree. If you find this confusing, please note that the state of the ”…”�”}”(hjy h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj¥ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjy ubhŒI changes over time, just like Heraclitus’s river. However, to keep the ”…”�”}”(hjy h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj· h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjy ubhŒ± river tractable, the grace-period kernel thread’s traversals are presented in multiple parts, starting in this section with the various phases of grace-period initialization.”…”�”}”(hjy h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MJhjh h²hubhÌ)�”}”(hŒ£The first ordering-related grace-period initialization action is to advance the ``rcu_state`` structure's ``->gp_seq`` grace-period-number counter, as shown below:”h]”(hŒPThe first ordering-related grace-period initialization action is to advance the ”…”�”}”(hjÏ h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_state``”h]”hŒ rcu_state”…”�”}”(hj× h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÏ ubhŒ structure’s ”…”�”}”(hjÏ h²hh³Nh´Nubj8)�”}”(hŒ ``->gp_seq``”h]”hŒ->gp_seq”…”�”}”(hjé h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÏ ubhŒ- grace-period-number counter, as shown below:”…”�”}”(hjÏ h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MThjh h²hubj")�”}”(hhh]”j')�”}”(hhh]”j,)�”}”(hŒ).. kernel-figure:: TreeRCU-gp-init-1.svg ”h]”h}”(h]”h ]”h"]”h$]”h&]”Œuri”Œ0RCU/Design/Memory-Ordering/TreeRCU-gp-init-1.svg”j9}”j;j suh1j+hj h³hÊh´Kubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1j!hjh h²hh³hÊh´MYubhÌ)�”}”(hŒ¸The actual increment is carried out using ``smp_store_release()``, which helps reject false-positive RCU CPU stall detection. Note that only the root ``rcu_node`` structure is touched.”h]”(hŒ*The actual increment is carried out using ”…”�”}”(hj h²hh³Nh´Nubj8)�”}”(hŒ``smp_store_release()``”h]”hŒsmp_store_release()”…”�”}”(hj( h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj ubhŒU, which helps reject false-positive RCU CPU stall detection. Note that only the root ”…”�”}”(hj h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj: h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj ubhŒ structure is touched.”…”�”}”(hj h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MZhjh h²hubhÌ)�”}”(hXÝThe first pass through the ``rcu_node`` tree updates bitmasks based on CPUs having come online or gone offline since the start of the previous grace period. In the common case where the number of online CPUs for this ``rcu_node`` structure has not transitioned to or from zero, this pass will scan only the leaf ``rcu_node`` structures. However, if the number of online CPUs for a given leaf ``rcu_node`` structure has transitioned from zero, ``rcu_init_new_rnp()`` will be invoked for the first incoming CPU. Similarly, if the number of online CPUs for a given leaf ``rcu_node`` structure has transitioned to zero, ``rcu_cleanup_dead_rnp()`` will be invoked for the last outgoing CPU. The diagram below shows the path of ordering if the leftmost ``rcu_node`` structure onlines its first CPU and if the next ``rcu_node`` structure has no online CPUs (or, alternatively if the leftmost ``rcu_node`` structure offlines its last CPU and if the next ``rcu_node`` structure has no online CPUs).”h]”(hŒThe first pass through the ”…”�”}”(hjR h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjZ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjR ubhŒ² tree updates bitmasks based on CPUs having come online or gone offline since the start of the previous grace period. In the common case where the number of online CPUs for this ”…”�”}”(hjR h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjl h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjR ubhŒS structure has not transitioned to or from zero, this pass will scan only the leaf ”…”�”}”(hjR h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj~ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjR ubhŒD structures. However, if the number of online CPUs for a given leaf ”…”�”}”(hjR h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj� h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjR ubhŒ' structure has transitioned from zero, ”…”�”}”(hjR h²hh³Nh´Nubj8)�”}”(hŒ``rcu_init_new_rnp()``”h]”hŒrcu_init_new_rnp()”…”�”}”(hj¢ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjR ubhŒf will be invoked for the first incoming CPU. Similarly, if the number of online CPUs for a given leaf ”…”�”}”(hjR h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj´ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjR ubhŒ% structure has transitioned to zero, ”…”�”}”(hjR h²hh³Nh´Nubj8)�”}”(hŒ``rcu_cleanup_dead_rnp()``”h]”hŒrcu_cleanup_dead_rnp()”…”�”}”(hjÆ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjR ubhŒi will be invoked for the last outgoing CPU. The diagram below shows the path of ordering if the leftmost ”…”�”}”(hjR h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjØ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjR ubhŒ1 structure onlines its first CPU and if the next ”…”�”}”(hjR h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjê h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjR ubhŒA structure has no online CPUs (or, alternatively if the leftmost ”…”�”}”(hjR h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjü h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjR ubhŒ1 structure offlines its last CPU and if the next ”…”�”}”(hjR h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjR ubhŒ structure has no online CPUs).”…”�”}”(hjR h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M^hjh h²hubj")�”}”(hhh]”j')�”}”(hhh]”j,)�”}”(hŒ).. kernel-figure:: TreeRCU-gp-init-2.svg ”h]”h}”(h]”h ]”h"]”h$]”h&]”Œuri”Œ0RCU/Design/Memory-Ordering/TreeRCU-gp-init-2.svg”j9}”j;j7suh1j+hj)h³hÊh´Kubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hj&ubah}”(h]”h ]”h"]”h$]”h&]”uh1j!hjh h²hh³hÊh´MoubhÌ)�”}”(hŒñThe final ``rcu_gp_init()`` pass through the ``rcu_node`` tree traverses breadth-first, setting each ``rcu_node`` structure's ``->gp_seq`` field to the newly advanced value from the ``rcu_state`` structure, as shown in the following diagram.”h]”(hŒ The final ”…”�”}”(hjEh²hh³Nh´Nubj8)�”}”(hŒ``rcu_gp_init()``”h]”hŒ rcu_gp_init()”…”�”}”(hjMh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjEubhŒ pass through the ”…”�”}”(hjEh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj_h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjEubhŒ, tree traverses breadth-first, setting each ”…”�”}”(hjEh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjqh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjEubhŒ structure’s ”…”�”}”(hjEh²hh³Nh´Nubj8)�”}”(hŒ ``->gp_seq``”h]”hŒ->gp_seq”…”�”}”(hjƒh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjEubhŒ, field to the newly advanced value from the ”…”�”}”(hjEh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_state``”h]”hŒ rcu_state”…”�”}”(hj•h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjEubhŒ. structure, as shown in the following diagram.”…”�”}”(hjEh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Mphjh h²hubj")�”}”(hhh]”j')�”}”(hhh]”j,)�”}”(hŒ).. kernel-figure:: TreeRCU-gp-init-3.svg ”h]”h}”(h]”h ]”h"]”h$]”h&]”Œuri”Œ0RCU/Design/Memory-Ordering/TreeRCU-gp-init-3.svg”j9}”j;j¾suh1j+hj°h³hÊh´Kubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hj­ubah}”(h]”h ]”h"]”h$]”h&]”uh1j!hjh h²hh³hÊh´MvubhÌ)�”}”(hXåThis change will also cause each CPU's next call to ``__note_gp_changes()`` to notice that a new grace period has started, as described in the next section. But because the grace-period kthread started the grace period at the root (with the advancing of the ``rcu_state`` structure's ``->gp_seq`` field) before setting each leaf ``rcu_node`` structure's ``->gp_seq`` field, each CPU's observation of the start of the grace period will happen after the actual start of the grace period.”h]”(hŒ6This change will also cause each CPU’s next call to ”…”�”}”(hjÌh²hh³Nh´Nubj8)�”}”(hŒ``__note_gp_changes()``”h]”hŒ__note_gp_changes()”…”�”}”(hjÔh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÌubhŒ· to notice that a new grace period has started, as described in the next section. But because the grace-period kthread started the grace period at the root (with the advancing of the ”…”�”}”(hjÌh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_state``”h]”hŒ rcu_state”…”�”}”(hjæh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÌubhŒ structure’s ”…”�”}”(hjÌh²hh³Nh´Nubj8)�”}”(hŒ ``->gp_seq``”h]”hŒ->gp_seq”…”�”}”(hjøh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÌubhŒ! field) before setting each leaf ”…”�”}”(hjÌh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÌubhŒ structure’s ”…”�”}”(hjÌh²hh³Nh´Nubj8)�”}”(hŒ ``->gp_seq``”h]”hŒ->gp_seq”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÌubhŒy field, each CPU’s observation of the start of the grace period will happen after the actual start of the grace period.”…”�”}”(hjÌh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Mwhjh h²hubj')�”}”(hhh]”j,)�”}”(hhh]”(j1)�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”KGuh1j0hj7ubj=)�”}”(hhh]”(jB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ**Quick Quiz**:”h]”(jP)�”}”(hŒ**Quick Quiz**”h]”hŒ Quick Quiz”…”�”}”(hjQh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jOhjMubhŒ:”…”�”}”(hjMh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M�hjJubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjGubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjDubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ�But what about the CPU that started the grace period? Why wouldn't it see the start of the grace period right when it started that grace period?”h]”hŒ’But what about the CPU that started the grace period? Why wouldn’t it see the start of the grace period right when it started that grace period?”…”�”}”(hj{h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Mƒhjxubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjuubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjDubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ **Answer**:”h]”(jP)�”}”(hŒ **Answer**”h]”hŒAnswer”…”�”}”(hjŸh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jOhj›ubhŒ:”…”�”}”(hj›h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M‡hj˜ubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhj•ubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjDubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hXIn some deep philosophical and overly anthromorphized sense, yes, the CPU starting the grace period is immediately aware of having done so. However, if we instead assume that RCU is not self-aware, then even the CPU starting the grace period does not really become aware of the start of this grace period until its first call to ``__note_gp_changes()``. On the other hand, this CPU potentially gets early notification because it invokes ``__note_gp_changes()`` during its last ``rcu_gp_init()`` pass through its leaf ``rcu_node`` structure.”h]”(hXIIn some deep philosophical and overly anthromorphized sense, yes, the CPU starting the grace period is immediately aware of having done so. However, if we instead assume that RCU is not self-aware, then even the CPU starting the grace period does not really become aware of the start of this grace period until its first call to ”…”�”}”(hjÉh²hh³Nh´Nubj8)�”}”(hŒ``__note_gp_changes()``”h]”hŒ__note_gp_changes()”…”�”}”(hjÑh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÉubhŒU. On the other hand, this CPU potentially gets early notification because it invokes ”…”�”}”(hjÉh²hh³Nh´Nubj8)�”}”(hŒ``__note_gp_changes()``”h]”hŒ__note_gp_changes()”…”�”}”(hjãh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÉubhŒ during its last ”…”�”}”(hjÉh²hh³Nh´Nubj8)�”}”(hŒ``rcu_gp_init()``”h]”hŒ rcu_gp_init()”…”�”}”(hjõh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÉubhŒ pass through its leaf ”…”�”}”(hjÉh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÉubhŒ structure.”…”�”}”(hjÉh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M‰hjÆubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjÃubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjDubeh}”(h]”h ]”h"]”h$]”h&]”uh1j<hj7ubeh}”(h]”h ]”h"]”h$]”h&]”Œcols”Kuh1j+hj4ubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hjh h²hh³hÊh´Nubeh}”(h]”jïah ]”h"]”Œgrace-period initialization”ah$]”h&]”uh1hµhjŒh²hh³hÊh´MHjg Kubh¶)�”}”(hhh]”(h»)�”}”(hŒSelf-Reported Quiescent States”h]”hŒSelf-Reported Quiescent States”…”�”}”(hjHh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjEh²hh³hÊh´M•ubhÌ)�”}”(hXWhen all entities that might block the grace period have reported quiescent states (or as described in a later section, had quiescent states reported on their behalf), the grace period can end. Online non-idle CPUs report their own quiescent states, as shown in the following diagram:”h]”hXWhen all entities that might block the grace period have reported quiescent states (or as described in a later section, had quiescent states reported on their behalf), the grace period can end. Online non-idle CPUs report their own quiescent states, as shown in the following diagram:”…”�”}”(hjVh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M—hjEh²hubj")�”}”(hhh]”j')�”}”(hhh]”j,)�”}”(hŒ".. kernel-figure:: TreeRCU-qs.svg ”h]”h}”(h]”h ]”h"]”h$]”h&]”Œuri”Œ)RCU/Design/Memory-Ordering/TreeRCU-qs.svg”j9}”j;jusuh1j+hjgh³hÊh´Kubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hjdubah}”(h]”h ]”h"]”h$]”h&]”uh1j!hjEh²hh³hÊh´MžubhÌ)�”}”(hXŠThis is for the last CPU to report a quiescent state, which signals the end of the grace period. Earlier quiescent states would push up the ``rcu_node`` tree only until they encountered an ``rcu_node`` structure that is waiting for additional quiescent states. However, ordering is nevertheless preserved because some later quiescent state will acquire that ``rcu_node`` structure's ``->lock``.”h]”(hŒŒThis is for the last CPU to report a quiescent state, which signals the end of the grace period. Earlier quiescent states would push up the ”…”�”•~�}”(hjƒh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj‹h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjƒubhŒ% tree only until they encountered an ”…”�”}”(hjƒh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjƒubhŒ� structure that is waiting for additional quiescent states. However, ordering is nevertheless preserved because some later quiescent state will acquire that ”…”�”}”(hjƒh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj¯h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjƒubhŒ structure’s ”…”�”}”(hjƒh²hh³Nh´Nubj8)�”}”(hŒ ``->lock``”h]”hŒ->lock”…”�”}”(hjÁh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjƒubhŒ.”…”�”}”(hjƒh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MŸhjEh²hubhÌ)�”}”(hX=Any number of events can lead up to a CPU invoking ``note_gp_changes`` (or alternatively, directly invoking ``__note_gp_changes()``), at which point that CPU will notice the start of a new grace period while holding its leaf ``rcu_node`` lock. Therefore, all execution shown in this diagram happens after the start of the grace period. In addition, this CPU will consider any RCU read-side critical section that started before the invocation of ``__note_gp_changes()`` to have started before the grace period, and thus a critical section that the grace period must wait on.”h]”(hŒ3Any number of events can lead up to a CPU invoking ”…”�”}”(hjÙh²hh³Nh´Nubj8)�”}”(hŒ``note_gp_changes``”h]”hŒnote_gp_changes”…”�”}”(hjáh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÙubhŒ& (or alternatively, directly invoking ”…”�”}”(hjÙh²hh³Nh´Nubj8)�”}”(hŒ``__note_gp_changes()``”h]”hŒ__note_gp_changes()”…”�”}”(hjóh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÙubhŒ^), at which point that CPU will notice the start of a new grace period while holding its leaf ”…”�”}”(hjÙh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÙubhŒÐ lock. Therefore, all execution shown in this diagram happens after the start of the grace period. In addition, this CPU will consider any RCU read-side critical section that started before the invocation of ”…”�”}”(hjÙh²hh³Nh´Nubj8)�”}”(hŒ``__note_gp_changes()``”h]”hŒ__note_gp_changes()”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÙubhŒi to have started before the grace period, and thus a critical section that the grace period must wait on.”…”�”}”(hjÙh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M¦hjEh²hubj')�”}”(hhh]”j,)�”}”(hhh]”(j1)�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”KGuh1j0hj2ubj=)�”}”(hhh]”(jB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ**Quick Quiz**:”h]”(jP)�”}”(hŒ**Quick Quiz**”h]”hŒ Quick Quiz”…”�”}”(hjLh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jOhjHubhŒ:”…”�”}”(hjHh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M±hjEubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjBubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhj?ubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒÍBut a RCU read-side critical section might have started after the beginning of the grace period (the advancing of ``->gp_seq`` from earlier), so why should the grace period wait on such a critical section?”h]”(hŒrBut a RCU read-side critical section might have started after the beginning of the grace period (the advancing of ”…”�”}”(hjvh²hh³Nh´Nubj8)�”}”(hŒ ``->gp_seq``”h]”hŒ->gp_seq”…”�”}”(hj~h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjvubhŒO from earlier), so why should the grace period wait on such a critical section?”…”�”}”(hjvh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M³hjsubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjpubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhj?ubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ **Answer**:”h]”(jP)�”}”(hŒ **Answer**”h]”hŒAnswer”…”�”}”(hj¬h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jOhj¨ubhŒ:”…”�”}”(hj¨h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M¸hj¥ubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhj¢ubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhj?ubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hXIt is indeed not necessary for the grace period to wait on such a critical section. However, it is permissible to wait on it. And it is furthermore important to wait on it, as this lazy approach is far more scalable than a “big bangâ€� all-at-once grace-period start could possibly be.”h]”hXIt is indeed not necessary for the grace period to wait on such a critical section. However, it is permissible to wait on it. And it is furthermore important to wait on it, as this lazy approach is far more scalable than a “big bangâ€� all-at-once grace-period start could possibly be.”…”�”}”(hjÖh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MºhjÓubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjÐubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhj?ubeh}”(h]”h ]”h"]”h$]”h&]”uh1j<hj2ubeh}”(h]”h ]”h"]”h$]”h&]”Œcols”Kuh1j+hj/ubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hjEh²hh³hÊh´NubhÌ)�”}”(hXnIf the CPU does a context switch, a quiescent state will be noted by ``rcu_note_context_switch()`` on the left. On the other hand, if the CPU takes a scheduler-clock interrupt while executing in usermode, a quiescent state will be noted by ``rcu_sched_clock_irq()`` on the right. Either way, the passage through a quiescent state will be noted in a per-CPU variable.”h]”(hŒEIf the CPU does a context switch, a quiescent state will be noted by ”…”�”}”(hjh²hh³Nh´Nubj8)�”}”(hŒ``rcu_note_context_switch()``”h]”hŒrcu_note_context_switch()”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjubhŒŽ on the left. On the other hand, if the CPU takes a scheduler-clock interrupt while executing in usermode, a quiescent state will be noted by ”…”�”}”(hjh²hh³Nh´Nubj8)�”}”(hŒ``rcu_sched_clock_irq()``”h]”hŒrcu_sched_clock_irq()”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjubhŒe on the right. Either way, the passage through a quiescent state will be noted in a per-CPU variable.”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MÁhjEh²hubhÌ)�”}”(hX\The next time an ``RCU_SOFTIRQ`` handler executes on this CPU (for example, after the next scheduler-clock interrupt), ``rcu_core()`` will invoke ``rcu_check_quiescent_state()``, which will notice the recorded quiescent state, and invoke ``rcu_report_qs_rdp()``. If ``rcu_report_qs_rdp()`` verifies that the quiescent state really does apply to the current grace period, it invokes ``rcu_report_rnp()`` which traverses up the ``rcu_node`` tree as shown at the bottom of the diagram, clearing bits from each ``rcu_node`` structure's ``->qsmask`` field, and propagating up the tree when the result is zero.”h]”(hŒThe next time an ”…”�”}”(hj5h²hh³Nh´Nubj8)�”}”(hŒ``RCU_SOFTIRQ``”h]”hŒ RCU_SOFTIRQ”…”�”}”(hj=h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj5ubhŒW handler executes on this CPU (for example, after the next scheduler-clock interrupt), ”…”�”}”(hj5h²hh³Nh´Nubj8)�”}”(hŒ``rcu_core()``”h]”hŒ rcu_core()”…”�”}”(hjOh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj5ubhŒ will invoke ”…”�”}”(hj5h²hh³Nh´Nubj8)�”}”(hŒ``rcu_check_quiescent_state()``”h]”hŒrcu_check_quiescent_state()”…”�”}”(hjah²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj5ubhŒ=, which will notice the recorded quiescent state, and invoke ”…”�”}”(hj5h²hh³Nh´Nubj8)�”}”(hŒ``rcu_report_qs_rdp()``”h]”hŒrcu_report_qs_rdp()”…”�”}”(hjsh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj5ubhŒ. If ”…”�”}”(hj5h²hh³Nh´Nubj8)�”}”(hŒ``rcu_report_qs_rdp()``”h]”hŒrcu_report_qs_rdp()”…”�”}”(hj…h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj5ubhŒ] verifies that the quiescent state really does apply to the current grace period, it invokes ”…”�”}”(hj5h²hh³Nh´Nubj8)�”}”(hŒ``rcu_report_rnp()``”h]”hŒrcu_report_rnp()”…”�”}”(hj—h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj5ubhŒ which traverses up the ”…”�”}”(hj5h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj©h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj5ubhŒE tree as shown at the bottom of the diagram, clearing bits from each ”…”�”}”(hj5h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj»h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj5ubhŒ structure’s ”…”�”}”(hj5h²hh³Nh´Nubj8)�”}”(hŒ ``->qsmask``”h]”hŒ->qsmask”…”�”}”(hjÍh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj5ubhŒ< field, and propagating up the tree when the result is zero.”…”�”}”(hj5h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MÈhjEh²hubhÌ)�”}”(hX Note that traversal passes upwards out of a given ``rcu_node`` structure only if the current CPU is reporting the last quiescent state for the subtree headed by that ``rcu_node`` structure. A key point is that if a CPU's traversal stops at a given ``rcu_node`` structure, then there will be a later traversal by another CPU (or perhaps the same one) that proceeds upwards from that point, and the ``rcu_node`` ``->lock`` guarantees that the first CPU's quiescent state happens before the remainder of the second CPU's traversal. Applying this line of thought repeatedly shows that all CPUs' quiescent states happen before the last CPU traverses through the root ``rcu_node`` structure, the “last CPUâ€� being the one that clears the last bit in the root ``rcu_node`` structure's ``->qsmask`` field.”h]”(hŒ2Note that traversal passes upwards out of a given ”…”�”}”(hjåh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjíh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjåubhŒh structure only if the current CPU is reporting the last quiescent state for the subtree headed by that ”…”�”}”(hjåh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjÿh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjåubhŒH structure. A key point is that if a CPU’s traversal stops at a given ”…”�”}”(hjåh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjåubhŒ‰ structure, then there will be a later traversal by another CPU (or perhaps the same one) that proceeds upwards from that point, and the ”…”�”}”(hjåh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj#h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjåubhŒ ”…”�”}”(hjåh²hh³Nh´Nubj8)�”}”(hŒ ``->lock``”h]”hŒ->lock”…”�”}”(hj5h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjåubhŒø guarantees that the first CPU’s quiescent state happens before the remainder of the second CPU’s traversal. Applying this line of thought repeatedly shows that all CPUs’ quiescent states happen before the last CPU traverses through the root ”…”�”}”(hjåh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjGh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjåubhŒR structure, the “last CPUâ€� being the one that clears the last bit in the root ”…”�”}”(hjåh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjYh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjåubhŒ structure’s ”…”�”}”(hjåh²hh³Nh´Nubj8)�”}”(hŒ ``->qsmask``”h]”hŒ->qsmask”…”�”}”(hjkh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjåubhŒ field.”…”�”}”(hjåh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MÒhjEh²hubeh}”(h]”jah ]”h"]”Œself-reported quiescent states”ah$]”h&]”uh1hµhjŒh²hh³hÊh´M•jg Kubh¶)�”}”(hhh]”(h»)�”}”(hŒDynamic Tick Interface”h]”hŒDynamic Tick Interface”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjŠh²hh³hÊh´MàubhÌ)�”}”(hX%Due to energy-efficiency considerations, RCU is forbidden from disturbing idle CPUs. CPUs are therefore required to notify RCU when entering or leaving idle state, which they do via fully ordered value-returning atomic operations on a per-CPU variable. The ordering effects are as shown below:”h]”hX%Due to energy-efficiency considerations, RCU is forbidden from disturbing idle CPUs. CPUs are therefore required to notify RCU when entering or leaving idle state, which they do via fully ordered value-returning atomic operations on a per-CPU variable. The ordering effects are as shown below:”…”�”}”(hj›h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MâhjŠh²hubj")�”}”(hhh]”j')�”}”(hhh]”j,)�”}”(hŒ'.. kernel-figure:: TreeRCU-dyntick.svg ”h]”h}”(h]”h ]”h"]”h$]”h&]”Œuri”Œ.RCU/Design/Memory-Ordering/TreeRCU-dyntick.svg”j9}”j;jºsuh1j+hj¬h³hÊh´Kubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hj©ubah}”(h]”h ]”h"]”h$]”h&]”uh1j!hjŠh²hh³hÊh´MéubhÌ)�”}”(hXThe RCU grace-period kernel thread samples the per-CPU idleness variable while holding the corresponding CPU's leaf ``rcu_node`` structure's ``->lock``. This means that any RCU read-side critical sections that precede the idle period (the oval near the top of the diagram above) will happen before the end of the current grace period. Similarly, the beginning of the current grace period will happen before any RCU read-side critical sections that follow the idle period (the oval near the bottom of the diagram above).”h]”(hŒvThe RCU grace-period kernel thread samples the per-CPU idleness variable while holding the corresponding CPU’s leaf ”…”�”}”(hjÈh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjÐh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÈubhŒ structure’s ”…”�”}”(hjÈh²hh³Nh´Nubj8)�”}”(hŒ ``->lock``”h]”hŒ->lock”…”�”}”(hjâh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÈubhXp. This means that any RCU read-side critical sections that precede the idle period (the oval near the top of the diagram above) will happen before the end of the current grace period. Similarly, the beginning of the current grace period will happen before any RCU read-side critical sections that follow the idle period (the oval near the bottom of the diagram above).”…”�”}”(hjÈh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MêhjŠh²hubhÌ)�”}”(hŒfPlumbing this into the full grace-period execution is described `below `__.”h]”(hŒ@Plumbing this into the full grace-period execution is described ”…”�”}”(hjúh²hh³Nh´Nubjº)�”}”(hŒ%`below `__”h]”hŒbelow”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œname”Œbelow”jÊj{uh1j¹hjújÌKubhŒ.”…”�”}”(hjúh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MóhjŠh²hubeh}”(h]”j5ah ]”h"]”Œdynamic tick interface”ah$]”h&]”uh1hµhjŒh²hh³hÊh´Màjg Kubh¶)�”}”(hhh]”(h»)�”}”(hŒCPU-Hotplug Interface”h]”hŒCPU-Hotplug Interface”…”�”}”(hj&h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhj#h²hh³hÊh´M÷ubhÌ)�”}”(hXRCU is also forbidden from disturbing offline CPUs, which might well be powered off and removed from the system completely. CPUs are therefore required to notify RCU of their comings and goings as part of the corresponding CPU hotplug operations. The ordering effects are shown below:”h]”hXRCU is also forbidden from disturbing offline CPUs, which might well be powered off and removed from the system completely. CPUs are therefore required to notify RCU of their comings and goings as part of the corresponding CPU hotplug operations. The ordering effects are shown below:”…”�”}”(hj4h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Mùhj#h²hubj")�”}”(hhh]”j')�”}”(hhh]”j,)�”}”(hŒ'.. kernel-figure:: TreeRCU-hotplug.svg ”h]”h}”(h]”h ]”h"]”h$]”h&]”Œuri”Œ.RCU/Design/Memory-Ordering/TreeRCU-hotplug.svg”j9}”j;jSsuh1j+hjEh³hÊh´Kubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hjBubah}”(h]”h ]”h"]”h$]”h&]”uh1j!hj#h²hh³hÊh´MubhÌ)�”}”(hX]Because CPU hotplug operations are much less frequent than idle transitions, they are heavier weight, and thus acquire the CPU's leaf ``rcu_node`` structure's ``->lock`` and update this structure's ``->qsmaskinitnext``. The RCU grace-period kernel thread samples this mask to detect CPUs having gone offline since the beginning of this grace period.”h]”(hŒˆBecause CPU hotplug operations are much less frequent than idle transitions, they are heavier weight, and thus acquire the CPU’s leaf ”…”�”}”(hjah²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjih²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjaubhŒ structure’s ”…”�”}”(hjah²hh³Nh´Nubj8)�”}”(hŒ ``->lock``”h]”hŒ->lock”…”�”}”(hj{h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjaubhŒ and update this structure’s ”…”�”}”(hjah²hh³Nh´Nubj8)�”}”(hŒ``->qsmaskinitnext``”h]”hŒ->qsmaskinitnext”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjaubhŒƒ. The RCU grace-period kernel thread samples this mask to detect CPUs having gone offline since the beginning of this grace period.”…”�”}”(hjah²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Mhj#h²hubhÌ)�”}”(hŒfPlumbing this into the full grace-period execution is described `below `__.”h]”(hŒ@Plumbing this into the full grace-period execution is described ”…”�”}”(hj¥h²hh³Nh´Nubjº)�”}”(hŒ%`below `__”h]”hŒbelow”…”�”}”(hj­h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œname”Œbelow”jÊj{uh1j¹hj¥jÌKubhŒ.”…”�”}”(hj¥h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Mhj#h²hubeh}”(h]”jXah ]”h"]”Œcpu-hotplug interface”ah$]”h&]”uh1hµhjŒh²hh³hÊh´M÷jg Kubh¶)�”}”(hhh]”(h»)�”}”(hŒForcing Quiescent States”h]”hŒForcing Quiescent States”…”�”}”(hjÑh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjÎh²hh³hÊh´M ubhÌ)�”}”(hX&As noted above, idle and offline CPUs cannot report their own quiescent states, and therefore the grace-period kernel thread must do the reporting on their behalf. This process is called “forcing quiescent statesâ€�, it is repeated every few jiffies, and its ordering effects are shown below:”h]”hX&As noted above, idle and offline CPUs cannot report their own quiescent states, and therefore the grace-period kernel thread must do the reporting on their behalf. This process is called “forcing quiescent statesâ€�, it is repeated every few jiffies, and its ordering effects are shown below:”…”�”}”(hjßh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MhjÎh²hubj")�”}”(hhh]”j')�”}”(hhh]”j,)�”}”(hŒ&.. kernel-figure:: TreeRCU-gp-fqs.svg ”h]”h}”(h]”h ]”h"]”h$]”h&]”Œuri”Œ-RCU/Design/Memory-Ordering/TreeRCU-gp-fqs.svg”j9}”j;jþsuh1j+hjðh³hÊh´Kubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hjíubah}”(h]”h ]”h"]”h$]”h&]”uh1j!hjÎh²hh³hÊh´MubhÌ)�”}”(hX9Each pass of quiescent state forcing is guaranteed to traverse the leaf ``rcu_node`` structures, and if there are no new quiescent states due to recently idled and/or offlined CPUs, then only the leaves are traversed. However, if there is a newly offlined CPU as illustrated on the left or a newly idled CPU as illustrated on the right, the corresponding quiescent state will be driven up towards the root. As with self-reported quiescent states, the upwards driving stops once it reaches an ``rcu_node`` structure that has quiescent states outstanding from other CPUs.”h]”(hŒHEach pass of quiescent state forcing is guaranteed to traverse the leaf ”…”�”}”(hj h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj ubhX˜ structures, and if there are no new quiescent states due to recently idled and/or offlined CPUs, then only the leaves are traversed. However, if there is a newly offlined CPU as illustrated on the left or a newly idled CPU as illustrated on the right, the corresponding quiescent state will be driven up towards the root. As with self-reported quiescent states, the upwards driving stops once it reaches an ”…”�”}”(hj h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj&h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj ubhŒA structure that has quiescent states outstanding from other CPUs.”…”�”}”(hj h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MhjÎh²hubj')�”}”(hhh]”j,)�”}”(hhh]”(j1)�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”KGuh1j0hjAubj=)�”}”(hhh]”(jB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ**Quick Quiz**:”h]”(jP)�”}”(hŒ**Quick Quiz**”h]”hŒ Quick Quiz”…”�”}”(hj[h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jOhjWubhŒ:”…”�”}”(hjWh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M!hjTubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjQubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjNubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hXThe leftmost drive to root stopped before it reached the root ``rcu_node`` structure, which means that there are still CPUs subordinate to that structure on which the current grace period is waiting. Given that, how is it possible that the rightmost drive to root ended the grace period?”h]”(hŒ>The leftmost drive to root stopped before it reached the root ”…”�”}”(hj…h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj…ubhŒÕ structure, which means that there are still CPUs subordinate to that structure on which the current grace period is waiting. Given that, how is it possible that the rightmost drive to root ended the grace period?”…”�”}”(hj…h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M#hj‚ubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjNubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ **Answer**:”h]”(jP)�”}”(hŒ **Answer**”h]”hŒAnswer”…”�”}”(hj»h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jOhj·ubhŒ:”…”�”}”(hj·h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M)hj´ubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhj±ubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjNubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hX4Good analysis! It is in fact impossible in the absence of bugs in RCU. But this diagram is complex enough as it is, so simplicity overrode accuracy. You can think of it as poetic license, or you can think of it as misdirection that is resolved in the `stitched-together diagram `__.”h]”(hŒûGood analysis! It is in fact impossible in the absence of bugs in RCU. But this diagram is complex enough as it is, so simplicity overrode accuracy. You can think of it as poetic license, or you can think of it as misdirection that is resolved in the ”…”�”}”(hjåh²hh³Nh´Nubjº)�”}”(hŒ8`stitched-together diagram `__”h]”hŒstitched-together diagram”…”�”}”(hjíh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œname”Œstitched-together diagram”jÊŒputting-it-all-together”uh1j¹hjåjÌKubhŒ.”…”�”}”(hjåh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M+hjâubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjßubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjNubeh}”(h]”h ]”h"]”h$]”h&]”uh1j<hjAubeh}”(h]”h ]”h"]”h$]”h&]”Œcols”Kuh1j+hj>ubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hjÎh²hh³hÊh´Nubeh}”(h]”j{ah ]”h"]”Œforcing quiescent states”ah$]”h&]”uh1hµhjŒh²hh³hÊh´M jg Kubh¶)�”}”(hhh]”(h»)�”}”(hŒGrace-Period Cleanup”h]”hŒGrace-Period Cleanup”…”�”}”(hj1h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhj.h²hh³hÊh´M3ubhÌ)�”}”(hŒÔGrace-period cleanup first scans the ``rcu_node`` tree breadth-first advancing all the ``->gp_seq`` fields, then it advances the ``rcu_state`` structure's ``->gp_seq`` field. The ordering effects are shown below:”h]”(hŒ%Grace-period cleanup first scans the ”…”�”}”(hj?h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjGh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj?ubhŒ& tree breadth-first advancing all the ”…”�”}”(hj?h²hh³Nh´Nubj8)�”}”(hŒ ``->gp_seq``”h]”hŒ->gp_seq”…”�”}”(hjYh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj?ubhŒ fields, then it advances the ”…”�”}”(hj?h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_state``”h]”hŒ rcu_state”…”�”}”(hjkh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj?ubhŒ structure’s ”…”�”}”(hj?h²hh³Nh´Nubj8)�”}”(hŒ ``->gp_seq``”h]”hŒ->gp_seq”…”�”}”(hj}h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj?ubhŒ- field. The ordering effects are shown below:”…”�”}”(hj?h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M5hj.h²hubj")�”}”(hhh]”j')�”}”(hhh]”j,)�”}”(hŒ*.. kernel-figure:: TreeRCU-gp-cleanup.svg ”h]”h}”(h]”h ]”h"]”h$]”h&]”Œuri”Œ1RCU/Design/Memory-Ordering/TreeRCU-gp-cleanup.svg”j9}”j;j¦suh1j+hj˜h³hÊh´Kubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hj•ubah}”(h]”h ]”h"]”h$]”h&]”uh1j!hj.h²hh³hÊh´M;ubhÌ)�”}”(hŒ~As indicated by the oval at the bottom of the diagram, once grace-period cleanup is complete, the next grace period can begin.”h]”hŒ~As indicated by the oval at the bottom of the diagram, once grace-period cleanup is complete, the next grace period can begin.”…”�”}”(hj´h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M<hj.h²hubj')�”}”(hhh]”j,)�”}”(hhh]”(j1)�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”KGuh1j0hjÅubj=)�”}”(hhh]”(jB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ**Quick Quiz**:”h]”(jP)�”}”(hŒ**Quick Quiz**”h]”hŒ Quick Quiz”…”�”}”(hjßh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jOhjÛubhŒ:”…”�”}”(hjÛh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M@hjØubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjÕubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjÒubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ-But when precisely does the grace period end?”h]”hŒ-But when precisely does the grace period end?”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MBhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjÒubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hŒ **Answer**:”h]”(jP)�”}”(hŒ **Answer**”h]”hŒAnswer”…”�”}”(hj-h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jOhj)ubhŒ:”…”�”}”(hj)h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MDhj&ubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhj#ubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjÒubjB)�”}”(hhh]”jG)�”}”(hhh]”hÌ)�”}”(hXThere is no useful single point at which the grace period can be said to end. The earliest reasonable candidate is as soon as the last CPU has reported its quiescent state, but it may be some milliseconds before RCU becomes aware of this. The latest reasonable candidate is once the ``rcu_state`` structure's ``->gp_seq`` field has been updated, but it is quite possible that some CPUs have already completed phase two of their updates by that time. In short, if you are going to work with RCU, you need to learn to embrace uncertainty.”h]”(hXThere is no useful single point at which the grace period can be said to end. The earliest reasonable candidate is as soon as the last CPU has reported its quiescent state, but it may be some milliseconds before RCU becomes aware of this. The latest reasonable candidate is once the ”…”�”}”(hjWh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_state``”h]”hŒ rcu_state”…”�”}”(hj_h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjWubhŒ structure’s ”…”�”}”(hjWh²hh³Nh´Nubj8)�”}”(hŒ ``->gp_seq``”h]”hŒ->gp_seq”…”�”}”(hjqh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjWubhŒ× field has been updated, but it is quite possible that some CPUs have already completed phase two of their updates by that time. In short, if you are going to work with RCU, you need to learn to embrace uncertainty.”…”�”}”(hjWh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MFhjTubah}”(h]”h ]”h"]”h$]”h&]”uh1jFhjQubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjÒubeh}”(h]”h ]”h"]”h$]”h&]”uh1j<hjÅubeh}”(h]”h ]”h"]”h$]”h&]”Œcols”Kuh1j+hjÂubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hj.h²hh³hÊh´Nubeh}”(h]”jžah ]”h"]”Œgrace-period cleanup”ah$]”h&]”uh1hµhjŒh²hh³hÊh´M3jg Kubh¶)�”}”(hhh]”(h»)�”}”(hŒCallback Invocation”h]”hŒCallback Invocation”…”�”}”(hj²h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhj¯h²hh³hÊh´MQubhÌ)�”}”(hXOnce a given CPU's leaf ``rcu_node`` structure's ``->gp_seq`` field has been updated, that CPU can begin invoking its RCU callbacks that were waiting for this grace period to end. These callbacks are identified by ``rcu_advance_cbs()``, which is usually invoked by ``__note_gp_changes()``. As shown in the diagram below, this invocation can be triggered by the scheduling-clock interrupt (``rcu_sched_clock_irq()`` on the left) or by idle entry (``rcu_cleanup_after_idle()`` on the right, but only for kernels build with ``CONFIG_RCU_FAST_NO_HZ=y``). Either way, ``RCU_SOFTIRQ`` is raised, which results in ``rcu_do_batch()`` invoking the callbacks, which in turn allows those callbacks to carry out (either directly or indirectly via wakeup) the needed phase-two processing for each update.”h]”(hŒOnce a given CPU’s leaf ”…”�”}”(hjÀh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjÈh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÀubhŒ structure’s ”…”�”}”(hjÀh²hh³Nh´Nubj8)�”}”(hŒ ``->gp_seq``”h]”hŒ->gp_seq”…”�”}”(hjÚh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÀubhŒ™ field has been updated, that CPU can begin invoking its RCU callbacks that were waiting for this grace period to end. These callbacks are identified by ”…”�”}”(hjÀh²hh³Nh´Nubj8)�”}”(hŒ``rcu_advance_cbs()``”h]”hŒrcu_advance_cbs()”…”�”}”(hjìh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÀubhŒ, which is usually invoked by ”…”�”}”(hjÀh²hh³Nh´Nubj8)�”}”(hŒ``__note_gp_changes()``”h]”hŒ__note_gp_changes()”…”�”}”(hjþh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÀubhŒe. As shown in the diagram below, this invocation can be triggered by the scheduling-clock interrupt (”…”�”}”(hjÀh²hh³Nh´Nubj8)�”}”(hŒ``rcu_sched_clock_irq()``”h]”hŒrcu_sched_clock_irq()”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÀubhŒ on the left) or by idle entry (”…”�”}”(hjÀh²hh³Nh´Nubj8)�”}”(hŒ``rcu_cleanup_after_idle()``”h]”hŒrcu_cleanup_after_idle()”…”�”}”(hj"h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÀubhŒ/ on the right, but only for kernels build with ”…”�”}”(hjÀh²hh³Nh´Nubj8)�”}”(hŒ``CONFIG_RCU_FAST_NO_HZ=y``”h]”hŒCONFIG_RCU_FAST_NO_HZ=y”…”�”}”(hj4h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÀubhŒ). Either way, ”…”�”}”(hjÀh²hh³Nh´Nubj8)�”}”(hŒ``RCU_SOFTIRQ``”h]”hŒ RCU_SOFTIRQ”…”�”}”(hjFh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÀubhŒ is raised, which results in ”…”�”}”(hjÀh²hh³Nh´Nubj8)�”}”(hŒ``rcu_do_batch()``”h]”hŒrcu_do_batch()”…”�”}”(hjXh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÀubhŒ¦ invoking the callbacks, which in turn allows those callbacks to carry out (either directly or indirectly via wakeup) the needed phase-two processing for each update.”…”�”}”(hjÀh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´MShj¯h²hubj")�”}”(hhh]”j')�”}”(hhh]”j,)�”}”(hŒ3.. kernel-figure:: TreeRCU-callback-invocation.svg ”h]”h}”(h]”h ]”h"]”h$]”h&]”Œuri”Œ:RCU/Design/Memory-Ordering/TreeRCU-callback-invocation.svg”j9}”j;j�suh1j+hjsh³hÊh´Kubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hjpubah}”(h]”h ]”h"]”h$]”h&]”uh1j!hj¯h²hh³hÊh´MaubhÌ)�”}”(hXjPlease note that callback invocation can also be prompted by any number of corner-case code paths, for example, when a CPU notes that it has excessive numbers of callbacks queued. In all cases, the CPU acquires its leaf ``rcu_node`` structure's ``->lock`` before invoking callbacks, which preserves the required ordering against the newly completed grace period.”h]”(hŒÜPlease note that callback invocation can also be prompted by any number of corner-case code paths, for example, when a CPU notes that it has excessive numbers of callbacks queued. In all cases, the CPU acquires its leaf ”…”�”}”(hj�h²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hj—h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj�ubhŒ structure’s ”…”�”}”(hj�h²hh³Nh´Nubj8)�”}”(hŒ ``->lock``”h]”hŒ->lock”…”�”}”(hj©h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj�ubhŒk before invoking callbacks, which preserves the required ordering against the newly completed grace period.”…”�”}”(hj�h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Mbhj¯h²hubhÌ)�”}”(hXdHowever, if the callback function communicates to other CPUs, for example, doing a wakeup, then it is that function's responsibility to maintain ordering. For example, if the callback function wakes up a task that runs on some other CPU, proper ordering must in place in both the callback function and the task being awakened. To see why this is important, consider the top half of the `grace-period cleanup`_ diagram. The callback might be running on a CPU corresponding to the leftmost leaf ``rcu_node`` structure, and awaken a task that is to run on a CPU corresponding to the rightmost leaf ``rcu_node`` structure, and the grace-period kernel thread might not yet have reached the rightmost leaf. In this case, the grace period's memory ordering might not yet have reached that CPU, so again the callback function and the awakened task must supply proper ordering.”h]”(hX„However, if the callback function communicates to other CPUs, for example, doing a wakeup, then it is that function’s responsibility to maintain ordering. For example, if the callback function wakes up a task that runs on some other CPU, proper ordering must in place in both the callback function and the task being awakened. To see why this is important, consider the top half of the ”…”�”}”(hjÁh²hh³Nh´Nubjº)�”}”(hŒ`grace-period cleanup`_”h]”hŒgrace-period cleanup”…”�”}”(hjÉh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œname”Œgrace-period cleanup”jÊjžuh1j¹hjÁjÌKubhŒT diagram. The callback might be running on a CPU corresponding to the leftmost leaf ”…”�”}”(hjÁh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjÝh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÁubhŒZ structure, and awaken a task that is to run on a CPU corresponding to the rightmost leaf ”…”�”}”(hjÁh²hh³Nh´Nubj8)�”}”(hŒ ``rcu_node``”h]”hŒrcu_node”…”�”}”(hjïh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÁubhX structure, and the grace-period kernel thread might not yet have reached the rightmost leaf. In this case, the grace period’s memory ordering might not yet have reached that CPU, so again the callback function and the awakened task must supply proper ordering.”…”�”}”(hjÁh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Mihj¯h²hubeh}”(h]”jÂah ]”h"]”Œcallback invocation”ah$]”h&]”uh1hµhjŒh²hh³hÊh´MQjg Kubeh}”(h]”Œ0tree-rcu-grace-period-memory-ordering-components”ah ]”h"]”Œ0tree rcu grace period memory ordering components”ah$]”h&]”uh1hµhj‡h²hh³hÊh´Küubh¶)�”}”(hhh]”(h»)�”}”(hŒPutting It All Together”h]”hŒPutting It All Together”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjh²hh³hÊh´MyubhÌ)�”}”(hŒ$A stitched-together diagram is here:”h]”hŒ$A stitched-together diagram is here:”…”�”}”(hj'h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M{hjh²hubj")�”}”(hhh]”j')�”}”(hhh]”j,)�”}”(hŒ".. kernel-figure:: TreeRCU-gp.svg ”h]”h}”(h]”h ]”h"]”h$]”h&]”Œuri”Œ)RCU/Design/Memory-Ordering/TreeRCU-gp.svg”j9}”j;jFsuh1j+hj8h³hÊh´Kubah}”(h]”h ]”h"]”h$]”h&]”uh1j&hj5ubah}”(h]”h ]”h"]”h$]”h&]”uh1j!hjh²hh³hÊh´M~ubeh}”(h]”jýah ]”h"]”Œputting it all together”ah$]”h&]”uh1hµhj‡h²hh³hÊh´Myjg Kubh¶)�”}”(hhh]”(h»)�”}”(hŒLegal Statement”h]”hŒLegal Statement”…”�”}”(hj^h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhj[h²hh³hÊh´M€ubhÌ)�”}”(hŒ_This work represents the view of the author and does not necessarily represent the view of IBM.”h]”hŒ_This work represents the view of the author and does not necessarily represent the view of IBM.”…”�”}”(hjlh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M‚hj[h²hubhÌ)�”}”(hŒ2Linux is a registered trademark of Linus Torvalds.”h]”hŒ2Linux is a registered trademark of Linus Torvalds.”…”�”}”(hjzh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M…hj[h²hubhÌ)�”}”(hŒWOther company, product, and service names may be trademarks or service marks of others.”h]”hŒWOther company, product, and service names may be trademarks or service marks of others.”…”�”}”(hjˆh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M‡hj[h²hubeh}”(h]”Œlegal-statement”ah ]”h"]”Œlegal statement”ah$]”h&]”uh1hµhj‡h²hh³hÊh´M€ubeh}”(h]”Œ5tree-rcu-grace-period-memory-ordering-building-blocks”ah ]”h"]”Œ5tree rcu grace period memory ordering building blocks”ah$]”h&]”uh1hµhh·h²hh³hÊh´K/ubeh}”(h]”Œ6a-tour-through-tree-rcu-s-grace-period-memory-ordering”ah ]”h"]”Œ6a tour through tree_rcu's grace-period memory ordering”ah$]”h&]”uh1hµhhh²hh³hÊh´Kubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”hÊuh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)�”}”(hºNŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”jFŒfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”jÐŒerror_encoding”Œutf-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”hÊŒ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”(Œcallback registry”]”j»aŒgrace-period initialization”]”jàaŒself-reported quiescent states”]”jaŒdynamic tick interface”]”j&aŒcpu-hotplug interface”]”jIaŒforcing quiescent states”]”(jljj­eŒgrace-period cleanup”]”(j�jÉeŒcallback invocation”]”j³aŒputting it all together”]”jíauŒrefids”}”Œnameids”}”(j«j¨j j j„j�j£j jjjd jËjBjïj‡jj j5jËjXj+j{j¬jžj jÂjXjýj›j˜uŒ nametypes”}”(j«‰j ‰j„‰j£‰j‰jd ‰jB‰j‡‰j ‰jˉj+‰j¬‰j ‰jX‰j›‰uh}”(j¨h·j héj�jj j‡jjŒjËjèjïjh jjEj5jŠjXj#j{jÎjžj.jÂj¯jýjj˜j[uŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”…”R”Œparse_messages”]”Œtransform_messages”]”Œ transformer”NŒ include_log”]”Œ decoration”Nh²hub.