Simplifying Linearizability Proofs Using Reduction and Abstraction Serdar Tasiran Koc University, Istanbul, Turkey Tayfun Elmas, Ali Sezgin, Omer Subasi.

Slides:



Advertisements
Similar presentations
Bounded Model Checking of Concurrent Data Types on Relaxed Memory Models: A Case Study Sebastian Burckhardt Rajeev Alur Milo M. K. Martin Department of.
Advertisements

Technologies for finding errors in object-oriented software K. Rustan M. Leino Microsoft Research, Redmond, WA Lecture 1 Summer school on Formal Models.
Automated Theorem Proving Lecture 1. Program verification is undecidable! Given program P and specification S, does P satisfy S?
The many faces of TM Tim Harris. Granularity Distributed, large-scale atomic actions Composable shared memory data structures Leaf shared memory data.
Introduction to Proofs
QED: A Simplifier for Concurrent Programs Shaz Qadeer Microsoft Research Joint work with Tayfun ElmasAli SezginSerdar Tasiran.
Hongjin Liang and Xinyu Feng
Semantics Static semantics Dynamic semantics attribute grammars
A Program Transformation For Faster Goal-Directed Search Akash Lal, Shaz Qadeer Microsoft Research.
Architecture-aware Analysis of Concurrent Software Rajeev Alur University of Pennsylvania Amir Pnueli Memorial Symposium New York University, May 2010.
Verifying Executable Object-Oriented Specifications with Separation Logic Stephan van Staden, Cristiano Calcagno, Bertrand Meyer.
Reduction, abstraction, and atomicity: How much can we prove about concurrent programs using them? Serdar Tasiran Koç University Istanbul, Turkey Tayfun.
Goldilocks: Efficiently Computing the Happens-Before Relation Using Locksets Tayfun Elmas 1, Shaz Qadeer 2, Serdar Tasiran 1 1 Koç University, İstanbul,
1 1 Regression Verification for Multi-Threaded Programs Sagar Chaki, SEI-Pittsburgh Arie Gurfinkel, SEI-Pittsburgh Ofer Strichman, Technion-Haifa Originally.
Model-based reasoning meets code verification Michael Butler 21 May 2014 WG 2.3 Meeting 55, Orlando.
A simple sequential reasoning approach for sound modular verification of mainstream multithreaded programs Wolfram Schulte & Bart Jacobs Microsoft Research.
1 Eran Yahav Technion Joint work with Martin Vechev (ETH), Greta Yorsh (ARM), Michael Kuperstein (Technion), Veselin Raychev (ETH)
Silberschatz, Galvin and Gagne ©2009 Operating System Concepts – 8 th Edition, Chapter 6: Process Synchronization.
1 Partial Order Reduction. 2 Basic idea P1P1 P2P2 P3P3 a1a1 a2a2 a3a3 a1a1 a1a1 a2a2 a2a2 a2a2 a2a2 a3a3 a3a3 a3a3 a3a3 a1a1 a1a1 3 independent processes.
/ PSWLAB Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs By Cormac Flanagan, Stephen N. Freund 24 th April, 2008 Hong,Shin.
Verifying Concurrent Programs with Relaxed Conflict Detection Tayfun Elmas, Ismail Kuru, Serdar Taşıran, Omer Subasi Koç University Istanbul, Turkey.
Generalizing Reduction and Abstraction to Simplify Concurrent Programs: The QED Approach Shaz Qadeer Microsoft Research Redmond, WA Serdar Taşıran Serdar.
A Semantic Characterization of Unbounded-Nondeterministic Abstract State Machines Andreas Glausch and Wolfgang Reisig 1.
1 Operational Semantics Mooly Sagiv Tel Aviv University Textbook: Semantics with Applications.
Katz Formal Specifications Larch 1 Algebraic Specification and Larch Formal Specifications of Complex Systems Shmuel Katz The Technion.
Modular Verification of Multithreaded Software Shaz Qadeer Compaq Systems Research Center Shaz Qadeer Compaq Systems Research Center Joint work with Cormac.
Operational Semantics Semantics with Applications Chapter 2 H. Nielson and F. Nielson
Comparison Under Abstraction for Verifying Linearizability Daphna Amit Noam Rinetzky Mooly Sagiv Tom RepsEran Yahav Tel Aviv UniversityUniversity of Wisconsin.
Compositional Verification of Termination-Preserving Refinement of Concurrent Programs Hongjin Liang Univ. of Science and Technology of China (USTC) Joint.
Thread Quantification for Concurrent Shape Analysis Josh BerdineMSR Cambridge Tal Lev-AmiTel Aviv University Roman ManevichTel Aviv University Mooly Sagiv.
Runtime Refinement Checking of Concurrent Data Structures (the VYRD project) Serdar Tasiran Koç University, Istanbul, Turkey Shaz Qadeer Microsoft Research,
Verifying Concurrent Programs with Relaxed Conflict Detection Tayfun Elmas, Ismail Kuru, Serdar Taşıran, Omer Subasi Koç University Istanbul, Turkey.
Art of Multiprocessor Programming 1 Programming Paradigms for Concurrency Pavol Černý, Vasu Singh, Thomas Wies.
Eran Yahav 1. Previously…  An algorithmic view  Abstract data types (ADT)  Correctness Conditions  Sequential consistency  Linearizability  Treiber’s.
11/18/20151 Operating Systems Design (CS 423) Elsa L Gunter 2112 SC, UIUC Based on slides by Roy Campbell, Sam.
Concurrent Linked Lists and Linearizability Proofs Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit Modified.
Chapter 3 Part II Describing Syntax and Semantics.
Automated and Modular Refinement Reasoning for Concurrent Programs Shaz Qadeer.
Lecture 5 1 CSP tools for verification of Sec Prot Overview of the lecture The Casper interface Refinement checking and FDR Model checking Theorem proving.
Program Logic for Concurrency Refinement Verification Xinyu Feng University of Science and Technology of China Joint work with Hongjin Liang (USTC) and.
Types and Programming Languages Lecture 11 Simon Gay Department of Computing Science University of Glasgow 2006/07.
Understanding ADTs CSE 331 University of Washington.
This Week Lecture on relational semantics Exercises on logic and relations Labs on using Isabelle to do proofs.
Operational Semantics Mooly Sagiv Tel Aviv University Textbook: Semantics with Applications Chapter.
/ PSWLAB Thread Modular Model Checking by Cormac Flanagan and Shaz Qadeer (published in Spin’03) Hong,Shin Thread Modular Model.
A Compositional Method for Verifying Software Transactional Memory Implementations Serdar Tasiran Koç University Istanbul, Turkey Thanks: Rustan Leino,
A Calculus of Atomic Actions Tayfun Elmas, Shaz Qadeer and Serdar Tasiran POPL ‘ – Seminar in Distributed Algorithms Cynthia Disenfeld 27/05/2013.
Faithful mapping of model classes to mathematical structures Ádám Darvas ETH Zürich Switzerland Peter Müller Microsoft Research Redmond, WA, USA SAVCBS.
Verifying Transactional Programs with Programmer-Defined Conflict Detection Omer Subasi, Serdar Tasiran (Koç University) Tim Harris (Microsoft Research)
Operational Semantics Mooly Sagiv Tel Aviv University Sunday Scrieber 8 Monday Schrieber.
Agenda  Quick Review  Finish Introduction  Java Threads.
Operational Semantics Mooly Sagiv Reference: Semantics with Applications Chapter 2 H. Nielson and F. Nielson
Operational Semantics Mooly Sagiv Reference: Semantics with Applications Chapter 2 H. Nielson and F. Nielson
A Calculus of Atomic Actions Serdar Tasiran Koc University, Istanbul, Turkey Tayfun ElmasShaz Qadeer Koc University Microsoft Research.
Lecture 5 Page 1 CS 111 Summer 2013 Bounded Buffers A higher level abstraction than shared domains or simple messages But not quite as high level as RPC.
CS 326 Programming Languages, Concepts and Implementation
Joint work with Yong Li, Xinyu Feng, Zhong Shao and Yu Zhang
Verification of Concurrent Programs
Stateful Manifest Contracts
Threads and Memory Models Hal Perkins Autumn 2011
Logical architecture refinement
Progress of Concurrent Objects with Partial Methods
Over-Approximating Boolean Programs with Unbounded Thread Creation
Threads and Memory Models Hal Perkins Autumn 2009
Semantics In Text: Chapter 3.
VyrdMC: Driving Runtime Refinement Checking Using Model Checkers
Serdar Tasiran, Tayfun Elmas Koç University, Istanbul, Turkey
CSE 153 Design of Operating Systems Winter 19
Tayfun Elmas, Serdar Tasiran Koç University, Istanbul, Turkey
Tayfun Elmas, Serdar Tasiran Koç University, Istanbul, Turkey
Presentation transcript:

