E.7.1.3 Grace-Period Interface
Keywords: perfbook_html

###
E.7.1.3 Grace-Period Interface

Of the four preemptible RCU grace-period states shown in Figure on page in Appendix , only the rcu_try_flip_waitack_state() and rcu_try_flip_waitmb_state() states need to wait for other CPUs to respond.

Of course, if a given CPU is in dynticks-idle state, we shouldn't wait for it. Therefore, just before entering one of these two states, the preceding state takes a snapshot of each CPU's dynticks_progress_counter variable, placing the snapshot in another per-CPU variable, rcu_dyntick_snapshot. This is accomplished by invoking dyntick_save_progress_counter, shown below:

      1 static void dyntick_save_progress_counter(int cpu)
      2 {
      3   per_cpu(rcu_dyntick_snapshot, cpu) =
      4     per_cpu(dynticks_progress_counter, cpu);
      5 }

The rcu_try_flip_waitack_state() state invokes rcu_try_flip_waitack_needed(), shown below:

      1 static inline int
      2 rcu_try_flip_waitack_needed(int cpu)
      3 {
      4   long curr;
      5   long snap;
      6
      7   curr = per_cpu(dynticks_progress_counter, cpu);
      8   snap = per_cpu(rcu_dyntick_snapshot, cpu);
      9   smp_mb();
     10   if ((curr == snap) && ((curr & 0x1) == 0))
     11     return 0;
     12   if ((curr - snap) > 2 || (snap & 0x1) == 0)
     13     return 0;
     14   return 1;
     15 }

Lines 7 and 8 pick up current and snapshot versions of dynticks_progress_counter, respectively. The memory barrier on line ensures that the counter checks in the later rcu_try_flip_waitzero_state follow the fetches of these counters. Lines 10 and 11 return zero (meaning no communication with the specified CPU is required) if that CPU has remained in dynticks-idle state since the time that the snapshot was taken. Similarly, lines 12 and 13 return zero if that CPU was initially in dynticks-idle state or if it has completely passed through a dynticks-idle state. In both these cases, there is no way that that CPU could have retained the old value of the grace-period counter. If neither of these conditions hold, line 14 returns one, meaning that the CPU needs to explicitly respond.

For its part, the rcu_try_flip_waitmb_state state invokes rcu_try_flip_waitmb_needed(), shown below:

      1 static inline int
      2 rcu_try_flip_waitmb_needed(int cpu)
      3 {
      4   long curr;
      5   long snap;
      6
      7   curr = per_cpu(dynticks_progress_counter, cpu);
      8   snap = per_cpu(rcu_dyntick_snapshot, cpu);
      9   smp_mb();
     10   if ((curr == snap) && ((curr & 0x1) == 0))
     11     return 0;
     12   if (curr != snap)
     13     return 0;
     14   return 1;
     15 }

This is quite similar to rcu_try_flip_waitack_needed, the difference being in lines 12 and 13, because any transition either to or from dynticks-idle state executes the memory barrier needed by the rcu_try_flip_waitmb_state() state.

We now have seen all the code involved in the interface between RCU and the dynticks-idle state. The next section builds up the Promela model used to verify this code.

Quick Quiz E.9: Can you spot any bugs in any of the code in this section? End Quick Quiz