D.3.2.4 rcu_process_callbacks()

Figure: rcu_process_callbacks() Code
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 __rcu_process_ca...
... &__get_cpu_var(rcu_bh_data));
29 smp_mb();
30 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for rcu_process_callbacks(), which is a wrapper around __rcu_process_callbacks(). These functions are invoked as a result of a call to raise_softirq(RCU_SOFTIRQ), for example, line 47 of Figure [*], which is normally done if there is reason to believe that the RCU core needs this CPU to do something.

Lines 7-10 check to see if it has been awhile since the current grace period started, and, if so, line 11 invokes force_quiescent_state() in order to try to convince holdout CPUs to pass through a quiescent state for this grace period.

Quick Quiz D.31: But don't we also need to check that a grace period is actually in progress in __rcu_process_callbacks in Figure [*]? End Quick Quiz

In any case, line 12 invokes rcu_process_gp_end(), which checks to see if some other CPU ended the last grace period that this CPU was aware of, and, if so, notes the end of the grace period and advances this CPU's RCU callbacks accordingly. Line 13 invokes rcu_check_quiescent_state(), which checks to see if some other CPU has started a new grace period, and also whether the current CPU has passed through a quiescent state for the current grace period, updating state appropriately if so. Line 14 checks to see if there is no grace period in progress and whether the current CPU has callbacks that need another grace period. If so, line 15 acquires the root rcu_node structure's lock, and line 17 invokes rcu_start_gp(), which starts a new grace period (and also releases the root rcu_node structure's lock). In either case, line 18 invokes rcu_do_batch(), which invokes any of this CPU's callbacks whose grace period has completed.

Quick Quiz D.32: What happens if two CPUs attempt to start a new grace period concurrently in Figure [*]? End Quick Quiz

Lines 21-30 are rcu_process_callbacks(), which is again a wrapper for __rcu_process_callbacks(). Line 24 executes a memory barrier to ensure that any prior RCU read-side critical sections are seen to have ended before any subsequent RCU processing. Lines 25-26 and 27-28 invoke __rcu_process_callbacks() for ``rcu'' and ``rcu_bh'', respectively, and, finally, line 29 executes a memory barrier to ensure that any RCU processing carried out by __rcu_process_callbacks() is seen prior to any subsequent RCU read-side critical sections.

Paul E. McKenney 2011-12-16