Simplifying Linearizability Proofs Using Reduction and Abstraction Serdar Tasiran Koc University, Istanbul, Turkey Tayfun Elmas, Ali Sezgin, Omer Subasi (Koc University) Shaz Qadeer (Microsoft Research)

The QED Proof System Assertions difficult to verify Fine-grain concurrency Annotations at every interleaving point Assertions easy to verify Larger atomic blocks Local, sequential analysis within atomic blocks Impl 2 Impl 1 Impl n Original implementation Transformed implementation reduce abstract

Overview Proof system for proving linearizability, refinement – Builds on QED: Proof system for verifying assertions [WG 2.3 Mtg. 50, POPL’09] New proof rule: Variable hiding – Implementation in QED-verifier Demonstrated on – Lock-coupling linked list [Vafeiadis, PPoPP’06] – Treiber’s non-blocking stack [Treiber, 1986] – Non-blocking and two-lock queues [Michael, Scott, PODC’96] – Writer mode of readers/writer lock [Krieger et.al., ICPP’93] 3

The multiset data structure Collection of integer with multiplicities: {2, 2, 3, 4, 4, 4, 5} Operations – LookUp(x: int) returns (r: bool) If x is in multiset then r == true, otherwise r == false – InsertPair(x: int, y: int) returns (r: bool) Inserts both x and y and returns r == true Inserts nothing and returns r == false Verification goal: Show that a concurrent implementation of multiset is linearizable to a sequential specification of multiset. 4

