a calculus of atomic actions tayfun elmas , shaz qadeer and serdar tasiran popl ‘09

Post on 23-Feb-2016

59 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

A Calculus of Atomic Actions Tayfun Elmas , Shaz Qadeer and Serdar Tasiran POPL ‘09. 236825 – Seminar in Distributed Algorithms Cynthia Disenfeld 27/05/2013. *Some slides are based on those of the authors. Goal. - PowerPoint PPT Presentation

TRANSCRIPT

A Calculus of Atomic ActionsTayfun Elmas, Shaz Qadeer and Serdar TasiranPOPL ‘09

236825 – Seminar in Distributed AlgorithmsCynthia Disenfeld

27/05/2013

*Some slides are based on those of the authors

GoalStatically verifying (partial) correctness of

shared-memory multithreaded programs

Difficult: understand thread-interaction + shared memory

Single-thread programs: pre/post conditions, loop invariants

Multithreaded programs: consider the effect of all thread-interleavings (e.g. Owicki-Gries)

Approach(Sound) program transformations

◦Abstraction◦Reduction

Invariant strengthening

OutlineMotivating examplesApproach – SoundnessReductionAbstractionBorrowing assertionsTacticsExperience / Conclusions

Motivating examples

void inc() { int t; acquire(lock); t := x; t := t+1; x := t; release(lock);}

void inc() { int t; [havoc t; x := x+1;]}

Lock-based atomic increment

Motivating examples

