1+ module Dekker
2+ # lang - pulse
3+ open Pulse.Lib.Pervasives
4+ module GR = Pulse.Lib.GhostReference
5+ module R = Pulse.Lib.Reference
6+ open Pulse.Class.PtsTo
7+
8+ (* Dekker's algorithm for mutual exclusion relies on sequential consistency
9+
10+ a := 0; b := 0;
11+ par
12+ (
13+ atomic_write a 1;
14+ if atomic_read b = 0
15+ then /* critical section */
16+ )
17+ (
18+ atomic_write b 1;
19+ if atomic_read a = 0
20+ then /* critical section */
21+ )
22+
23+ This is provable in Pulse with an invariant & ghost state
24+ *)
25+
26+
27+ // Some primitives for atomic read and write
28+ atomic
29+ fn read_atomic ( r : R. ref bool) (# p : perm ) (# v : erased bool)
30+ requires
31+ r |-> Frac p v
32+ returns b :bool
33+ ensures
34+ r |-> Frac p v
35+ ensures
36+ pure ( b == reveal v )
37+ { admit ()}
38+
39+ atomic
40+ fn write_atomic ( r : R. ref bool) ( b :bool)
41+ requires
42+ exists * v . r |-> v
43+ ensures
44+ r |-> b
45+ { admit () }
46+
47+ //The main invariant
48+ let dekker_inv ( ra rb : R. ref bool) ( ga gb : GR. ref bool) ( p : slprop )
49+ : slprop
50+ = exists * ( va vb ua ub :bool).
51+ ( ra |-> Frac 0 . 5R va ) **
52+ ( rb |-> Frac 0 . 5R vb ) **
53+ ( ga |-> Frac 0 . 5R ua ) **
54+ ( gb |-> Frac 0 . 5R ub ) **
55+ cond ( ua || ub ) emp p ** //if both ghost variables are false, then p is available
56+ pure ( //ghost vars are false if their concrete counterparts are
57+ ( va = false ==> ua = false ) /\
58+ ( vb = false ==> ub = false )
59+ )
60+
61+ ghost
62+ fn intro_dekker_inv_init
63+ ( ra rb : R. ref bool) ( ga gb : GR. ref bool) ( p : slprop )
64+ requires
65+ ( ra |-> Frac 0 . 5R false ) **
66+ ( rb |-> Frac 0 . 5R false ) **
67+ ( ga |-> Frac 0 . 5R false ) **
68+ ( gb |-> Frac 0 . 5R false ) **
69+ p
70+ ensures
71+ dekker_inv ra rb ga gb p
72+ {
73+ intro_cond_false emp p ;
74+ fold ( dekker_inv ra rb ga gb p )
75+ }
76+
77+ ghost
78+ fn init_dekker_inv
79+ ( ra rb : R. ref bool)
80+ ( ga gb : GR. ref bool)
81+ ( p : slprop )
82+ requires
83+ ( ra |-> false ) **
84+ ( rb |-> false ) **
85+ ( ga |-> false ) **
86+ ( gb |-> false ) **
87+ p
88+ returns i : iname
89+ ensures
90+ inv i ( dekker_inv ra rb ga gb p )
91+ ensures
92+ ( ra |-> Frac 0 . 5R false ) **
93+ ( rb |-> Frac 0 . 5R false ) **
94+ ( ga |-> Frac 0 . 5R false ) **
95+ ( gb |-> Frac 0 . 5R false )
96+ {
97+ R. share ra ; R. share rb ;
98+ GR. share ga ; GR. share gb ;
99+ intro_dekker_inv_init ra rb ga gb p ;
100+ let i = new_invariant ( dekker_inv ra rb ga gb p );
101+ i
102+ }
103+
104+ ghost
105+ fn intro_dekker_inv_a
106+ ( ra rb : R. ref bool) ( ga gb : GR. ref bool) ( p : slprop )
107+ requires
108+ exists * ( vb ub :bool).
109+ ( ra |-> Frac 0 . 5R true ) **
110+ ( rb |-> Frac 0 . 5R vb ) **
111+ ( ga |-> Frac 0 . 5R true ) **
112+ ( gb |-> Frac 0 . 5R ub ) **
113+ pure (
114+ ( vb = false ==> ub = false )
115+ )
116+ ensures
117+ dekker_inv ra rb ga gb p
118+ {
119+ intro_cond_true emp p ;
120+ fold ( dekker_inv ra rb ga gb p )
121+ }
122+
123+
124+ fn procA ( i : iname ) ( ra rb : R. ref bool) ( ga gb : GR. ref bool) ( p : slprop )
125+ preserves
126+ inv i ( dekker_inv ra rb ga gb p ) //with the invariant
127+ requires
128+ ( ra |-> Frac 0 . 5R false ) ** //if a is initially false
129+ ( exists * ( ua :bool). ga |-> Frac 0 . 5R ua ) //and with ga
130+ returns b :bool
131+ ensures
132+ ( ra |-> Frac 0 . 5R true ) ** //a is true
133+ ( ga |-> Frac 0 . 5R b ) //g is set to the return value
134+ ensures
135+ ( if b then p else emp ) //and if this returns true then we have the resource p
136+ {
137+ later_credit_buy 1 ;
138+ with_invariants i
139+ returns _ :unit
140+ ensures
141+ later ( dekker_inv ra rb ga gb p ) **
142+ ( ra |-> Frac 0 . 5R true ) **
143+ ( ga |-> Frac 0 . 5R false )
144+ {
145+ later_elim _ ;
146+ unfold dekker_inv ;
147+ R. gather ra ;
148+ write_atomic ra true ; // x := true
149+ R. share ra ;
150+ GR. gather ga ;
151+ GR. share ga ;
152+ fold ( dekker_inv ra rb ga gb p );
153+ later_intro ( dekker_inv ra rb ga gb p );
154+ };
155+ later_credit_buy 1 ;
156+ with_invariants i
157+ {
158+ later_elim _ ;
159+ unfold dekker_inv ;
160+ R. gather ra ; R. share ra ;
161+ if ( read_atomic rb )
162+ {
163+ fold ( dekker_inv ra rb ga gb );
164+ later_intro ( dekker_inv _ _ _ _ _ );
165+ false
166+ }
167+ else
168+ {
169+ GR. gather ga ;
170+ elim_cond_false _ _ _ ;
171+ GR. write ga true ;
172+ GR. share ga ;
173+ intro_dekker_inv_a ra rb ga gb p ;
174+ later_intro ( dekker_inv _ _ _ _ _ );
175+ true
176+ }
177+ };
178+ }
0 commit comments