Multiset specification var Spec: map[int -> int]; // Spec[x] == how many x’s? atomic LOOKUP(x:int) returns (r:bool) { r := (Spec[x] > 0); } atomic INSERTPAIR(x:int, y:int) returns (r:bool) { r := nonDetBool(); if (r == true) { Spec[x] := Spec[x] + 1; Spec[y] := Spec[y] + 1; } 5

Multiset implementation 6 LookUp(x:int) returns(r:bool) r := false; for each slot Impl[i] { lock(Impl[i]); r := (Impl[i].elt == x && Impl[i].stt == full); unlock(Impl[i]); if (r == true) return; } Specification: atomic LOOKUP(x:int) returns (r:bool) { r := (Spec[x] > 0); } 4 full - empty 9 full 4 - reserved 3 full 9 reserved var Impl: array[int] of Slot; elt stt {4, 9, 4, 3}

7 InsertPair(x:int, y:int) returns (r:bool) i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; Reserve slots 2. Insert numbers 3. Insert logically - reserved... - reserved - empty... - empty y reserved... x reserved y full... x full i j i j i j i j

Multiset implementation 8 FindSlot(x:int) returns(k:int) k := -1; for each slot Impl[i] { lock(Impl[i]); if (Impl[i].stt == empty) Impl[i].stt = reserved; k := i; return; unlock(Impl[i]); } 4 full - empty 9 full 4 - reserved 3 full 9 reserved var Impl: array[int] of Slot; elt stt {4, 9, 4, 3}

9 InsertPair(x:int, y:int) returns(r:bool) i := FindSlot(); if (i == -1) { r := false; return;} j := FindSlot(); if (j == -1) {Impl[i].stt := empty; r: false; return;} Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true;

Linearizability: Definition 10 A concurrent history call InsertPair(3,5) InsertPair(3,5) returns true call LookUp(5) call LookUp(4) LookUp(4) returns true LookUp(5) returns false Time

Linearizability 11 A sequential history, consistent with sequential specification for data structure call InsertPair(3,5) InsertPair(3,5) returns true call LookUp(5) call LookUp(4) LookUp(4) returns true LookUp(5) returns false

Linearizability 12 A concurrent history call InsertPair(3,5) InsertPair(3,5) returns true call LookUp(5) call LookUp(4) LookUp(4) returns true LookUp(5) returns false Time

Linearizability 13 Concurrent implementation history call InsertPair(3,5) InsertPair(3,5) returns true call LookUp(5) call LookUp(4) LookUp(4) returns true LookUp(5) returns false call InsertPair(3,5) InsertPair(3,5) returns true call LookUp(5) call LookUp(4) LookUp(4) returns true LookUp(5) returns false ≈ Sequential specification history

