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.

E.7. PROMELA PARABLE: DYNTICKS AND PREEMPTABLE RCU 2617 curr = per_cpu(dynticks_progress_counter, cpu);8 snap = per_cpu(rcu_dyntick_snapshot, cpu);9 smp_mb();10 if ((curr - snap) >= 2 || (curr & 0x1) == 0)11 return 0;12 return 1;13 }Making the corresponding correction in the model(dyntickRCU-base-sl.spin) results in a correctverification with 661 states that passes without errors.However, it is worth noting that the first versionof the liveness verification failed to catch thisbug, due to a bug in the liveness verification itself.This liveness-verification bug was located by insertingan infinite loop in the grace_period() process,and noting that the liveness-verification code failedto detect this problem!We have now successfully verified both safety andliveness conditions, but only for processes runningand blocking. We also need to handle interrupts, atask taken up in the next section.E.7.2.4 InterruptsThere are a couple of ways to model interrupts inPromela:1. using C-preprocessor tricks to insert the interrupthandler between each and every statementof the dynticks_nohz() process, or2. modeling the interrupt handler with a separateprocess.A bit of thought indicated that the second approachwould have a smaller state space, thoughit requires that the interrupt handler somehowrun atomically with respect to the dynticks_nohz() process, but not with respect to the grace_period() process.Fortunately, it turns out that Promela permitsyou to branch out of atomic statements. This trickallowsustohavetheinterrupthandlersetaflag, andrecode dynticks_nohz() to atomically check thisflag and execute only when the flag is not set. Thiscan be accomplished with a C-preprocessor macrothat takes a label and a Promela statement as follows:1 #define EXECUTE_MAINLINE(label, stmt) \2 label: skip; \3 atomic { \4 if \5 :: in_dyntick_irq -> goto label; \6 :: else -> stmt; \7 fi; \8 } \One might use this macro as follows:EXECUTE_MAINLINE(stmt1,tmp = dynticks_progress_counter)Line 2 of the macro creates the specified statementlabel. Lines 3-8 are an atomic block that teststhe in_dyntick_irq variable, and if this variable isset (indicating that the interrupt handler is active),branches out of the atomic block back to the label.Otherwise, line 6 executes the specified statement.The overall effect is that mainline execution stallsany time an interrupt is active, as required.E.7.2.5 Validating Interrupt HandlersThe first step is to convert dyntick_nohz() toEXECUTE_MAINLINE() form, as follows:1 proctype dyntick_nohz()2 {3 byte tmp;4 byte i = 0;5 bit old_gp_idle;67 do8 :: i >= MAX_DYNTICK_LOOP_NOHZ -> break;9 :: i < MAX_DYNTICK_LOOP_NOHZ ->10 EXECUTE_MAINLINE(stmt1,11 tmp = dynticks_progress_counter)12 EXECUTE_MAINLINE(stmt2,13 dynticks_progress_counter = tmp + 1;14 old_gp_idle = (grace_period_state == GP_IDLE);15 assert((dynticks_progress_counter & 1) == 1))16 EXECUTE_MAINLINE(stmt3,17 tmp = dynticks_progress_counter;18 assert(!old_gp_idle ||19 grace_period_state != GP_DONE))20 EXECUTE_MAINLINE(stmt4,21 dynticks_progress_counter = tmp + 1;22 assert((dynticks_progress_counter & 1) == 0))23 i++;24 od;25 dyntick_nohz_done = 1;26 }<strong>It</strong> is important to note that when a group ofstatements is passed to EXECUTE_MAINLINE(), as inlines 11-14, all statements in that group executeatomically.Quick Quiz E.14: But what would you do ifyou needed the statements in a single EXECUTE_MAINLINE() group to execute non-atomically?Quick Quiz E.15: But what if the dynticks_nohz() process had “if” or “do” statements withconditions, where the statement bodies of these constructsneeded to execute non-atomically?Thenextstepistowriteadyntick_irq()processto model an interrupt handler:1 proctype dyntick_irq()2 {3 byte tmp;4 byte i = 0;5 bit old_gp_idle;67 do8 :: i >= MAX_DYNTICK_LOOP_IRQ -> break;9 :: i < MAX_DYNTICK_LOOP_IRQ ->10 in_dyntick_irq = 1;

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

Saved successfully!

Ooh no, something went wrong!