-
Notifications
You must be signed in to change notification settings - Fork 14
/
verona_rc_wrc.cvf
executable file
·182 lines (159 loc) · 4.54 KB
/
verona_rc_wrc.cvf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/* Atomic reference counter from Verona
*
* Strong and Weak references
*
* Provides a wait-free acquire_strong_from_weak.
*
* This was verified using ff235a5a5e0e4057 from Matt Windsor's development
* branch of Starling.
* https://github.com/MattWindsor91/starling-tool
*
* Caveats: The proof does not contain the full lifetime management aspects
* such as actually running the destructor of a Cown, or deallocating the
* underlying representation.
*/
/**
* The strong reference count
*/
shared int rc;
/*
* The weak reference count
*/
shared int wrc;
/*
* Has the structure been destructed
*/
shared bool destructed;
/*
* Has the structure been deallocated
*/
shared bool deallocated;
/**
* This is a mark bit added to the reference count.
*/
shared bool closed;
thread bool success;
thread bool lost_weak;
thread bool last;
view iter StrongRef;
view iter WeakRef;
view Destruct;
view Dealloc;
/**
* This corresponds to Object::incref in object.h
*/
method acquire_strong()
{
{| StrongRef |} <| rc++; |> {| StrongRef * StrongRef |}
}
/**
* This corresponds to Cown::weak_acquire in cown.h
*/
method acquire_weak()
{
{| WeakRef |} <| wrc++; |> {| WeakRef * WeakRef |}
}
/**
* This corresponds to Cown::weak_acquire in cown.h
* It is the same method as above, just with a different specification.
*/
method acquire_weak_from_strong()
{
{| StrongRef |} <| wrc++; |> {| StrongRef * WeakRef |}
}
/*
Releases a strong reference count.
Internally may destruct and also deallocate the underlying object.
This corresponds to Cown::release in object.h
*/
method release_strong()
{
{| StrongRef |}
<| rc--; last = rc==0; |>
{| if last { WeakRef } |} /* Note A */
if last {
{| WeakRef |}
// The following is a CAS to attempt to set the bit if the
// rc is still zero.
<| last = ((closed == false) && (rc == 0)); if last {closed = true;} |>
{| if last { Destruct } else { WeakRef } |}
if (last)
{
{| Destruct |}
<| destructed = true; |>
{| WeakRef |}
}
{| WeakRef |}
// Should call weak release here
// Not supported in starling syntax.
}
}
/**
* This is corresponds to the start of
* Cown::weak_release in cown.h
* The function in Verona also handles the deallocation of
* the underlying object, and integrating with other considerations
* of the runtime. Here we represent that deallocation by setting a flag.
*/
method release_weak()
{
{| WeakRef |}
<| wrc--; last = wrc == 0; |>
{| if last { Dealloc } |}
if (last)
{
{| Dealloc |}
<| deallocated = true; |>
{| emp |}
}
}
/**
This has two returns
success signifies we successfully acquired a StrongRef
lost_weak signifies we lost our weak reference in the acquisition.
This corresponds to Object::acquire_strong_from_weak in object.h
*/
method acquire_strong_from_weak()
{
{| WeakRef |}
<|
lost_weak = rc == 0 && !closed;
rc++;
success = !closed;
|>
{| if (success) { StrongRef }
* if (lost_weak) { emp } else {WeakRef}
|}
}
// Invariant
constraint emp ->
rc >= 0 &&
wrc >= 0 &&
(closed == false => destructed == false) &&
(wrc > 0 => deallocated == false) &&
(rc > 0 => (wrc > 0 || closed == true)) &&
destructed == true => closed == true &&
deallocated == true => wrc == 0
;
constraint Destruct -> destructed == false && closed == true && wrc > 0;
constraint Dealloc -> deallocated == false && wrc == 0;
// Note A: that we cannot prove the Stronger
//
// constraint Dealloc -> deallocated == false && wrc == 0 && destructed == true;
//
// This is because the WeakRef used between the decrement and closing the count
// (as far as the proof is concerned) could be released with weak_release.
// To remove this possibility, it would require two different versions of WeakRef
// and this would go beyond what is easily expressible in the current Starling tool.
// It could be handled with auxiliary variables or an constraints over two iterated views.
// Linear
constraint Dealloc * Dealloc -> false;
constraint Destruct * Destruct -> false;
constraint iter[n] StrongRef -> n > 0 => (rc >= n && closed == false);
constraint iter[n] WeakRef ->
n > 0
=> ( destructed == false && closed == true && wrc >= n + 1 )
|| ( closed == false && rc > 0 && wrc >= n + 1 )
|| ( destructed == true && wrc >= n )
|| ( closed == false && rc == 0 && wrc >= n )
;