Linearizability 14 Concurrent implementation history call InsertPair(3,5) InsertPair(3,5) returns true call LookUp(5) call LookUp(4) LookUp(4) returns true LookUp(5) returns false call InsertPair(3,5) InsertPair(3,5) returns true call LookUp(5) call LookUp(4) LookUp(4) returns true LookUp(5) returns false ≈ Sequential specification history Equivalence: -Per-thread order of actions preserved -Order of non-overlapping operations preserved -Same call and return values E

15 s0s0 s1s1 s2s2 s3s3 Abs s4s4 s5s5 s6s6 s7s7 s8s8 s9s9 q 0 = Abs(s 0 ) q 1 = Abs(s 3 ) q 1 = Abs(s 4 ) q0q0 q 0 = Abs(s 2 ) Abs q 2 = Abs(s 5 ) q 2 = Abs(s 7 ) q2q2 q 3 = Abs(s 8 ) q3q3 For concurrent data structures, model the implementation and spec as state transition systems Spec: A data structure with atomic operations An abstraction function Abs maps each implementation state to a spec state Refinement: For each execution of the implementation its image under Abs is an execution of the specification Refinement between two state-transition systems

16 s0s0 s1s1 s2s2 s3s3 s4s4 s5s5 s6s6 s7s7 s8s8 s9s9 q 0 = Abs(s 0 ) q 1 = Abs(s 3 ) q 1 = Abs(s 4 ) q0q0 q 0 = Abs(s 2 ) q 2 = Abs(s 5 ) q 2 = Abs(s 7 ) q2q2 q 3 = Abs(s 8 ) q3q3 Linearizability can be formulated as a special case of refinement – A set V of variables store operation arguments, return values – Abs leaves variables in V unchanged For each implementation execution E I, there is a spec execution E S such that – The projections of E I and E S onto V are the same If all spec operations are atomic, this leads to a linearizability proof. Abs

Proving refinement between two transition systems Revised goal: Prove refinement – Method 1: Pick arbitrary execution of implementation, use abstraction map, prove that mapped execution is allowed by spec – Method 2: Work on implementation and spec program text Prove refinement relation using proof system (QED + new rules) Fine-grain atomic actions in implementation make both methods hard Next: – Illustrate this difficulty on multiset Rest of talk: – Address this difficulty 17

Refinement proof difficulties Reasonable first guess at abstraction map Abst: Impl  Spec x. Spec[x] == |{ k | 0 <= k < N && Impl[k].elt == x && Impl[k].stt == full }| Abstraction map should update spec state once per operation instance – The “commit action” of the operation 18

Refinement proof cartoon 19 call INSERTPAIR(4,5) returns true call INSERTPAIR(4,5) returns true call LOOKUP(5) returns false call LOOKUP(5) returns false call LOOKUP(4) returns true Implementation trace Specification trace ≈ call InsertPair(3,5) InsertPair(3,5) returns true call LookUp(5) call LookUp(4) LookUp(4) returns true LookUp(5) returns false commit Time

20 Commit action: InsertPair(x:int, y:int) returns (r:bool) i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; Proof obligations: 1. Non-commit actions do not change abstract state Abst(Impl after ) == Abst(Impl before ) 2. Commit action updates abstract state atomically (According to INSERTPAIR specification) Abst(Impl after )[x] == Abst(Impl before )[x] + 1 Abst(Impl after )[y] == Abst(Impl before )[y] + 1

21 Abstraction function attempt: Spec[x] == |{ k | 0 <= k < N && Impl[k].elt == x && Impl[k].stt == full }| Spec[x] incremented: Spec[y] incremented: InsertPair(x:int, y:int) returns (r:bool) i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; Not good! Abstract state updated more than once.

22 Abstraction function: Spec[x] == |{ k | 0 <= k < N && Impl[k].elt == x && Impl[k].stt == full && !Locked(Impl[k]) }| Spec[x] incremented BUT NOT Spec[y] ! Spec[x] NOT incremented : Spec[y] NOT incremented : InsertPair(x:int, y:int) returns (r:bool) i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true;

23 Abstraction function: Spec[x] == |{ k | 0 <= k < N && Impl[k].elt == x && Impl[k].stt == full && (!Locked(Impl[k]) || LockerAtLine(Impl[k],10)) }| Spec[x] and Spec[y] incremented atomically InsertPair(x:int, y:int) returns (r:bool) i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true;

