A case for relaxed program logics Viktor Vafeiadis MPI-SWS 10 July 2014
Understanding weak memory consistency Read the architecture/language specs? ◮ Too informal, often wrong. Read the formalisations? ◮ Fairly complex. Run benchmarks / Litmus tests? ◮ Observe only subset of behaviours. We need better tools. . . Relaxed program logics Viktor Vafeiadis A case for relaxed program logics 2/17
Which memory model? Hardware or language models? ◮ Want to reason at “high level” ◮ TSO ❀ good robustness theorems C/C++ or Java? ◮ JMM is broken [Sevcik et al.] ◮ So, only C/C++11 left Goals: ◮ Understand the memory model ◮ Verify intricate concurrent programs Viktor Vafeiadis A case for relaxed program logics 3/17
The C11 memory model Two types of locations: ordinary and atomic ◮ Races on ordinary accesses ❀ error A spectrum of atomic accesses: ◮ Relaxed ❀ no fence ◮ Consume reads ❀ no fence, but preserve deps ◮ Release writes ❀ no fence (x86); lwsync (PPC) ◮ Acquire reads ❀ no fence (x86); isync (PPC) ◮ Seq. consistent ❀ full memory fence Explicit primitives for fences Viktor Vafeiadis A case for relaxed program logics 4/17
� � � � Release-acquire synchronization: message passing Initially a = x = 0. a = 5; while ( x . load( acq ) == 0); x . store( release , 1); print( a ); This will always print 5. Justification: W na ( a , 5) R acq ( x , 1) Release-acquire synchronization W rel ( x , 1) R na ( x , 5) Viktor Vafeiadis A case for relaxed program logics 5/17
Rules for release/acquire accesses Ownership transfer by rel-acq synchronizations. ◮ Atomic allocation ❀ pick loc. invariant Q . � � � � Q ( v ) x = alloc( v ); W Q ( x ) ∗ R Q ( x ) ◮ Release write ❀ give away permissions. � � � � Q ( v ) ∗ W Q ( x ) x . store( v , rel ); W Q ( x ) ◮ Acquire read ❀ gain permissions. � � � � R Q ( x ) t = x . load( acq ); Q ( t ) ∗ R Q [ t :=emp] ( x ) Viktor Vafeiadis A case for relaxed program logics 6/17
Release-acquire synchronization: message passing Initially a = x = 0. Let J ( v ) def = v = 0 ∨ & a �→ 5. � � � � & a �→ 0 ∗ W J ( x ) R J ( x ) a = 5; while ( x . load( acq ) == 0); � � � � & a �→ 5 ∗ W J ( x ) & a �→ 5 x . store( release , 1); print( a ); � � � � W J ( x ) & a �→ 5 PL consequences: Ownership transfer works! Viktor Vafeiadis A case for relaxed program logics 7/17
Relaxed accesses Basically, disallow ownership transfer. ◮ Relaxed reads: � � � � R Q ( x ) t := x . load( rlx ) R Q ( x ) ◮ Relaxed writes: Q ( v ) = emp � � � � W Q ( x ) x . store( v , rlx ) W Q ( x ) Unsound because of dependency cycles! Viktor Vafeiadis A case for relaxed program logics 8/17
� � � � Dependency cycles Initially x = y = 0. if ( x . load ( rlx ) == 1) if ( y . load ( rlx ) == 1) y . store (1 , rlx ); x . store (1 , rlx ); C11 allows the outcome x = y = 1. Justification: R rlx ( x , 1) R rlx ( y , 1) Relaxed accesses don’t synchronize W rlx ( y , 1) W rlx ( x , 1) Viktor Vafeiadis A case for relaxed program logics 9/17
Dependency cycles Initially x = y = 0. if ( x . load ( rlx ) == 1) if ( y . load ( rlx ) == 1) y . store (1 , rlx ); x . store (1 , rlx ); C11 allows the outcome x = y = 1. What goes wrong: Non-relational invariants are unsound. x = 0 ∧ y = 0 The DRF-property does not hold. Viktor Vafeiadis A case for relaxed program logics 9/17
Dependency cycles Initially x = y = 0. if ( x . load ( rlx ) == 1) if ( y . load ( rlx ) == 1) y . store (1 , rlx ); x . store (1 , rlx ); C11 allows the outcome x = y = 1. How to fix this: Don’t use relaxed writes ∨ Strengthen the model Viktor Vafeiadis A case for relaxed program logics 9/17
� � � � � � � � Incorrect message passing int a ; atomic_int x = 0; a = 5; if ( x . load( rlx ) � = 0) { x . store(1 , rlx ); print ( a ); } W na ( x , 0) W na ( a , 5) R rlx ( x , 1) race W rlx ( x , 1) R na ( a , 5) Viktor Vafeiadis A case for relaxed program logics 10/17
� � � � � � � � � � Message passing with C11 memory fences int a ; atomic_int x = 0; a = 5; if ( x . load( rlx ) � = 0) { fence( release ); fence( acq ); x . store(1 , rlx ); print ( a ); } W na ( x , 0) W na ( a , 5) R rlx ( x , 1) sw � Fence acq Fence rel W rlx ( x , 1) R na ( a , 5) Viktor Vafeiadis A case for relaxed program logics 10/17
Reasoning about fences ◮ Introduce two ‘modalities’ in the logic � � � � P fence( release ) △ P � � � � ∇ P fence( acq ) P � � � � R Q ( x ) t := x . load( rlx ) R Q [ t :=emp] ( x ) ∗ ∇Q ( t ) � � � � W Q ( x ) ∗ △Q ( v ) x . store( v , rlx ) W Q ( x ) Viktor Vafeiadis A case for relaxed program logics 11/17
Reasoning about fences Let Q ( v ) def = v = 0 ∨ & a �→ 5. � � & a �→ 0 ∗ W Q ( x ) ∗ R Q ( x ) � � & a �→ 0 ∗ W Q ( x ) t = x . load( rlx ); � � a = 5; ∇ ( t = 0 ∨ & a �→ 5) � � & a �→ 5 ∗ W Q ( x ) if ( t � = 0) fence( release ); fence( acq ); � � � � △ (& a �→ 5) ∗ W Q ( x ) & a �→ 5 x . store(1 , rlx ); print ( a ); } � � � � true true Viktor Vafeiadis A case for relaxed program logics 12/17
� � � � Release-consume synchronization Initially a = x = 0. a = 5; t = x . load ( consume ); x . store ( release , & a ); if ( t � = 0) print ( ∗ t ); This program cannot crash nor print 0. Justification: W na ( a , 5) R con ( x , & a ) Release-consume synchronization W rel ( x , & a ) R na ( a , 5) Viktor Vafeiadis A case for relaxed program logics 13/17
Release-consume synchronization Initially a = x = 0. Let J ( t ) def = t = 0 ∨ t �→ 5. � � � � & a �→ 0 ∗ W J ( x ) R J ( x ) a = 5; t = x . load ( consume ); � � � � & a �→ 5 ∗ W J ( x ) ∇ t ( t = 0 ∨ t �→ 5) x . store ( release , & a ); if ( t � = 0) print ( ∗ t ); This program cannot crash nor print 0. PL consequences: Needs funny modality, but otherwise OK. Viktor Vafeiadis A case for relaxed program logics 13/17
Proposed rules for consume accesses � � � � R Q ( x ) t := x . load( cons ) R Q [ t :=emp] ( x ) ∗ ∇ t Q ( t ) � � � � P C Q C is basic command mentioning t � � � � ∇ ∇ t P C t Q Viktor Vafeiadis A case for relaxed program logics 14/17
Release-acquire too weak in the presence of consume Initially x = y = 0. while ( x . load ( consume ) � = 1); a = 1; y . store (1 , release ); x . store (1 , release ); ( ∗ ) while ( y . load ( acquire ) � = 1); ( ∗ ) a = 2; C11 deems this program racy. ◮ Only different thread rel-acq synchronize. What goes wrong in PL: On ownership transfers, we must prove that we don’t read from the same thread. Viktor Vafeiadis A case for relaxed program logics 15/17
Release-acquire too weak in the presence of consume Initially x = y = 0. while ( x . load ( consume ) � = 1); a = 1; y . store (1 , release ); x . store (1 , release ); ( ∗ ) while ( y . load ( acquire ) � = 1); ( ∗ ) a = 2; C11 deems this program racy. But, it is not racy: ◮ On x86-TSO, Power, ARM, and Itanium. ◮ Or if we move the ( ∗ ) lines to a new thread. So, drop the “different thread” restriction. Viktor Vafeiadis A case for relaxed program logics 15/17
Release sequences too strong (relaxed writes) Initially x = y = 0. a = 1; x . store(1 , release ); while ( x . load( acquire ) � = 3); x . store(3 , relaxed ); a = 2; This program is not racy. The acquire synchronizes with the release. Viktor Vafeiadis A case for relaxed program logics 16/17
Release sequences too strong (relaxed writes) Initially x = y = 0. a = 1; x . store(2 , relaxed ); x . store(1 , release ); while ( x . load( acquire ) � = 3); x . store(3 , relaxed ); a = 2; But this one is racy according to C11. The acquire no longer synchronizes with the release. Viktor Vafeiadis A case for relaxed program logics 16/17
Conclusion Relaxed program logics are a tool for understanding weak memory models Viktor Vafeiadis A case for relaxed program logics 17/17
Recommend
More recommend