void inc() { int t; while(true){ t := x; if (CAS(x,t,t+1) break; }}

void inc() { int t; while(*){ t := x; assume x!=t; } t := x; [assume x==t; x := t+1];}

Lock-free atomic increment

* Transformation from Flanagan et al.[2005]

Motivating examples

void inc() { int t; while(*){ t := x; assume x!=t; } t := x; [assume x==t; x := t+1];}

void inc() { int t; while (*) { havoc t; skip; } havoc t; [assume x==t; x := t+1];}

Lock-free atomic increment

Motivating examples

void inc() { int t; while (*) { havoc t; skip; } havoc t; [assume x==t; x := t+1];}

void inc() { int t; havoc t; havoc t; [assume x==t; x := t+1];}

Lock-free atomic incrementvoid inc() { int t; [havoc t; x := x+1];}

Motivating examples

void add(int n){ while (0<n) { inc() n := n-1; }}

void add(int n){ while (0<n){ [x := x+1] n := n-1; }}

Client of incvoid add(int n){ [assert 0<=n; x := x+n; n := 0];}

OutlineMotivating examplesApproach – SoundnessReductionAbstractionBorrowing assertionsTacticsExperience / Conclusions

QED approach 1 1 2 2, , ... ,n nP I P I P I

Program InvariantFine-grained concurrencyHard to prove!Invariant = True

Coarse-grained concurrencyEasy to prove

Proof step

If the original program may fail the new program may fail

Soundness

For all

If then exists

If then exists

or

1 2I P P├ 1s I├1

1 errorP

s 2

1 errorP

s

1

1 2

P

s s2

1 2

P

s s

2

1 errorP

s

SoundnessFor each proof step

1 1 2 2, ,P I P I

2 1 2I P P├

Proof steps:•Invariant strengthening•Reduction: build more coarse-grained atomic blocks•Abstraction: add (possibly failing) behaviors

OutlineMotivating examplesApproach – SoundnessReductionAbstractionBorrowing assertionsTacticsExperience / Conclusions

Reduction

inc() { int t; acquire(lock); t := x; t := t+1; x := t; release(lock);}

main() { x := 0; inc(); || inc(); assert(x==2);}

Reduction

inc() { int t; acquire(lock); R t := x; B t := t+1; B x := t; B release(lock); L}

inc() { int t; acquire(lock); t := x; t := t+1; x := t; release(lock); }

inc() x := x+1REDUCE-SEQUENTIAL

Right Mover

Reduction

main() { x := 0; inc(); || inc(); assert(x==2);}

main() { x := 0;B x := x+1; || x := x+1; B assert(x==2);}

main() { x := 0; x := x+1; x := x+1; assert(x==2);}

INLINE-CALL REDUCE-PARALLEL

Static mover check ; ;I ├

Check using the current invariant if they access different variables, or are not enabled at the same time

Each statement consists of:when can it be applied?how is the state changed?

OutlineMotivating examplesApproach – SoundnessReductionAbstractionBorrowing assertionsTacticsExperience / Conclusions

Abstraction ruleReplace with if

I ├For all

If then exists

If then exists

or

1s I├

1 errors 1 errors

1 2s s 1 2s s

1 errors

Abstraction

void inc() { int t; while(*){ t := x; assume x!=t; } t := x; [assume x==t; x := t+1];}

void inc() { int t; while (*) { havoc t; skip; } havoc t; [assume x==t; x := t+1];}

SIMULATE

Then, we can reduce• havoc t + skip • while (*){…} havoc t

AbstractionAdding non-determinism

◦Guards if(*)◦t := x havoc t◦assume … skip

Adding behaviors that may go wrong◦x := x+1 if (x==0) fail; x := x+1◦y := y-x assert (y>x); y := y-x

OutlineMotivating examplesApproach – SoundnessReductionAbstractionBorrowing assertionsTacticsExperience / Conclusions

Example – Sorted linked listHand-over-hand lockingFind, insert, deleteLocal assertionsClass invariantAtomic easy!But… implementation with fine-

grained locking

Insert(5)

Insert(x)p := find(x); //locks pn := p.next;

t := new Node();t.val := x;t.next := n;

p.next := t;assert (p, t, n sorted); //they are linked as they

should and their values have increasing order

UNLOCK(p);

Insert(x)invariant: list is sorted

p := find(x); n := p.next;

t := new Node();t.val := x;t.next := n;

p.next := t;assert (p, t, n sorted);

UNLOCK(p);

p.val and p.next are not affected by other

threads

t.val and t.next are not affected by other

threads

Proof 1 1 2 2, , ... ,n nP I P I P I

p := find(x); n := p.next;

t := new Node();t.val := x;t.next := n;

p.next := t;assert (p, t, n sorted);

UNLOCK(p);

find appropriate pLOCK(p)n := p.next;

t := new Node(); Rt.val := x;t.next := n;

p.next := t;assert (p, t, n sorted);

UNLOCK(p); L

Proof 1 1 2 2, , ... ,n nP I P I P I

find appropriate pLOCK(p)n := p.next;

t := new Node(); Rt.val := x;t.next := n;

p.next := t;assert (p, t, n sorted);

UNLOCK(p); L

find appropriate pLOCK(p)n := p.next;

t := new Node();t.val := x;t.next := n;

p.next := t;assert (p, t, n sorted);

UNLOCK(p);

how to continue?

Apparent interferencep.next := t;

p.next := t;

n := p.next;

n := p.next;

Thread A Thread B

Apparent interferencep.next := t;

p.next := t;

n := p.next;

n := p.next;

Thread A Thread B

But: both p’s are locked!

Ruling out interference - 1assert owner[p]==Ap.next := t;

assert owner[p]==Ap.next := t;

assert owner[p]==Bn := p.next;

assert owner[p]==Bn := p.next;

Thread A Thread B

Ruling out interference - 2assert !inList[t]t.next := n;

assert !inList[t]t.next := n;

assert inList[p]n := p.next;

assert inList[p]n := p.next;

Thread A Thread B

Reduction after abstraction

find appropriate pLOCK(p)

assert inList[p]&&owner[p]==tidn := p.next;t := new Node(); t.val := x;assert !inList[t]t.next := n;assert inList[p]&&owner[p]==tidp.next := t;assert (p, t, n sorted); assert owner[p]==tidUNLOCK(p);

find appropriate pLOCK(p)

assert inList[p]&&owner[p]==tidn := p.next;t := new Node(); t.val := x;assert !inList[t]t.next := n;assert inList[p]&&owner[p]==tidp.next := t;assert (p, t, n sorted); assert owner[p]==tidUNLOCK(p);

Borrowed assertionsfind appropriate pLOCK(p)

assert inList[p]&&owner[p]==tidn := p.next;t := new Node(); t.val := x;assert !inList[t]t.next := n;assert inList[p]&&owner[p]==tidp.next := t;assert (p, t, n sorted); assert owner[p]==tidUNLOCK(p);

find appropriate pLOCK(p)

assert inList[p]&&owner[p]==tidn := p.next;t := new Node(); t.val := x;assert !inList[t]t.next := n;assert inList[p]&&owner[p]==tidp.next := t;assert (p, t, n sorted); assert owner[p]==tidUNLOCK(p);

Completing the prooffind appropriate pLOCK(p)

n := p.next;

t := new Node(); t.val := x;t.next := n;

p.next := t;assert (p, t, n sorted); UNLOCK(p);

Invariant : List is sorted

OutlineMotivating examplesApproach – SoundnessReductionAbstractionBorrowing assertionsTacticsExperience / Conclusions

TacticsHigh-level strategies multiple

rule proofs◦abstract from a read, write◦add invariants◦synchronization mechanisms

inc() { int t; acquire(lock); t := x; t := t+1; x := t; release(lock);}

Example

acquire(lock) { assume lock==false; lock := true;}

release(lock) { lock := false;}

mutex P, x1, … , xn

mutex (lock==true), x

Tactic - mutexinc() { int t; acquire(lock); a=tid; t := x; t := t+1; x := t; release(lock); a=0;}

AUX-ANNOTATE

Invariant: lock==true iff a !=0

Tactic - mutexinc() { int t; acquire(lock); a=tid; t := x; t := t+1; x := t; release(lock); a=0;}

SIMULATE

inc() { int t; acquire(lock); a=tid; assert a==tid;t := x; t := t+1; assert a==tid;x := t; assert a==tid; release(lock); a=0;}

Tactic - mutexinc() { int t; acquire(lock); a=tid; R assert a==tid;t := x; B t := t+1; B assert a==tid;x := t; B assert a==tid; release(lock); a=0; L}

Tactic - mutex

REDUCE & RELAX

inc() { int t; acquire(lock); a=tid; assert a==tid; t := x; t := t+1; assert a==tid; x := t; assert a==tid; release(lock); a=0; }

OutlineMotivating examplesApproach – SoundnessReductionAbstractionBorrowing assertionsTacticsExperience / Conclusions

ExperienceImplementation

◦Boogie + parallel composition◦Verification conditions for validity of

each step: Z3 SMT SolverBenchmarks without complicated

global invariantsFine-grained locking

◦Multiset◦Hand-over-hand locking

Non-blocking algorithms

Future workMore tacticsMore synchronization

mechanismsC / Spec#Larger verification problems

ConclusionsA formal and sound proof calculus for

atomicity was presented Abstraction helps applying reduction

and the other way aroundAssertions can be added and checked

only laterThe program is simplified by obtaining

coarser atomic actionsTactics can be defined to represent

different synchronization mechanisms

top related