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

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

210 APPENDIX D. READ-COPY UPDATE IMPLEMENTATIONSLines 7-10 check to see if it has been awhile sincethe current grace period started, and, if so, line 11invokes force_quiescent_state() in order to tryto convince holdout CPUs to pass through a quiescentstate for this grace period.Quick Quiz D.31: But don’t we also need tocheck that a grace period is actually in progress in__rcu_process_callbacks in Figure D.24?In any case, line 12 invokes rcu_process_gp_end(), which checks to see if some other CPUended the last grace period that this CPU wasaware of, and, if so, notes the end of the grace periodand advances this CPU’s RCU callbacks accordingly.Line 13 invokes rcu_check_quiescent_state(), which checks to see if some other CPU hasstarted a new grace period, and also whether thecurrent CPU has passed through a quiescent statefor the current grace period, updating state appropriatelyif so. Line 14 checks to see if there is nograce period in progress and whether the currentCPU has callbacks that need another grace period.<strong>If</strong> so, line 15 acquires the root rcu_node structure’slock, and line 17 invokes rcu_start_gp(), whichstarts a new grace period (and also releases the rootrcu_node structure’s lock). In either case, line 18invokes rcu_do_batch(), which invokes any of thisCPU’s callbacks whose grace period has completed.Quick Quiz D.32: <strong>What</strong> happens if two CPUsattempt to start a new grace period concurrently inFigure D.24?Lines 21-30 are rcu_process_callbacks(),which is again a wrapper for __rcu_process_callbacks(). Line 24 executes a memory barrierto ensure that any prior RCU read-side criticalsections are seen to have ended before any subsequentRCU processing. Lines 25-26 and 27-28invoke __rcu_process_callbacks() for “rcu” and“rcu bh”, respectively, and, finally, line 29 executesa memory barrier to ensure that any RCU processingcarried out by __rcu_process_callbacks() isseen prior to any subsequent RCU read-side criticalsections.D.3.2.5 rcu needs cpu()rcu cpu notify()andFigure D.25 shows the code for rcu_needs_cpu()and rcu_cpu_notify(), which are invoked by theLinux kernel to check on switching to dynticks-idlemode and to handle CPU hotplug, respectively.Lines 1-5 show rcu_needs_cpu(), which simplychecks if the specified CPU has either “rcu” (line 3)or “rcu bh” (line 4) callbacks.Lines 7-28 show rcu_cpu_notify(), which is a1 int rcu_needs_cpu(int cpu)2 {3 return per_cpu(rcu_data, cpu).nxtlist ||4 per_cpu(rcu_bh_data, cpu).nxtlist;5 }67 static int __cpuinit8 rcu_cpu_notify(struct notifier_block *self,9 unsigned long action, void *hcpu)10 {11 long cpu = (long)hcpu;1213 switch (action) {14 case CPU_UP_PREPARE:15 case CPU_UP_PREPARE_FROZEN:16 rcu_online_cpu(cpu);17 break;18 case CPU_DEAD:19 case CPU_DEAD_FROZEN:20 case CPU_UP_CANCELED:21 case CPU_UP_CANCELED_FROZEN:22 rcu_offline_cpu(cpu);23 break;24 default:25 break;26 }27 return NOTIFY_OK;28 }Figure D.25: rcu needs cpu() and rcu cpu notifyCodevery typical CPU-hotplug notifier function with thetypical switch statement. Line 16 invokes rcu_online_cpu() if the specified CPU is going to becoming online, and line 22 invokes rcu_offline_cpu() if the specified CPU has gone to be going offline.<strong>It</strong> is important to note that CPU-hotplug operationsare not atomic, but rather happen in stagesthat can extend for multiple grace periods. RCUmust therefore gracefully handle CPUs that are inthe process of coming or going.D.3.3 InitializationThis section walks through the initialization code,which links the main data structures together asshown in Figure D.26. The yellow region representsfields in the rcu_state data structure, includingthe ->node array, individual elements of whichare shown in pink, matching the convention usedin Section D.2. The blue boxes each represent onercu_data structure, and the group of blue boxesmakes up a set of per-CPU rcu_data structures.The ->levelcnt[] array is initialized at compiletime, as is ->level[0], but the rest of the valuesand pointers are filled in by the functions describedin the following sections. The figure shows a twolevelhierarchy, but one-level and three-level hierarchiesare possible as well. Each element of the->levelspread[] array gives the number of childrenper node at the corresponding level of the hi-

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

Saved successfully!

Ooh no, something went wrong!