24 Abstraction function: Spec[x] == |{ k | 0 <= k < N && Impl[k].elt == x && Impl[k].stt == full && (!Locked(Impl[k]) || LockerAtLine(Impl[k],10)) }| InsertPair(x:int, y:int) returns (r:bool) i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; Messy! Abstraction map refers to program counter and locking state of every thread

25 InsertPair(x:int, y:int) returns (r:bool) i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; atomic { lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; } Abstraction function: Spec[x] == |{ k | 0 <= k < N && Impl[k].elt == x && Impl[k].stt == full && (!Locked(Impl[k]) || LockerAtLine(Impl[k],10)) }| Commit action: Spec[x] and Spec[y] both incremented

QED Proof System: Reduction and Abstraction Impl 2 Impl 1 Impl n Difficult to prove Fine-grained concurrency  Complicated abstraction map Concurrency control + data Complete/rollback partial actions Easy to prove Coarse-grained concurrency  Clean abstraction map Separates data from concurrency No need to consider partial actions Original implementation Transformed implementation reduce abstract

27 InsertPair(x:int, y:int) returns (r:bool) atomic { i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; } InsertPair(x:int, y:int) returns (r:bool) i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; atomic { lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; } reduction + abstraction

28 InsertPair(x:int, y:int) returns (r:bool) atomic { i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; } introduce Spec InsertPair(x:int, y:int) returns (r:bool) atomic { i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; Spec[x] := Spec[x] + 1; Spec[y] := Spec[y] + 1; } code modifying new variable

29 add invariant InsertPair(x:int, y:int) returns (r:bool) atomic { i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; Spec[x] := Spec[x] + 1; Spec[y] := Spec[y] + 1; } forall x. Spec[x] == |{ k | 0 <= k < N && Impl[k].elt == x && Impl[k].stt == full }|

30 hide Impl InsertPair(x:int, y:int) returns (r:bool) atomic { i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; Spec[x] := Spec[x] + 1; Spec[y] := Spec[y] + 1; } InsertPair(x:int, y:int) returns (r:bool) atomic { r := true; Spec[x] := Spec[x] + 1; Spec[y] := Spec[y] + 1; } LookUp(x:int) returns (r:bool) atomic { if(Spec[x] > 0) r := true; else r := false; }

QED + Variable Hiding Proof Rule + New Soundness Theorem Impl 2 Impl 1 Spec If Spec satisfies all assertions then [POPL’09]: Impl 1 satisfies all assertions [TACAS’10]: Impl 1 is linearizable to Spec Original implementationSpecification reduce abstract

Programs Syntax: Gated action 32 S ::= assume e | assert e | x := e | havoc x | S ; S | if (e) then S else S | while (e) do S | proc(a, out b) | S || S | [ S ] Syntax in code examples: Semantics: A collection of threads and a global store Non-deterministically pick a thread and execute one atomic step Failed assert makes the thread and program go wrong A distinguished state “error” Failed assume blocks the executing thread

33 Gated actions x = x + 1; Transition: Two-store relation Gate: Assertion on pre-state 33

34 Gated actions – examples assert (x != 0); y = y / x; x = x + 1; assert (x != 0); y = y / x; assume (x != 0); y = y / x; Transition: Two-store relation Gate: Assertion on pre-state 34

35 Verifying the program Proof succeeds when all executions of starting from states in satisfy all assertions. Sufficient condition: For all actions in the program, Actions “large enough” to establish assertions within themselves x := 0; x := x + 1; assert (x == 2) 35

Rule 1: Strengthen invariant 36

Rule 2: Abstraction 37 if (x == 1) y := y + 1; if ( * ) y := y + 1; Adding non-determinism Adding assertions t := x; havoc t; assume x != t; skip; assert (lock_owner == tid); x := t + 1;

S1S1 S2S2 S3S3 acquirey S1S1 T2T2 S3S3 y S1S1 T2T2 S3S3 releasex S1S1 S2S2 S3S3 x Right and left movers (Lipton 1975) 38

Rule 3: Reduction 39

40 Reduction  ;  ;  ...   1   2 ...   n   ;  ...  right-mover: For each execution: Exist equivalent executions:...     1   2 ...   n      1     2 ...   n      1   2 ...     n   ...  ;  40

