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.

300 APPENDIX F. ANSWERS TO QUICK QUIZZES1 idx = srcu_read_lock(&ssa);2 synchronize_srcu(&ssb);3 srcu_read_unlock(&ssa, idx);45 /* . . . */67 idx = srcu_read_lock(&ssb);8 synchronize_srcu(&ssa);9 srcu_read_unlock(&ssb, idx);Figure F.6: Multistage SRCU DeadlocksQuick Quiz 8.31:Why doesn’t list_del_rcu() poison both the nextand prev pointers?Answer:Poisoning the next pointer would interfere withconcurrent RCU readers, who must use this pointer.However, RCU readers are forbidden from using theprev pointer, so it may safely be poisoned.Quick Quiz 8.32:Normally, any pointer subject to rcu_dereference() must always be updated usingrcu_assign_pointer(). <strong>What</strong> is an exception tothis rule?Answer:One such exception is when a multi-elementlinked data structure is initialized as a unitwhile inaccessible to other CPUs, and then asingle rcu_assign_pointer() is used to planta global pointer to this data structure. Theinitialization-time pointer assignments need not usercu_assign_pointer(), though any such assignmentsthat happen after the structure is globallyvisible must use rcu_assign_pointer().However, unless this initialization code is on animpressively hot code-path, it is probably wise touse rcu_assign_pointer() anyway, even though itis in theory unnecessary. <strong>It</strong> is all too easy for a”minor”changetoinvalidateyourcherishedassumptionsabout the initialization happening privately.Quick Quiz 8.33:Are there any downsides to the fact that thesetraversal and update primitives can be used withany of the RCU API family members?Answer:<strong>It</strong> can sometimes be difficult for automated codecheckers such as “sparse” (or indeed for humanbeings) to work out which type of RCU read-sidecritical section a given RCU traversal primitivecorresponds to. For example, consider the codeshown in Figure F.7.1 rcu_read_lock();2 preempt_disable();3 p = rcu_dereference(global_pointer);45 /* . . . */67 preempt_enable();8 rcu_read_unlock();Figure F.7: Diverse RCU Read-Side Nesting<strong>Is</strong> the rcu_dereference() primitive in an RCUClassic or an RCU Sched critical section? <strong>What</strong>would you have to do to figure this out?Quick Quiz 8.34:Why wouldn’t any deadlock in the RCU implementationin Figure 8.27 also be a deadlock in any otherRCU implementation?Answer:Suppose the functions foo() and bar() in FigureF.8 are invoked concurrently from differentCPUs. Thenfoo()willacquiremy_lock()online3,while bar() will acquire rcu_gp_lock on line 13.When foo() advances to line 4, it will attempt toacquire rcu_gp_lock, which is held by bar(). Then1 void foo(void)2 {3 spin_lock(&my_lock);4 rcu_read_lock();5 do_something();6 rcu_read_unlock();7 do_something_else();8 spin_unlock(&my_lock);9 }1011 void bar(void)12 {13 rcu_read_lock();14 spin_lock(&my_lock);15 do_some_other_thing();16 spin_unlock(&my_lock);17 do_whatever();18 rcu_read_unlock();19 }Figure F.8: Deadlock in Lock-Based RCU Implementation

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

Saved successfully!

Ooh no, something went wrong!