D.3.7.2 NMIs from Dyntick-Idle Mode

Figure: NMIs from Dyntick-Idle Mode
\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_nmi_enter(void)
2 {
...
...18 return;
19 smp_mb();
20 rdtp->dynticks_nmi++;\end{verbatim}
}\end{figure}

Figure [*] shows rcu_nmi_enter() and rcu_nmi_exit(), which handle NMI entry and exit, respectively. It is important to keep in mind that entering an NMI handler exits dyntick-idle mode and vice versa, in other words, RCU must pay attention to CPUs that claim to be in dyntick-idle mode while they are executing NMI handlers, due to the fact that NMI handlers can contain RCU read-side critical sections. This reversal of roles can be quite confusing: you have been warned.

Line 5 of rcu_nmi_enter() obtains a pointer to this CPU's rcu_dynticks structure, and line 6 checks to see if this CPU is already under scrutiny by RCU, with line 7 silently returning if so. Otherwise, line 8 increments the ->dynticks_nmi field, which must now have an odd-numbered value. Finally, line 9 executes a memory barrier to ensure that the prior increment of ->dynticks_nmi is see by all CPUs to happen before any subsequent RCU read-side critical section.

Line 16 of rcu_nmi_exit() again fetches a pointer to this CPU's rcu_dynticks structure, and line 17 checks to see if RCU would be paying attention to this CPU even if it were not in an NMI, with line 18 silently returning if so. Otherwise, line 19 executes a memory barrier to ensure that any RCU read-side critical sections within the handler are seen by all CPUs to happen before the increment of the ->dynticks_nmi field on line 20. The new value of this field must now be even.

Quick Quiz D.51: But how does the code in Figure [*] handle nested NMIs? End Quick Quiz

Paul E. McKenney 2011-12-16