41 Static mover check Right mover: Commutes to the right of any other action run by a different thread Static right-mover check for  : For every action  in program: (run by different thread)     41

42 Static mover check Static right-mover check between  and  : Simple cases –Mover check passes:  and  access different variables  and  disable each other –Fails:  writes to a variable and  reads it  and  both write to a variable, writes do not commute   42

43 Rule 4: Auxiliary variable addition inc (): acquire (lock); t1 := x; t1 := t1 + 1 x := t1; release(lock); inc (): acquire (lock); a := tid; t1 := x; t1 := t1 + 1 x := t1; release(lock); a := 0; AUX-ANNOTATE 43

Rule 5: Variable Hiding 44 LookUp(x:int) returns (r:bool) atomic { if (Spec[x] > 0) r := true; else r := false; } LookUp(x:int) returns(r:bool) atomic { r := \Exists k. 0 <= k < N && Impl[k].elt == x && Impl[k].stt == full } forall x. Spec[x] == | { k | 0 <=k< N && Impl[k].elt == x && Impl[k].stt == full } | The invariant: HIDE VARIABLE

Rule 5: Variable Hiding 45 LookUp(x:int) returns (r:bool) atomic { if (Spec[x] > 0) r := true; else r := false; } LookUp(x:int) returns(r:bool) atomic { r := \Exists k. 0 <= k < N && Impl[k].elt == x && Impl[k].stt == full } forall x. Spec[x] == | { k | 0 <=k< N && Impl[k].elt == x && Impl[k].stt == full } | The invariant: HIDE VARIABLE

Soundness theorem 46 If Impl n satisfies all assertions then [POPL’09]: Impl 1 satisfies all assertions. [TACAS’10]: If Impl n is linearizable to Spec then Impl 1 is linearizable to Spec... Impl 2 Impl 1 Impl n Original implementation Transformed implementation reduce abstract

Proof in QED and soundness Impl 2 Impl 1 Spec If Spec satisfies all assertions then [POPL’09]: Impl 1 satisfies all assertions [TACAS’10]: Impl 1 is linearizable to Spec Original implementationSpecification reduce abstract

48

49 InsertPair(x:int, y:int) returns (r:bool) atomic { i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; } InsertPair(x:int, y:int) returns (r:bool) i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; atomic { lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; } reduction + abstraction

50 InsertPair(x:int, y:int) returns (r:bool) atomic { i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; } introduce Spec InsertPair(x:int, y:int) returns (r:bool) atomic { i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; Spec[x] := Spec[x] + 1; Spec[y] := Spec[y] + 1; } code modifying new variable

51 add invariant InsertPair(x:int, y:int) returns (r:bool) atomic { i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; Spec[x] := Spec[x] + 1; Spec[y] := Spec[y] + 1; } forall x. Spec[x] == |{ k | 0 <= k < N && Impl[k].elt == x && Impl[k].stt == full }|

52 hide Impl InsertPair(x:int, y:int) returns (r:bool) atomic { i := FindSlot(); j := FindSlot(); Impl[i].elt := x; Impl[j].elt := y; lock(Impl[i]); lock(Impl[j]); Impl[i].stt := full; Impl[j].stt := full; unlock(Impl[i]); unlock(Impl[j]); r := true; Spec[x] := Spec[x] + 1; Spec[y] := Spec[y] + 1; } InsertPair(x:int, y:int) returns (r:bool) atomic { r := true; Spec[x] := Spec[x] + 1; Spec[y] := Spec[y] + 1; } LookUp(x:int) returns (r:bool) atomic { if(Spec[x] > 0) r := true; else r := false; }

53

54

55 Superficial Conflict Not a right mover: Modifies Tail

56 Variable Addition and Hiding Removes Conflict Add auxiliary var _Tail: “Real” tail of list Introduce invariant: Hide _Tail Superficial conflict disappears: Move_Tail d oesn’t access _Tail New invariant: Define auxiliary var for sequence of elements in list, hide everything else

57 Variable Addition and Hiding Removes Conflict Add auxiliary var _Tail: “Real” tail of list Introduce invariant: Hide _Tail Superficial conflict disappears: Move_Tail d oesn’t access _Tail New invariant: Define auxiliary var for sequence of elements in list, hide everything else

58 Variable Addition and Hiding Removes Conflict Apply reduction and variable hiding to arrive at specification Final invariant: Implementation is linearizable to specification

59