10.07.2015 Views

Is Parallel Programming Hard, And, If So, What Can You Do About It?

Is Parallel Programming Hard, And, If So, What Can You Do About It?

Is Parallel Programming Hard, And, If So, What Can You Do About It?

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

240 APPENDIX D. READ-COPY UPDATE IMPLEMENTATIONStook a scheduling-clock interrupt. The firstCPU would then see that it needed to acknowledgethe counter flip, which it would do. Thisacknowledgment is a promise to avoid incrementingthe newly old counter, and this CPUwould break this promise. Worse yet, this CPUmight be preempted immediately upon returnfrom the scheduling-clock interrupt, and thusend up incrementing the counter at some randompoint in the future. Either situation coulddisrupt grace-period detection.2. Disabling irqs has the side effect of disablingpreemption. <strong>If</strong> this code were tobe preempted between fetching rcu_ctrlblk.completed (line 14) and incrementing rcu_flipctr (line 16), it might well be migratedto some other CPU. This would result in itnon-atomically incrementing the counter fromthat other CPU. <strong>If</strong> this CPU happened to beexecuting in rcu_read_lock() or rcu_read_unlock() just at that time, one of the incrementsor decrements might be lost, again disruptinggrace-perioddetection.Thesameresultcould happen on RISC machines if the preemptionoccurred in the middle of the increment(after the fetch of the old counter but beforethe store of the newly incremented counter).3. Permitting preemption in the midst of line 16,between selecting the current CPU’s copy of thercu_flipctr array and the increment of the elementindicated by rcu_flipctr_idx, can resultin a similar failure. Execution might wellresume on some other CPU. <strong>If</strong> this resumptionhappened concurrently with an rcu_read_lock() or rcu_read_unlock() running on theoriginal CPU, an increment or decrement mightbe lost, resulting in either premature terminationof a grace period, indefinite extension of agrace period, or even both.4. Failing to disable preemption can also defeatRCU priority boosting, which relies on rcu_read_lock_nesting to determine when a giventask is in an RCU read-side critical section. <strong>So</strong>,for example, if a given task is indefinitely preemptedjust after incrementing rcu_flipctr,but before updating rcu_read_lock_nesting,then it will stall RCU grace periods for aslong as it is preempted. However, becausercu_read_lock_nesting has not yet been incremented,the RCU priority booster has noway to tell that boosting is needed. Therefore,in the presence of CPU-bound realtime threads,1 void __rcu_read_unlock(void)2 {3 int idx;4 struct task_struct *t = current;5 int nesting;67 nesting = ACCESS_ONCE(t->rcu_read_lock_nesting);8 if (nesting > 1) {9 t->rcu_read_lock_nesting = nesting - 1;10 } else {11 unsigned long flags;1213 local_irq_save(flags);14 idx = ACCESS_ONCE(t->rcu_flipctr_idx);15 ACCESS_ONCE(t->rcu_read_lock_nesting) = nesting - 1;16 ACCESS_ONCE(__get_cpu_var(rcu_flipctr)[idx])--;17 local_irq_restore(flags);18 }19 }Figure D.74: rcu read unlock() Implementationthe preempted task might stall grace periods indefinitely,eventually causing an OOM event.The last three reasons could of course be addressedby disabling preemption rather than disablingof irqs, but given that the first reason requiresdisabling irqs in any case, there is little reason toseparately disable preemption. <strong>It</strong> is entirely possiblethat the first reason might be tolerated by requiringan additional grace-period stage, however, it is notclear that disabling preemption is much faster thandisabling interrupts on modern CPUs.rcu read unlock() The implementation of rcu_read_unlock() is shown in Figure D.74. Line 7fetches the rcu_read_lock_nesting counter, whichline 8 checks to see if we are under the protectionof an enclosing rcu_read_lock() primitive. <strong>If</strong> so,line 9 simply decrements the counter.However, as with rcu_read_lock(), we otherwisemust do more work. Lines 13 and 17 disableand restore irqs in order to prevent the schedulingclockinterrupt from invoking the grace-period statemachine while in the midst of rcu_read_unlock()processing. Line 14 picks up the rcu_flipctr_idxthat was saved by the matching rcu_read_lock(),line 15 decrements rcu_read_lock_nesting so thatirq and NMI/SMI handlers will henceforth updatercu_flipctr, line 16 decrements the counter (withthe same index as, but possibly on a different CPUthan, that incremented by the matching rcu_read_lock().The ACCESS_ONCE() macros and irq disabling arerequired for similar reasons that they are in rcu_read_lock().Quick Quiz D.59: <strong>What</strong> problems could ariseif the lines containing ACCESS_ONCE() in rcu_read_

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!