| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" | |
| "http://www.w3.org/TR/html4/loose.dtd"> | |
| <html> | |
| <head><title>A Tour Through TREE_RCU's Grace-Period Memory Ordering</title> | |
| <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> | |
| <p>August 8, 2017</p> | |
| <p>This article was contributed by Paul E. McKenney</p> | |
| <h3>Introduction</h3> | |
| <p>This document gives a rough visual overview of how Tree RCU's | |
| grace-period memory ordering guarantee is provided. | |
| <ol> | |
| <li> <a href="#What Is Tree RCU's Grace Period Memory Ordering Guarantee?"> | |
| What Is Tree RCU's Grace Period Memory Ordering Guarantee?</a> | |
| <li> <a href="#Tree RCU Grace Period Memory Ordering Building Blocks"> | |
| Tree RCU Grace Period Memory Ordering Building Blocks</a> | |
| <li> <a href="#Tree RCU Grace Period Memory Ordering Components"> | |
| Tree RCU Grace Period Memory Ordering Components</a> | |
| <li> <a href="#Putting It All Together">Putting It All Together</a> | |
| </ol> | |
| <h3><a name="What Is Tree RCU's Grace Period Memory Ordering Guarantee?"> | |
| What Is Tree RCU's Grace Period Memory Ordering Guarantee?</a></h3> | |
| <p>RCU grace periods provide extremely strong memory-ordering guarantees | |
| for non-idle non-offline code. | |
| Any code that happens after the end of a given RCU grace period is guaranteed | |
| to see the effects of all accesses prior to the beginning of that grace | |
| period that are within RCU read-side critical sections. | |
| Similarly, any code that happens before the beginning of a given RCU grace | |
| period is guaranteed to see the effects of all accesses following the end | |
| of that grace period that are within RCU read-side critical sections. | |
| <p>This guarantee is particularly pervasive for <tt>synchronize_sched()</tt>, | |
| for which RCU-sched read-side critical sections include any region | |
| of code for which preemption is disabled. | |
| Given that each individual machine instruction can be thought of as | |
| an extremely small region of preemption-disabled code, one can think of | |
| <tt>synchronize_sched()</tt> as <tt>smp_mb()</tt> on steroids. | |
| <p>RCU updaters use this guarantee by splitting their updates into | |
| two phases, one of which is executed before the grace period and | |
| the other of which is executed after the grace period. | |
| In the most common use case, phase one removes an element from | |
| a linked RCU-protected data structure, and phase two frees that element. | |
| For this to work, any readers that have witnessed state prior to the | |
| phase-one update (in the common case, removal) must not witness state | |
| following the phase-two update (in the common case, freeing). | |
| <p>The RCU implementation provides this guarantee using a network | |
| of lock-based critical sections, memory barriers, and per-CPU | |
| processing, as is described in the following sections. | |
| <h3><a name="Tree RCU Grace Period Memory Ordering Building Blocks"> | |
| Tree RCU Grace Period Memory Ordering Building Blocks</a></h3> | |
| <p>The workhorse for RCU's grace-period memory ordering is the | |
| critical section for the <tt>rcu_node</tt> structure's | |
| <tt>->lock</tt>. | |
| These critical sections use helper functions for lock acquisition, including | |
| <tt>raw_spin_lock_rcu_node()</tt>, | |
| <tt>raw_spin_lock_irq_rcu_node()</tt>, and | |
| <tt>raw_spin_lock_irqsave_rcu_node()</tt>. | |
| Their lock-release counterparts are | |
| <tt>raw_spin_unlock_rcu_node()</tt>, | |
| <tt>raw_spin_unlock_irq_rcu_node()</tt>, and | |
| <tt>raw_spin_unlock_irqrestore_rcu_node()</tt>, | |
| respectively. | |
| For completeness, a | |
| <tt>raw_spin_trylock_rcu_node()</tt> | |
| is also provided. | |
| The key point is that the lock-acquisition functions, including | |
| <tt>raw_spin_trylock_rcu_node()</tt>, all invoke | |
| <tt>smp_mb__after_unlock_lock()</tt> immediately after successful | |
| acquisition of the lock. | |
| <p>Therefore, for any given <tt>rcu_node</tt> struction, 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 <tt>rcu_node</tt> 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. | |
| <p>The following litmus test exhibits the ordering effects of these | |
| lock-acquisition and lock-release functions: | |
| <pre> | |
| 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); | |
| </pre> | |
| <p>The <tt>WARN_ON()</tt> is evaluated at “the end of time”, | |
| after all changes have propagated throughout the system. | |
| Without the <tt>smp_mb__after_unlock_lock()</tt> provided by the | |
| acquisition functions, this <tt>WARN_ON()</tt> could trigger, for example | |
| on PowerPC. | |
| The <tt>smp_mb__after_unlock_lock()</tt> invocations prevent this | |
| <tt>WARN_ON()</tt> from triggering. | |
| <p>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 | |
| <tt>atomic_add_return()</tt> read-modify-write atomic operation that | |
| is invoked within <tt>rcu_dynticks_eqs_enter()</tt> at idle-entry | |
| time and within <tt>rcu_dynticks_eqs_exit()</tt> at idle-exit time. | |
| The grace-period kthread invokes <tt>rcu_dynticks_snap()</tt> and | |
| <tt>rcu_dynticks_in_eqs_since()</tt> (both of which invoke | |
| an <tt>atomic_add_return()</tt> of zero) to detect idle CPUs. | |
| <table> | |
| <tr><th> </th></tr> | |
| <tr><th align="left">Quick Quiz:</th></tr> | |
| <tr><td> | |
| But what about CPUs that remain offline for the entire | |
| grace period? | |
| </td></tr> | |
| <tr><th align="left">Answer:</th></tr> | |
| <tr><td bgcolor="#ffffff"><font color="ffffff"> | |
| 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 <tt>rcu_node</tt> structure's | |
| <tt>->lock</tt> as described above. | |
| </font></td></tr> | |
| <tr><td> </td></tr> | |
| </table> | |
| <p>The approach must be extended to handle one final case, that | |
| of waking a task blocked in <tt>synchronize_rcu()</tt>. | |
| This task might be affinitied 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 <tt>smp_mb()</tt> after the return from | |
| <tt>wait_for_completion()</tt> in the <tt>synchronize_rcu()</tt> | |
| code path. | |
| <table> | |
| <tr><th> </th></tr> | |
| <tr><th align="left">Quick Quiz:</th></tr> | |
| <tr><td> | |
| What? Where??? | |
| I don't see any <tt>smp_mb()</tt> after the return from | |
| <tt>wait_for_completion()</tt>!!! | |
| </td></tr> | |
| <tr><th align="left">Answer:</th></tr> | |
| <tr><td bgcolor="#ffffff"><font color="ffffff"> | |
| That would be because I spotted the need for that | |
| <tt>smp_mb()</tt> 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. | |
| </font></td></tr> | |
| <tr><td> </td></tr> | |
| </table> | |
| <p>Tree RCU's grace--period memory-ordering guarantees rely most | |
| heavily on the <tt>rcu_node</tt> structure's <tt>->lock</tt> | |
| field, so much so that it is necessary to abbreviate this pattern | |
| in the diagrams in the next section. | |
| For example, consider the <tt>rcu_prepare_for_idle()</tt> function | |
| shown below, which is one of several functions that enforce ordering | |
| of newly arrived RCU callbacks against future grace periods: | |
| <pre> | |
| 1 static void rcu_prepare_for_idle(void) | |
| 2 { | |
| 3 bool needwake; | |
| 4 struct rcu_data *rdp; | |
| 5 struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks); | |
| 6 struct rcu_node *rnp; | |
| 7 struct rcu_state *rsp; | |
| 8 int tne; | |
| 9 | |
| 10 if (IS_ENABLED(CONFIG_RCU_NOCB_CPU_ALL) || | |
| 11 rcu_is_nocb_cpu(smp_processor_id())) | |
| 12 return; | |
| 13 tne = READ_ONCE(tick_nohz_active); | |
| 14 if (tne != rdtp->tick_nohz_enabled_snap) { | |
| 15 if (rcu_cpu_has_callbacks(NULL)) | |
| 16 invoke_rcu_core(); | |
| 17 rdtp->tick_nohz_enabled_snap = tne; | |
| 18 return; | |
| 19 } | |
| 20 if (!tne) | |
| 21 return; | |
| 22 if (rdtp->all_lazy && | |
| 23 rdtp->nonlazy_posted != rdtp->nonlazy_posted_snap) { | |
| 24 rdtp->all_lazy = false; | |
| 25 rdtp->nonlazy_posted_snap = rdtp->nonlazy_posted; | |
| 26 invoke_rcu_core(); | |
| 27 return; | |
| 28 } | |
| 29 if (rdtp->last_accelerate == jiffies) | |
| 30 return; | |
| 31 rdtp->last_accelerate = jiffies; | |
| 32 for_each_rcu_flavor(rsp) { | |
| 33 rdp = this_cpu_ptr(rsp->rda); | |
| 34 if (rcu_segcblist_pend_cbs(&rdp->cblist)) | |
| 35 continue; | |
| 36 rnp = rdp->mynode; | |
| 37 raw_spin_lock_rcu_node(rnp); | |
| 38 needwake = rcu_accelerate_cbs(rsp, rnp, rdp); | |
| 39 raw_spin_unlock_rcu_node(rnp); | |
| 40 if (needwake) | |
| 41 rcu_gp_kthread_wake(rsp); | |
| 42 } | |
| 43 } | |
| </pre> | |
| <p>But the only part of <tt>rcu_prepare_for_idle()</tt> that really | |
| matters for this discussion are lines 37–39. | |
| We will therefore abbreviate this function as follows: | |
| </p><p><img src="rcu_node-lock.svg" alt="rcu_node-lock.svg"> | |
| <p>The box represents the <tt>rcu_node</tt> structure's <tt>->lock</tt> | |
| critical section, with the double line on top representing the additional | |
| <tt>smp_mb__after_unlock_lock()</tt>. | |
| <h3><a name="Tree RCU Grace Period Memory Ordering Components"> | |
| Tree RCU Grace Period Memory Ordering Components</a></h3> | |
| <p>Tree RCU's grace-period memory-ordering guarantee is provided by | |
| a number of RCU components: | |
| <ol> | |
| <li> <a href="#Callback Registry">Callback Registry</a> | |
| <li> <a href="#Grace-Period Initialization">Grace-Period Initialization</a> | |
| <li> <a href="#Self-Reported Quiescent States"> | |
| Self-Reported Quiescent States</a> | |
| <li> <a href="#Dynamic Tick Interface">Dynamic Tick Interface</a> | |
| <li> <a href="#CPU-Hotplug Interface">CPU-Hotplug Interface</a> | |
| <li> <a href="Forcing Quiescent States">Forcing Quiescent States</a> | |
| <li> <a href="Grace-Period Cleanup">Grace-Period Cleanup</a> | |
| <li> <a href="Callback Invocation">Callback Invocation</a> | |
| </ol> | |
| <p>Each of the following section looks at the corresponding component | |
| in detail. | |
| <h4><a name="Callback Registry">Callback Registry</a></h4> | |
| <p>If RCU's grace-period guarantee is to mean anything at all, any | |
| access that happens before a given invocation of <tt>call_rcu()</tt> | |
| 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: | |
| </p><p><img src="TreeRCU-callback-registry.svg" alt="TreeRCU-callback-registry.svg"> | |
| <p>Because <tt>call_rcu()</tt> 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 <tt>rcu_head</tt> structure on a per-CPU list, | |
| which cannot become associated with a grace period until a later | |
| call to <tt>rcu_accelerate_cbs()</tt>, as shown in the diagram above. | |
| <p>One set of code paths shown on the left invokes | |
| <tt>rcu_accelerate_cbs()</tt> via | |
| <tt>note_gp_changes()</tt>, either directly from <tt>call_rcu()</tt> (if | |
| the current CPU is inundated with queued <tt>rcu_head</tt> structures) | |
| or more likely from an <tt>RCU_SOFTIRQ</tt> handler. | |
| Another code path in the middle is taken only in kernels built with | |
| <tt>CONFIG_RCU_FAST_NO_HZ=y</tt>, which invokes | |
| <tt>rcu_accelerate_cbs()</tt> via <tt>rcu_prepare_for_idle()</tt>. | |
| The final code path on the right is taken only in kernels built with | |
| <tt>CONFIG_HOTPLUG_CPU=y</tt>, which invokes | |
| <tt>rcu_accelerate_cbs()</tt> via | |
| <tt>rcu_advance_cbs()</tt>, <tt>rcu_migrate_callbacks</tt>, | |
| <tt>rcutree_migrate_callbacks()</tt>, and <tt>takedown_cpu()</tt>, | |
| which in turn is invoked on a surviving CPU after the outgoing | |
| CPU has been completely offlined. | |
| <p>There are a few other code paths within grace-period processing | |
| that opportunistically invoke <tt>rcu_accelerate_cbs()</tt>. | |
| However, either way, all of the CPU's recently queued <tt>rcu_head</tt> | |
| structures are associated with a future grace-period number under | |
| the protection of the CPU's lead <tt>rcu_node</tt> structure's | |
| <tt>->lock</tt>. | |
| In all cases, there is full ordering against any prior critical section | |
| for that same <tt>rcu_node</tt> structure's <tt>->lock</tt>, and | |
| also full ordering against any of the current task's or CPU's prior critical | |
| sections for any <tt>rcu_node</tt> structure's <tt>->lock</tt>. | |
| <p>The next section will show how this ordering ensures that any | |
| accesses prior to the <tt>call_rcu()</tt> (particularly including phase | |
| one of the update) | |
| happen before the start of the corresponding grace period. | |
| <table> | |
| <tr><th> </th></tr> | |
| <tr><th align="left">Quick Quiz:</th></tr> | |
| <tr><td> | |
| But what about <tt>synchronize_rcu()</tt>? | |
| </td></tr> | |
| <tr><th align="left">Answer:</th></tr> | |
| <tr><td bgcolor="#ffffff"><font color="ffffff"> | |
| The <tt>synchronize_rcu()</tt> passes <tt>call_rcu()</tt> | |
| to <tt>wait_rcu_gp()</tt>, which invokes it. | |
| So either way, it eventually comes down to <tt>call_rcu()</tt>. | |
| </font></td></tr> | |
| <tr><td> </td></tr> | |
| </table> | |
| <h4><a name="Grace-Period Initialization">Grace-Period Initialization</a></h4> | |
| <p>Grace-period initialization is carried out by | |
| the grace-period kernel thread, which makes several passes over the | |
| <tt>rcu_node</tt> tree within the <tt>rcu_gp_init()</tt> 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 | |
| <tt>rcu_node</tt> changes over time, just like Heraclitus's river. | |
| However, to keep the <tt>rcu_node</tt> 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. | |
| <p>The first ordering-related grace-period initialization action is to | |
| advance the <tt>rcu_state</tt> structure's <tt>->gp_seq</tt> | |
| grace-period-number counter, as shown below: | |
| </p><p><img src="TreeRCU-gp-init-1.svg" alt="TreeRCU-gp-init-1.svg" width="75%"> | |
| <p>The actual increment is carried out using <tt>smp_store_release()</tt>, | |
| which helps reject false-positive RCU CPU stall detection. | |
| Note that only the root <tt>rcu_node</tt> structure is touched. | |
| <p>The first pass through the <tt>rcu_node</tt> 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 <tt>rcu_node</tt> | |
| structure has not transitioned to or from zero, | |
| this pass will scan only the leaf <tt>rcu_node</tt> structures. | |
| However, if the number of online CPUs for a given leaf <tt>rcu_node</tt> | |
| structure has transitioned from zero, | |
| <tt>rcu_init_new_rnp()</tt> will be invoked for the first incoming CPU. | |
| Similarly, if the number of online CPUs for a given leaf <tt>rcu_node</tt> | |
| structure has transitioned to zero, | |
| <tt>rcu_cleanup_dead_rnp()</tt> will be invoked for the last outgoing CPU. | |
| The diagram below shows the path of ordering if the leftmost | |
| <tt>rcu_node</tt> structure onlines its first CPU and if the next | |
| <tt>rcu_node</tt> structure has no online CPUs | |
| (or, alternatively if the leftmost <tt>rcu_node</tt> structure offlines | |
| its last CPU and if the next <tt>rcu_node</tt> structure has no online CPUs). | |
| </p><p><img src="TreeRCU-gp-init-2.svg" alt="TreeRCU-gp-init-1.svg" width="75%"> | |
| <p>The final <tt>rcu_gp_init()</tt> pass through the <tt>rcu_node</tt> | |
| tree traverses breadth-first, setting each <tt>rcu_node</tt> structure's | |
| <tt>->gp_seq</tt> field to the newly advanced value from the | |
| <tt>rcu_state</tt> structure, as shown in the following diagram. | |
| </p><p><img src="TreeRCU-gp-init-3.svg" alt="TreeRCU-gp-init-1.svg" width="75%"> | |
| <p>This change will also cause each CPU's next call to | |
| <tt>__note_gp_changes()</tt> | |
| 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 <tt>rcu_state</tt> structure's | |
| <tt>->gp_seq</tt> field) before setting each leaf <tt>rcu_node</tt> | |
| structure's <tt>->gp_seq</tt> field, each CPU's observation of | |
| the start of the grace period will happen after the actual start | |
| of the grace period. | |
| <table> | |
| <tr><th> </th></tr> | |
| <tr><th align="left">Quick Quiz:</th></tr> | |
| <tr><td> | |
| 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? | |
| </td></tr> | |
| <tr><th align="left">Answer:</th></tr> | |
| <tr><td bgcolor="#ffffff"><font color="ffffff"> | |
| In 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 <tt>__note_gp_changes()</tt>. | |
| On the other hand, this CPU potentially gets early notification | |
| because it invokes <tt>__note_gp_changes()</tt> during its | |
| last <tt>rcu_gp_init()</tt> pass through its leaf | |
| <tt>rcu_node</tt> structure. | |
| </font></td></tr> | |
| <tr><td> </td></tr> | |
| </table> | |
| <h4><a name="Self-Reported Quiescent States"> | |
| Self-Reported Quiescent States</a></h4> | |
| <p>When 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: | |
| </p><p><img src="TreeRCU-qs.svg" alt="TreeRCU-qs.svg" width="75%"> | |
| <p>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 <tt>rcu_node</tt> tree | |
| only until they encountered an <tt>rcu_node</tt> structure that | |
| is waiting for additional quiescent states. | |
| However, ordering is nevertheless preserved because some later quiescent | |
| state will acquire that <tt>rcu_node</tt> structure's <tt>->lock</tt>. | |
| <p>Any number of events can lead up to a CPU invoking | |
| <tt>note_gp_changes</tt> (or alternatively, directly invoking | |
| <tt>__note_gp_changes()</tt>), at which point that CPU will notice | |
| the start of a new grace period while holding its leaf | |
| <tt>rcu_node</tt> 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 <tt>__note_gp_changes()</tt> | |
| to have started before the grace period, and thus a critical | |
| section that the grace period must wait on. | |
| <table> | |
| <tr><th> </th></tr> | |
| <tr><th align="left">Quick Quiz:</th></tr> | |
| <tr><td> | |
| But a RCU read-side critical section might have started | |
| after the beginning of the grace period | |
| (the advancing of <tt>->gp_seq</tt> from earlier), so why should | |
| the grace period wait on such a critical section? | |
| </td></tr> | |
| <tr><th align="left">Answer:</th></tr> | |
| <tr><td bgcolor="#ffffff"><font color="ffffff"> | |
| It 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. | |
| </font></td></tr> | |
| <tr><td> </td></tr> | |
| </table> | |
| <p>If the CPU does a context switch, a quiescent state will be | |
| noted by <tt>rcu_node_context_switch()</tt> 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 | |
| <tt>rcu_check_callbacks()</tt> on the right. | |
| Either way, the passage through a quiescent state will be noted | |
| in a per-CPU variable. | |
| <p>The next time an <tt>RCU_SOFTIRQ</tt> handler executes on | |
| this CPU (for example, after the next scheduler-clock | |
| interrupt), <tt>__rcu_process_callbacks()</tt> will invoke | |
| <tt>rcu_check_quiescent_state()</tt>, which will notice the | |
| recorded quiescent state, and invoke | |
| <tt>rcu_report_qs_rdp()</tt>. | |
| If <tt>rcu_report_qs_rdp()</tt> verifies that the quiescent state | |
| really does apply to the current grace period, it invokes | |
| <tt>rcu_report_rnp()</tt> which traverses up the <tt>rcu_node</tt> | |
| tree as shown at the bottom of the diagram, clearing bits from | |
| each <tt>rcu_node</tt> structure's <tt>->qsmask</tt> field, | |
| and propagating up the tree when the result is zero. | |
| <p>Note that traversal passes upwards out of a given <tt>rcu_node</tt> | |
| structure only if the current CPU is reporting the last quiescent | |
| state for the subtree headed by that <tt>rcu_node</tt> structure. | |
| A key point is that if a CPU's traversal stops at a given <tt>rcu_node</tt> | |
| structure, then there will be a later traversal by another CPU | |
| (or perhaps the same one) that proceeds upwards | |
| from that point, and the <tt>rcu_node</tt> <tt>->lock</tt> | |
| 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 <tt>rcu_node</tt> structure, the “last CPU” | |
| being the one that clears the last bit in the root <tt>rcu_node</tt> | |
| structure's <tt>->qsmask</tt> field. | |
| <h4><a name="Dynamic Tick Interface">Dynamic Tick Interface</a></h4> | |
| <p>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: | |
| </p><p><img src="TreeRCU-dyntick.svg" alt="TreeRCU-dyntick.svg" width="50%"> | |
| <p>The RCU grace-period kernel thread samples the per-CPU idleness | |
| variable while holding the corresponding CPU's leaf <tt>rcu_node</tt> | |
| structure's <tt>->lock</tt>. | |
| 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). | |
| <p>Plumbing this into the full grace-period execution is described | |
| <a href="#Forcing Quiescent States">below</a>. | |
| <h4><a name="CPU-Hotplug Interface">CPU-Hotplug Interface</a></h4> | |
| <p>RCU 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: | |
| </p><p><img src="TreeRCU-hotplug.svg" alt="TreeRCU-hotplug.svg" width="50%"> | |
| <p>Because CPU hotplug operations are much less frequent than idle transitions, | |
| they are heavier weight, and thus acquire the CPU's leaf <tt>rcu_node</tt> | |
| structure's <tt>->lock</tt> and update this structure's | |
| <tt>->qsmaskinitnext</tt>. | |
| The RCU grace-period kernel thread samples this mask to detect CPUs | |
| having gone offline since the beginning of this grace period. | |
| <p>Plumbing this into the full grace-period execution is described | |
| <a href="#Forcing Quiescent States">below</a>. | |
| <h4><a name="Forcing Quiescent States">Forcing Quiescent States</a></h4> | |
| <p>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: | |
| </p><p><img src="TreeRCU-gp-fqs.svg" alt="TreeRCU-gp-fqs.svg" width="100%"> | |
| <p>Each pass of quiescent state forcing is guaranteed to traverse the | |
| leaf <tt>rcu_node</tt> 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 <tt>rcu_node</tt> structure that has quiescent | |
| states outstanding from other CPUs. | |
| <table> | |
| <tr><th> </th></tr> | |
| <tr><th align="left">Quick Quiz:</th></tr> | |
| <tr><td> | |
| The leftmost drive to root stopped before it reached | |
| the root <tt>rcu_node</tt> 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? | |
| </td></tr> | |
| <tr><th align="left">Answer:</th></tr> | |
| <tr><td bgcolor="#ffffff"><font color="ffffff"> | |
| 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 | |
| <a href="#Putting It All Together">stitched-together diagram</a>. | |
| </font></td></tr> | |
| <tr><td> </td></tr> | |
| </table> | |
| <h4><a name="Grace-Period Cleanup">Grace-Period Cleanup</a></h4> | |
| <p>Grace-period cleanup first scans the <tt>rcu_node</tt> tree | |
| breadth-first advancing all the <tt>->gp_seq</tt> fields, then it | |
| advances the <tt>rcu_state</tt> structure's <tt>->gp_seq</tt> field. | |
| The ordering effects are shown below: | |
| </p><p><img src="TreeRCU-gp-cleanup.svg" alt="TreeRCU-gp-cleanup.svg" width="75%"> | |
| <p>As indicated by the oval at the bottom of the diagram, once | |
| grace-period cleanup is complete, the next grace period can begin. | |
| <table> | |
| <tr><th> </th></tr> | |
| <tr><th align="left">Quick Quiz:</th></tr> | |
| <tr><td> | |
| But when precisely does the grace period end? | |
| </td></tr> | |
| <tr><th align="left">Answer:</th></tr> | |
| <tr><td bgcolor="#ffffff"><font color="ffffff"> | |
| There 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 <tt>rcu_state</tt> | |
| structure's <tt>->gp_seq</tt> 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. | |
| </font></td></tr> | |
| <tr><td> </td></tr> | |
| </table> | |
| <h4><a name="Callback Invocation">Callback Invocation</a></h4> | |
| <p>Once a given CPU's leaf <tt>rcu_node</tt> structure's | |
| <tt>->gp_seq</tt> 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 <tt>rcu_advance_cbs()</tt>, | |
| which is usually invoked by <tt>__note_gp_changes()</tt>. | |
| As shown in the diagram below, this invocation can be triggered by | |
| the scheduling-clock interrupt (<tt>rcu_check_callbacks()</tt> on | |
| the left) or by idle entry (<tt>rcu_cleanup_after_idle()</tt> on | |
| the right, but only for kernels build with | |
| <tt>CONFIG_RCU_FAST_NO_HZ=y</tt>). | |
| Either way, <tt>RCU_SOFTIRQ</tt> is raised, which results in | |
| <tt>rcu_do_batch()</tt> 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. | |
| </p><p><img src="TreeRCU-callback-invocation.svg" alt="TreeRCU-callback-invocation.svg" width="60%"> | |
| <p>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 <tt>rcu_node</tt> structure's | |
| <tt>->lock</tt> before invoking callbacks, which preserves the | |
| required ordering against the newly completed grace period. | |
| <p>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 | |
| <a href="#Grace-Period Cleanup">grace-period cleanup</a> diagram. | |
| The callback might be running on a CPU corresponding to the leftmost | |
| leaf <tt>rcu_node</tt> structure, and awaken a task that is to run on | |
| a CPU corresponding to the rightmost leaf <tt>rcu_node</tt> 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. | |
| <h3><a name="Putting It All Together">Putting It All Together</a></h3> | |
| <p>A stitched-together diagram is | |
| <a href="Tree-RCU-Diagram.html">here</a>. | |
| <h3><a name="Legal Statement"> | |
| Legal Statement</a></h3> | |
| <p>This work represents the view of the author and does not necessarily | |
| represent the view of IBM. | |
| </p><p>Linux is a registered trademark of Linus Torvalds. | |
| </p><p>Other company, product, and service names may be trademarks or | |
| service marks of others. | |
| </body></html> |