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.

80 CHAPTER 8. DEFERRED PROCESSINGtions):1 for_each_online_cpu(cpu)2 run_on(cpu);Here, run_on() switches the current thread to thespecified CPU, which forces a context switch on thatCPU. The for_each_online_cpu() loop thereforeforces a context switch on each CPU, thereby guaranteeingthat all prior RCU read-side critical sectionshave completed, as required. Although thissimple approach works for kernels in which preemptionis disabled across RCU read-side criticalsections, in other words, for non-CONFIG_PREEMPTand CONFIG_PREEMPT kernels, it does not work forCONFIG_PREEMPT_RT realtime (-rt) kernels. Therefore,realtime RCU uses a different approach basedloosely on reference counters [McK07a].Of course, the actual implementation in the Linuxkernelismuchmorecomplex,asitisrequiredtohandleinterrupts, NM<strong>Is</strong>, CPU hotplug, and other hazardsof production-capable kernels, but while alsomaintaining good performance and scalability. Realtimeimplementations of RCU must additionallyhelp provide good realtime response, which rules outimplementations (like the simple two-liner above)that rely on disabling preemption.Although it is good to know that there is a simpleconceptual implementation of synchronize_rcu(),other questions remain. For example, what exactlydo RCU readers see when traversing a concurrentlyupdated list? This question is addressed in the followingsection.8.3.1.3 Maintain Multiple Versions of RecentlyUpdated ObjectsThis section demonstrates how RCU maintainsmultiple versions of lists to accommodatesynchronization-free readers. Two examples arepresented showing how an element that might bereferenced by a given reader must remain intactwhile that reader remains in its RCU read-sidecritical section. The first example demonstratesdeletion of a list element, and the second exampledemonstrates replacement of an element.Example 1: Maintaining Multiple VersionsDuring Deletion To start the “deletion” example,we will modify lines 11-21 in Figure 8.12 to readas follows:1,2,3 5,6,7 11,4,8list_del_rcu()1,2,3 5,6,7 11,4,8synchronize_rcu()1,2,3 5,6,7 11,4,8kfree()1,2,3 11,4,8Figure 8.13: RCU Deletion From Linked List1 p = search(head, key);2 if (p != NULL) {3 list_del_rcu(&p->list);4 synchronize_rcu();5 kfree(p);6 }This code will update the list as shown in Figure8.13. The triples in each element represent thevalues of fields a, b, and c, respectively. The redshadedelements indicate that RCU readers mightbe holding references to them. Please note that wehave omitted the backwards pointers and the linkfrom the tail of the list to the head for clarity.After the list_del_rcu() on line 3 has completed,the 5,6,7 element has been removed fromthe list, as shown in the second row of Figure 8.13.Since readers do not synchronize directly with updaters,readers might be concurrently scanning thislist. These concurrent readers might or might notsee the newly removed element, depending on timing.However, readers that were delayed (e.g., dueto interrupts, ECC memory errors, or, in CONFIG_PREEMPT_RT kernels, preemption) just after fetchinga pointer to the newly removed element might seethe old version of the list for quite some time afterthe removal. Therefore, we now have two versions ofthe list, one with element 5,6,7 and one without.The 5,6,7 element is shaded yellow, indicating that

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

Saved successfully!

Ooh no, something went wrong!