proving linearizability lock freedom
play

Proving linearizability & lock-freedom Viktor Vafeiadis - PowerPoint PPT Presentation

Proving linearizability & lock-freedom Viktor Vafeiadis MPI-SWS Michael & Scott non-blocking queue head tail null X 1 2 3 CAS compare & swap CAS (address, expectedValue, newValue) { atomic { if ( *address ==


  1. Proving linearizability & lock-freedom Viktor Vafeiadis MPI-SWS

  2. Michael & Scott non-blocking queue head tail null X 1 2 3

  3. CAS – compare & swap CAS (address, expectedValue, newValue) { atomic { if ( *address == expectedValue ) { *address = newValue; return true; } else { return false; } } } -A single hardware instruction on x86

  4. Michael & Scott non-blocking queue head tail null X 1 2 3

  5. Michael & Scott non-blocking queue null head tail 4 null X 1 2 3

  6. Michael & Scott non-blocking queue null head tail 4 X 1 2 3

  7. Michael & Scott non-blocking queue null head tail 4 X 1 2 3

  8. Michael & Scott non-blocking queue null head tail 4 X 1 2 3

  9. Enqueue & dequeue Don’t read the code ! dequeue () { enqueue(v) { while (true) { m = new Node(); m → val = v; h = Q → head; m → next = null; t = Q → tail; while (true) { n = h → next; t = Q → tail; if (Q → tail ≠ t) continue ; n = tail → next; if (h == t) { if (Q → tail ≠ tail) continue ; if (n == null) if (n == null) { return EMPTY; if (CAS(&t → next,n,m)) CAS(&Q → tail,t,n); break; } else { } else { if (CAS(&Q → head,h,n)) CAS(&Q → tail,t,n); return n → val; } } } } CAS(&Q → tail,t,n); } }

  10. RGSep actions (pre-/postcondition pairs)  Summarize the shared state updates head tail head tail Enqueue null null A B A head tail head tail Dequeue A B A B head tail head tail Advance tail pointer A B A B

  11. The actions of enqueue & dequeue enqueue(v) { dequeue () { m = new Node(); while (true) { m → val = v; Local h = Q → head; m → next = null; updates t = Q → tail; while (true) { n = h → next; t = Q → tail; if (Q → tail ≠ t) continue ; n = tail → next; if (h == t) { if (Q → tail ≠ t) continue ; if (n == null) if (n == null) { return EMPTY; if (CAS(&t → next,n,m)) ENQUEUE CAS(&Q → tail,t,n); ADV. TAIL break; } else { } else { if (CAS(&Q → head,h,n)) DEQUEUE CAS(&Q → tail,t,n); ADV. TAIL return n → val; } } } } } CAS(&Q → tail,t,n); ADV. TAIL }

  12. Length (first attempt) length() { num = 0; curr = Q → head → next; while (curr ≠ null) { num++; curr = curr → next; } return num; } head tail null X 1 2 3 4

  13. Length (second attempt) length() { num = 0; while (true) { t = Q → tail; n = tail → next; Read Q → tail, and ensure if (n == null) break ; that Q → tail → next == null CAS(&Q → tail,t,n); } curr = Q → head → next; while (curr ≠ null) { num++; if (curr == t) break; curr = curr → next; } return num; }

  14. Length (third attempt) length() { num = 0; do { h = Q → head; while (true) { Get a snapshot of t = Q → tail; Q → head and Q → tail n = tail → next; and ensure that if (n == null) break ; Q → tail → next==null. CAS(&Q → tail,t,n); } } while (h ≠ Q → head); curr = h → next; while (curr ≠ null) { num++; if (curr == t) break; curr = curr → next; } return num; }

  15. Verification challenge Functional correctness (linearizability): Every method executes ‘atomically’ and obeys a high-level specification VMCAI ’09 CAV ’10 Liveness properties, e.g. lock-freedom: At all times, some outstanding method call is guaranteed to terminate. POPL ’09

  16. Linearizability Every method executes ‘atomically’ & obeys a functional correctness specification Shared variable: AQ enqueue(v) spec AQ := append(singleton(v), AQ); return 0; dequeue() spec if (AQ == empty) { return EMPTY; } else { r := hd(AQ); AQ := tl(AQ); return r; }

  17. Linearizability & forward simulation Linearizability: The implementation (of every method) is a refinement of an atomic specification. Standard proof technique: forward simulation Abstract (spec) S abs S’ abs Concrete (impl) S conc S’ conc

  18. Linearization points The implementation is a refinement of an atomic specification. abstract execution concrete execution linearization point (LP)

  19. Linearization point of enqueue enqueue(v) { m := new Node(); m → val := v; m → next := null; while (true) { t := Q → tail; n := tail → next; if (Q → tail ≠ tail) continue ; if (n == null) { Lin. Point if (CAS(&t → next,n,m)) break; (provided CAS succeeds) } else { CAS(&Q → tail,t,n); } } CAS(&Q → tail,t,n); }

  20. Proof search for the LP ?  For each execution path of each method, choose a candidate LP  Check whether it is a valid LP Does this work ?

  21. Proof search for the LP ?  For each execution path of each method, choose a candidate LP  Check whether it is a valid LP Does this work ? Not quite. 1. LPs can be conditional 2. LPs can be in the code of another thread

  22. LP of dequeue, when it returns EMPTY dequeue () { while (true) { h := Q → head; t := Q → tail; n := h → next; LP provided if (Q → tail ≠ t) this test fails, and continue ; the h==t test succeeds if (h == t) { the n==null test succeeds if (n == null) return EMPTY; CAS(&Q → tail,t,n); } else { if (CAS(&Q → head,h,n)) Condition: return n → val; } ¬prophecy(Q → tail ≠ t) } ∧ h == t } ∧ n == null

  23. Key observation  Method executions that logically modify the state have a simple LP.  Method executions that do not logically modify the state often have a complex LP. So: Treat these two cases differently.  Search for LPs of executions that logically modify the state;  Do a non-constructive proof for executions that do not logically modify the state.

  24. Basic LP validation Auxiliary variable: lres 1. At the entry to the function: lres := UNDEF; 2. At the candidate e fg ectful LPs: assert( lres ==UNDEF); lres := method_spec(); 3. At the return points, check res == lres concrete abstract result result

  25. Validating pure executions Auxiliary variable: can_return 1. At the entry to the function: ∀ i. can_return [i] := false; 2. At every point, add a pure ‘LP checker’: if (abs_method() has no side-e fg ects) can_return [abs_method()] := true; 3. At the return points, check can_return [res] == true concrete result

  26. For example... dequeue spec if (AQ == empty) { return EMPTY; } else { r := hd(AQ); AQ := tl(AQ); return r; } pure lin. checker if (AQ == empty) { can_return [EMPTY] := true; }

  27. Enhanced LP validation Auxiliary variables: lres , can_return 1. At the entry to the function: lres := UNDEF; ∀ i. can_return [i] := false; 2. At the candidate e fg ectful LPs: assert( lres= =UNDEF); lres := abs_method() 3. Add pure checkers at every program point: assign can_return [i] := true if method_spec returns i & has no side-e fg ects. 4. At the return points, check (res== lres ) ∨ ( lres ==UNDEF ∧ can_return [res])

  28. LPs in other threads add (e) { ... } remove (e) { ... } contains (e) { c := H; while (c → val < e) c := c → next; return (c → val == e); } null -INF 1 3 7 +INF contains(5) || add(5); remove(3); remove(5)

  29. LPs in other threads add (e) { ... } remove (e) { ... } contains (e) { c := H; while (c → val < e) c := c → next; return (c → val == e); } null -INF 1 3 7 +INF c contains(5) || add(5); remove(3); remove(5)

  30. LPs in other threads add (e) { ... } remove (e) { ... } contains (e) { c := H; while (c → val < e) c := c → next; return (c → val == e); } null -INF 1 3 7 +INF c contains(5) || add(5); remove(3); remove(5)

  31. LPs in other threads add (e) { ... } remove (e) { ... } contains (e) { c := H; while (c → val < e) c := c → next; return (c → val == e); } null -INF 1 3 7 +INF c contains(5) || add(5); remove(3); remove(5)

  32. LPs in other threads add (e) { ... } remove (e) { ... } contains (e) { c := H; while (c → val < e) c := c → next; return (c → val == e); } null -INF 1 3 5 7 +INF c contains(5) || add(5); remove(3); remove(5)

  33. LPs in other threads add (e) { ... } remove (e) { ... } contains (e) { c := H; while (c → val < e) c := c → next; return (c → val == e); } 3 null -INF 1 5 7 +INF c contains(5) || add(5); remove(3); remove(5)

  34. LPs in other threads add (e) { ... } remove (e) { ... } contains (e) { c := H; while (c → val < e) c := c → next; return (c → val == e); } 5 3 null -INF 1 7 +INF c contains(5) || add(5); remove(3); remove(5)

  35. LPs in other threads add (e) { ... } remove (e) { ... } contains (e) { c := H; while (c → val < e) c := c → next; return (c → val == e); } 5 3 null -INF 1 7 +INF c contains(5) || add(5); remove(3); remove(5)

  36. Enhanced LP validation Auxiliary variables: lres , can_return 1. At the entry to the function: lres := UNDEF; ∀ i. can_return [i] := false; 2. At the candidate e fg ectful LPs: assert( lres= =UNDEF); lres := abs_method() 3. Add pure checkers at every program point (incl. program points in other threads) 4. At the return points, check (res== lres ) ∨ ( lres ==UNDEF ∧ can_return [res])

  37. Implementation CAVE: Concurrent Algorithm VErifier - RGSep action inference [VMCAI 2010] - Shape-value abstract domain [VMCAI 2009] - Algorithm for proving linearizability [CAV 2010] http://www.mpi-sws.org/~viktor/cave

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend