760 likes | 927 Views
Separation Logic and Concurrency Verification. Xinyu Feng ( 冯新宇 ) University of Science and Technology of China. Why concurrency verification. Concurrent programs show in many systems Multi-task support in OS kernels Handling interrupts from external devices … Will be more common
E N D
Separation Logic and Concurrency Verification Xinyu Feng (冯新宇) University of Science and Technology of China
Why concurrency verification • Concurrent programs show in many systems • Multi-task support in OS kernels • Handling interrupts from external devices • … • Will be more common • Multi-core processors • Intellectually interesting • Correctness/incorrectness are not obvious
Shared-State Concurrency Model B A Memory
T1: T2: [ 100 ] := 3 [ 100 ] := 5 100 101 100 Execution Model: Simple Examples T1: T2: [ 100 ] := 3 [ 101 ] := 5 3 5 3/5 Don’t know which one is written first, but order doesn’t matter. Order may affect the result if threads share resources.
Execution Model: Simple Examples It is difficult to discuss resource sharing with memory pointer aliasing. T1: T2: [ x ] := 3 [ y ] := 5 x x y y 3/5 3 5
T1 T2 T1 T2 T1 T2 T1: T2: C11; C21; C12; C22; C1n C2n Execution Model: Simple Examples Non-deterministic interleaving may produce exponential num. of execution traces; Different traces may lead to different results (depends on the resource sharing).
Challenges to reason about concurrent programs • Sharing of resources makes the result dependent on the ordering of execution • Non-deterministic interleaving produces exponential num. of possible ordering • Memory pointer aliasing makes it difficult to tell how resources are shared
Outline of this Lecture • Separation Logic • Concurrent Separation Logic (CSL) • Extension of CSL to handle Interrupts
Separation Logic [Ishtiaq&O’Hearn’01,Reynolds’02] A Hoare-style program logic: { p } C { q } What’s new here is the assertion language.
emp empty heap l n l n pq p q p q pq Separation Logic Assertions
emp empty heap l n pq p q Separation Logic Assertions l n l_ defined as n.l n ln defined as (ln) true n l
pp p ptrue p Properties pemp p pq qp pp p ptrue p (l_)(l_) false p ptrue
{(l_)} {emp} [l] := m; [l] := m; {(lm)} {???} Ownership cannot be duplicated:(l_) (l_)(l_) Assertions Model Ownership
{(xn) (yn)} {(xn) (yn)} [x] := m; [x] := m; {(xm) (yn)} {(xm) (yn)} Strength of Separation what if x=y ?
r p C r q A Frame Rule for Modularity { p } C { q } { p r} C { q r} Another example showing the strength of separation!
top … Specification of a List List (top) (top = null) emp next. top (_, next) List ( next ).
{ List (top) } { List (top) top null } { next. top (_, next) List ( next ) } { r1 = top next. top (_, next) List ( next ) r2 = next } { r1 (_, _) List ( r2 ) } { r1 (_, _) List ( top ) } { List ( top ) * (top = r1 = null emp r1 (_, _)) } Example: getNode getNode() if (top <> null){ r1 = top; r2 = top.next; top = r2; } else {r1 = null }
Reading Materials See the miniCourse webpage of John Reynolds: http://www.cs.cmu.edu/~jcr/
Outline of This Lecture • Separation Logic • Concurrent Separation Logic (CSL) • Extension of CSL to handle Interrupts
T1: T2: [ 100 ] := 3 [ 100 ] := 5 100 101 100 Separation Logic for Concurrency T1: T2: [ 100 ] := 3 [ 101 ] := 5 3 5 3/5 Separation is an effective way to control interference.
p q {p q} C1 || C2 {p' q'} Concurrent Separation Logic (CSL) [O’Hearn 2004] Key ideas: Threads can only access disjoint resources at the same time. pq {p} C1 {p'} {q} C2 {q'} C1 and C2 are verified as sequential programs But how to allow threads to share resources?
Invariants about memory protected by locks: l1 ln = {l1 r1, …, ln rn} r1 rn Locks and Critical Regions Lock-based critical regions (CR): l.acq(); … … … … l.rel() Note: different locks protect disjoint resources.
p q l1 ln r1 rn Concurrent Separation Logic (CSL) ┝ {p} C1 {p'} ┝ {q} C2 {q'} ┝ {p q} C1 || C2 {p' q'} Memory Model:
p1’ CSL (cont’d) p1 p2 p2 r p1 r p2 p1’ r p2 p2 p2 r Each thread can freely access to its local resource.
p1 r p2 C l.rel(); CSL (cont’d) p1 p2 p2 r p1 r p2 l.acq(); Suppose (l) = r
p1’ r p2 CSL (cont’d) p1 p2 p2 r p1 r p2 l.acq(); p1 r p2 C l.rel()
p1’ r p2 p1’ r p2 CSL (cont’d) p1 p2 p2 r p1 r p2 l.acq(); p1 r p2 C l.rel();
CSL (cont’d) Reasoning about lock acquire/release: ┝ {emp} l.acq() { (l) } Acquiring the lock means getting the ownership of the lock-protected resource. (l) is transferred from shared to local.
CSL (cont’d) The rule does not support reentrant locks: ┝ {emp} l.acq() { (l) } {emp} l.acq() {(l)} l.acq() {(l) (l)}
CSL (cont’d) Reasoning about lock acquire/release: ┝ { (l) } l.rel() { emp } Before releasing the lock, the corresponding resource needs to be well-formed. Releasing the lock means losing the ownership of the resource (which is transferred from local to shared).
CSL (cont’d) Reasoning about lock acquire/release: ┝ {emp} l.acq() { (l) } ┝ { (l) } l.rel() { emp } We call this ownership-transfer axiomatic semantics of locks
r top … Example: List top … = { lList(top) } getNode(): l.acq(); … l.rel(); -{emp} -{emp * List(top)}; -{r(_,_) * List(top)} -{r(_,_)} Sequential verification
Outline of This Lecture • Separation Logic • Concurrent Separation Logic (CSL) • Extension of CSL to handle Interrupts
Layering of OS Code B: concurrent code with explicit interrupts How to certify ???
l 0/1 timer_0: ... switch ... iret … [l] :=1;… Example: Spinlocks (uniprocessor) acquire (l): cli; while([l] == 0){ sti; cli; } [l] := 0; sti; return; // disable Interrupt // lock is taken by others
l 0/1 Example: Spinlocks (uniprocessor) acquire (l): cli; while([l] == 0){ sti; cli; } [l] := 0; sti; return; // lock available // acquire lock // enable Interrupt
IR0 IR1 Concurrency with Interrupts: Challenges Asymmetric preemption between handlers and non-handler code Intertwining between threads and handlers Asymmetric synchronization: cli/sti are different from locks
Study the problem in 3 steps • Interrupts with Sequential Programs • Interrupts with Multi-threaded Programs • Adding block/unblock primitives
AIM – I : The Machine (data heap) H f1: I1 pc addu … cli sti iret … j f 0 1 2 … f2: I2 r1 r2 r3 … rn ih: ISR (register file) R ie … (code heap) C (state) S ::=(H,R,ie) ::={fI}* (program) P ::=(C,S,pc)
Example: Teeter-Totter right left 50 50 timer: if([left] == 0){ print(“right wins!”); iret; } [left] := [left]-1; [right] := [right]+1; iret; while([right] != 0){ cli; [right] := [right]-1; [left] := [left]+1; sti; } print(“left wins!”); Which side wins depends on how frequently the timer interrupt comes.
Wellformedness of A; Protocol for sharing AIM – I : The Memory Model INV B A Memory sti … iret cli … Non-handler Handler
INV cli B B sti B A B B INV INV AIM – I : cli/sti INV B A critical region B ie = 1 ie = 0
Ownership Transfer Semantics for cli/sti ┝ {ie=1} cli {ie=0 INV } ┝ {ie=0 INV} sti {ie=1}
INV irq B A iret B A B A INV INV AIM – I : handler INV B A ie = 1 ie = 0
Example: Teeter-Totter right left INV: m, n. (left m) (right n) (m+n = 100) m n while(!done){ -{ie=1} cli; -{ie=0 INV} [right] := [right]-1; [left] := [left]+1; done := ([right] == 0); -{ie=0 INV} sti; -{ie=1} } timer: -{INV} if([left] == 0){ print(“right wins!”); -{INV} iret; } [left] := [left]-1; [right] := [right]+1; -{INV} iret;
… R R R pc pc pc (ready. queue) Q AIM – II : The Machine (data heap) H f1: I1 0 1 2 … f2: I2 pc cli sti … switch j f r1 r2 r3 … rn ih: ISR (register file) R ie … (code heap) C (state) S ::=(H,R,ie) ::={fI}* (program) P ::=(C,S,Q,pc)
AIM – II : switch • A primitive implemented at layer C • Interrupt must be disabled before executing switch • Operational semantics: • Put the current thread into ready Q • Resume a thread in Q(non-deterministic op)
Example: spin locks acquire (l): cli; while([l] == 0){ sti; cli; } [l] := 0; sti; return; release (l): cli; [l] := 1; sti; return; switch
Layer A: timer_0: ... switch ... iret yield: cli switch sti ret ie = 0: non-preemptive threads ie = 1 & timer_1: non-preemptive threads ie = 1 & timer_0: preemptive threads timer_1: ... iret Examples