bend-python 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bend_python/__init__.py +24 -0
- bend_python/__main__.py +26 -0
- bend_python/build.py +368 -0
- bend_python/lib/LAWS.bend +85 -0
- bend_python/lib/PROOF.bend +141 -0
- bend_python/lib/THREAD_LAWS.bend +199 -0
- bend_python/lib/THREAD_PROOF.bend +362 -0
- bend_python/lib/python.bend +218 -0
- bend_python/lib/python.c +817 -0
- bend_python/lib/thread_state.bend +225 -0
- bend_python/library.py +52 -0
- bend_python-0.1.0.dist-info/METADATA +262 -0
- bend_python-0.1.0.dist-info/RECORD +16 -0
- bend_python-0.1.0.dist-info/WHEEL +5 -0
- bend_python-0.1.0.dist-info/licenses/LICENSE +21 -0
- bend_python-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import Base
|
|
2
|
+
import ./thread_state.bend as Thread
|
|
3
|
+
|
|
4
|
+
# Python effects
|
|
5
|
+
|
|
6
|
+
law detached_effect_rejected:
|
|
7
|
+
{Thread.step(Thread.Detached{}, Thread.PythonEffect{}) == None{} : Maybe<Thread.State>}
|
|
8
|
+
|
|
9
|
+
law accepted_effect_attached:
|
|
10
|
+
for state: Thread.State
|
|
11
|
+
for next: Thread.State
|
|
12
|
+
for accepted: {Thread.step(state, Thread.PythonEffect{}) == Some{next} : Maybe<Thread.State>}
|
|
13
|
+
{state == Thread.Attached{} : Thread.State}
|
|
14
|
+
|
|
15
|
+
# Inside native evaluation, no Python effect, save, restore, lease operation,
|
|
16
|
+
# or nested entry is accepted: the only way out is Leave.
|
|
17
|
+
law native_effect_rejected:
|
|
18
|
+
for state: Thread.State
|
|
19
|
+
for native: {Thread.is_native(state) == True{} : Bool}
|
|
20
|
+
{Thread.step(state, Thread.PythonEffect{}) == None{} : Maybe<Thread.State>}
|
|
21
|
+
|
|
22
|
+
law native_only_leaves:
|
|
23
|
+
for state: Thread.State
|
|
24
|
+
for operation: Thread.Operation
|
|
25
|
+
for native: {Thread.is_native(state) == True{} : Bool}
|
|
26
|
+
for staying: {Thread.is_leave(operation) == False{} : Bool}
|
|
27
|
+
{Thread.step(state, operation) == None{} : Maybe<Thread.State>}
|
|
28
|
+
|
|
29
|
+
# Attachment
|
|
30
|
+
|
|
31
|
+
law save_restore:
|
|
32
|
+
{Thread.run([Thread.Save{}, Thread.Restore{}], Thread.Attached{}) == Some{Thread.Attached{}} : Maybe<Thread.State>}
|
|
33
|
+
|
|
34
|
+
# Both detach policies and both outcomes (a native failure also leaves through
|
|
35
|
+
# Leave) return to the attached state.
|
|
36
|
+
law native_returns_attached:
|
|
37
|
+
for detach: Bool
|
|
38
|
+
for outcome: Thread.Outcome
|
|
39
|
+
{Thread.run(Thread.native_call(detach, outcome), Thread.Attached{}) == Some{Thread.Attached{}} : Maybe<Thread.State>}
|
|
40
|
+
|
|
41
|
+
law native_then_effect_accepted:
|
|
42
|
+
for detach: Bool
|
|
43
|
+
for outcome: Thread.Outcome
|
|
44
|
+
{Thread.run(List.append(&1, Thread.Operation, Thread.native_call(detach, outcome), [Thread.PythonEffect{}]), Thread.Attached{}) == Some{Thread.Attached{}} : Maybe<Thread.State>}
|
|
45
|
+
|
|
46
|
+
law release_before_restore_rejected:
|
|
47
|
+
for outcome: Thread.Outcome
|
|
48
|
+
{Thread.run([Thread.Save{}, Thread.Enter{}, Thread.Leave{outcome}, Thread.PythonEffect{}], Thread.Attached{}) == None{} : Maybe<Thread.State>}
|
|
49
|
+
|
|
50
|
+
law free_threaded_detaches:
|
|
51
|
+
for release_gil: Bool
|
|
52
|
+
{Thread.detaches(release_gil, True{}) == True{} : Bool}
|
|
53
|
+
|
|
54
|
+
# Leases
|
|
55
|
+
|
|
56
|
+
law acquire_requires_detached:
|
|
57
|
+
for state: Thread.State
|
|
58
|
+
for pool: List<&2, Thread.Context>
|
|
59
|
+
for slot: Nat
|
|
60
|
+
for attached: {state != Thread.Detached{} : Thread.State}
|
|
61
|
+
{Thread.step_session(Thread.Session{state, pool}, Thread.AcquireLease{slot}) == None{} : Maybe<Thread.Session>}
|
|
62
|
+
|
|
63
|
+
law return_requires_detached:
|
|
64
|
+
for state: Thread.State
|
|
65
|
+
for pool: List<&2, Thread.Context>
|
|
66
|
+
for slot: Nat
|
|
67
|
+
for outcome: Thread.Outcome
|
|
68
|
+
for small_heap: Bool
|
|
69
|
+
for cache_space: Bool
|
|
70
|
+
for attached: {state != Thread.Detached{} : Thread.State}
|
|
71
|
+
{Thread.step_session(Thread.Session{state, pool}, Thread.ReturnLease{slot, outcome, small_heap, cache_space}) == None{} : Maybe<Thread.Session>}
|
|
72
|
+
|
|
73
|
+
law reserved_unavailable:
|
|
74
|
+
for pool: List<&2, Thread.Context>
|
|
75
|
+
for slot: Nat
|
|
76
|
+
{Thread.available(Thread.reserve(pool, slot), slot) == False{} : Bool}
|
|
77
|
+
|
|
78
|
+
law reserved_acquisition_rejected:
|
|
79
|
+
for pool: List<&2, Thread.Context>
|
|
80
|
+
for slot: Nat
|
|
81
|
+
{Thread.acquire(Thread.reserve(pool, slot), slot) == None{} : Maybe<List<&2, Thread.Context>>}
|
|
82
|
+
|
|
83
|
+
law acquisition_requires_available:
|
|
84
|
+
for pool: List<&2, Thread.Context>
|
|
85
|
+
for slot: Nat
|
|
86
|
+
for next: List<&2, Thread.Context>
|
|
87
|
+
for acquired: {Thread.acquire(pool, slot) == Some{next} : Maybe<List<&2, Thread.Context>>}
|
|
88
|
+
{Thread.available(pool, slot) == True{} : Bool}
|
|
89
|
+
|
|
90
|
+
law reserved_returnable:
|
|
91
|
+
for pool: List<&2, Thread.Context>
|
|
92
|
+
for slot: Nat
|
|
93
|
+
for free: {Thread.available(pool, slot) == True{} : Bool}
|
|
94
|
+
{Thread.returnable(Thread.reserve(pool, slot), slot) == True{} : Bool}
|
|
95
|
+
|
|
96
|
+
law unleased_return_rejected:
|
|
97
|
+
for pool: List<&2, Thread.Context>
|
|
98
|
+
for slot: Nat
|
|
99
|
+
for outcome: Thread.Outcome
|
|
100
|
+
for small_heap: Bool
|
|
101
|
+
for cache_space: Bool
|
|
102
|
+
for unleased: {Thread.returnable(pool, slot) == False{} : Bool}
|
|
103
|
+
{Thread.release(pool, slot, outcome, small_heap, cache_space) == None{} : Maybe<List<&2, Thread.Context>>}
|
|
104
|
+
|
|
105
|
+
law double_return_rejected:
|
|
106
|
+
for pool: List<&2, Thread.Context>
|
|
107
|
+
for slot: Nat
|
|
108
|
+
for outcome: Thread.Outcome
|
|
109
|
+
for small_heap: Bool
|
|
110
|
+
for cache_space: Bool
|
|
111
|
+
{Thread.returnable(Thread.finish(pool, slot, outcome, small_heap, cache_space), slot) == False{} : Bool}
|
|
112
|
+
|
|
113
|
+
# Updating one slot leaves every other slot unchanged. In C, isolation comes
|
|
114
|
+
# from separate allocations and thread-local bp_current; this is the model's
|
|
115
|
+
# counterpart, a List.set/List.get lemma.
|
|
116
|
+
law context_update_isolated:
|
|
117
|
+
for pool: List<&2, Thread.Context>
|
|
118
|
+
for target: Nat
|
|
119
|
+
for other: Nat
|
|
120
|
+
for value: Thread.Context
|
|
121
|
+
for different: {Nat.is_eq(target, other) == False{} : Bool}
|
|
122
|
+
{List.get(&2, Thread.Context, List.set(&2, Thread.Context, pool, target, value), other) == List.get(&2, Thread.Context, pool, other) : Maybe<&2, Thread.Context>}
|
|
123
|
+
|
|
124
|
+
law failure_isolated:
|
|
125
|
+
for small_heap: Bool
|
|
126
|
+
for cache_space: Bool
|
|
127
|
+
for pool: List<&2, Thread.Context>
|
|
128
|
+
for target: Nat
|
|
129
|
+
for other: Nat
|
|
130
|
+
for different: {Nat.is_eq(target, other) == False{} : Bool}
|
|
131
|
+
{List.get(&2, Thread.Context, Thread.finish(pool, target, Thread.Failed{}, small_heap, cache_space), other) == List.get(&2, Thread.Context, pool, other) : Maybe<&2, Thread.Context>}
|
|
132
|
+
|
|
133
|
+
# Reuse
|
|
134
|
+
|
|
135
|
+
law failed_context_discarded:
|
|
136
|
+
for small_heap: Bool
|
|
137
|
+
for cache_space: Bool
|
|
138
|
+
{Thread.completion(Thread.Failed{}, small_heap, cache_space) == Thread.Discarded{} : Thread.Context}
|
|
139
|
+
|
|
140
|
+
law failed_context_unavailable:
|
|
141
|
+
for small_heap: Bool
|
|
142
|
+
for cache_space: Bool
|
|
143
|
+
for pool: List<&2, Thread.Context>
|
|
144
|
+
for slot: Nat
|
|
145
|
+
{Thread.available(Thread.finish(pool, slot, Thread.Failed{}, small_heap, cache_space), slot) == False{} : Bool}
|
|
146
|
+
|
|
147
|
+
law successful_context_reusable:
|
|
148
|
+
{Thread.completion(Thread.Succeeded{}, True{}, True{}) == Thread.Idle{} : Thread.Context}
|
|
149
|
+
|
|
150
|
+
law reusable_requires_success:
|
|
151
|
+
for outcome: Thread.Outcome
|
|
152
|
+
for small_heap: Bool
|
|
153
|
+
for cache_space: Bool
|
|
154
|
+
for reusable: {Thread.completion(outcome, small_heap, cache_space) == Thread.Idle{} : Thread.Context}
|
|
155
|
+
{outcome == Thread.Succeeded{} : Thread.Outcome}
|
|
156
|
+
|
|
157
|
+
law reusable_requires_small_heap:
|
|
158
|
+
for outcome: Thread.Outcome
|
|
159
|
+
for small_heap: Bool
|
|
160
|
+
for cache_space: Bool
|
|
161
|
+
for reusable: {Thread.completion(outcome, small_heap, cache_space) == Thread.Idle{} : Thread.Context}
|
|
162
|
+
{small_heap == True{} : Bool}
|
|
163
|
+
|
|
164
|
+
law reusable_requires_cache_space:
|
|
165
|
+
for outcome: Thread.Outcome
|
|
166
|
+
for small_heap: Bool
|
|
167
|
+
for cache_space: Bool
|
|
168
|
+
for reusable: {Thread.completion(outcome, small_heap, cache_space) == Thread.Idle{} : Thread.Context}
|
|
169
|
+
{cache_space == True{} : Bool}
|
|
170
|
+
|
|
171
|
+
# Whole invocations: the thread-state and lease models together.
|
|
172
|
+
|
|
173
|
+
# From any idle slot, an invocation with any number of rounds, detach policy,
|
|
174
|
+
# and native outcomes returns attached, leaving only its own slot updated.
|
|
175
|
+
law invocation_returns_attached:
|
|
176
|
+
for +pool: List<&2, Thread.Context>
|
|
177
|
+
for +slot: Nat
|
|
178
|
+
for +detach: Bool
|
|
179
|
+
for +outcomes: List<&2, Thread.Outcome>
|
|
180
|
+
for +small_heap: Bool
|
|
181
|
+
for +cache_space: Bool
|
|
182
|
+
for +free: {Thread.available(pool, slot) == True{} : Bool}
|
|
183
|
+
{Thread.run_session(Thread.invocation(slot, detach, outcomes, small_heap, cache_space), Thread.Session{Thread.Attached{}, pool}) == Some{Thread.Session{Thread.Attached{}, Thread.finish(pool, slot, Thread.health(outcomes), small_heap, cache_space)}} : Maybe<Thread.Session>}
|
|
184
|
+
|
|
185
|
+
law leased_invocation_rejected:
|
|
186
|
+
for pool: List<&2, Thread.Context>
|
|
187
|
+
for slot: Nat
|
|
188
|
+
for detach: Bool
|
|
189
|
+
for outcomes: List<&2, Thread.Outcome>
|
|
190
|
+
for small_heap: Bool
|
|
191
|
+
for cache_space: Bool
|
|
192
|
+
for busy: {Thread.available(pool, slot) == False{} : Bool}
|
|
193
|
+
{Thread.run_session(Thread.invocation(slot, detach, outcomes, small_heap, cache_space), Thread.Session{Thread.Attached{}, pool}) == None{} : Maybe<Thread.Session>}
|
|
194
|
+
|
|
195
|
+
# A native failure in any round poisons the lease, so it is never cached.
|
|
196
|
+
law failure_poisons_lease:
|
|
197
|
+
for before: List<&2, Thread.Outcome>
|
|
198
|
+
for after: List<&2, Thread.Outcome>
|
|
199
|
+
{Thread.health(List.append(&2, Thread.Outcome, before, Thread.Failed{} <> after)) == Thread.Failed{} : Thread.Outcome}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import Base
|
|
2
|
+
import ./THREAD_LAWS.bend as Laws
|
|
3
|
+
import ./thread_state.bend as Thread
|
|
4
|
+
|
|
5
|
+
# Discriminators
|
|
6
|
+
|
|
7
|
+
def none_discriminator(value: Maybe<Thread.State>) -> Type:
|
|
8
|
+
match value:
|
|
9
|
+
case None{}:
|
|
10
|
+
Unit
|
|
11
|
+
case Some{_}:
|
|
12
|
+
Empty
|
|
13
|
+
|
|
14
|
+
def none_not_some(-next: Thread.State, accepted: {None{} == Some{next} : Maybe<Thread.State>}) -> Empty:
|
|
15
|
+
%accepted : none_discriminator(_)
|
|
16
|
+
Unit{}
|
|
17
|
+
|
|
18
|
+
def true_discriminator(value: Bool) -> Type:
|
|
19
|
+
match value:
|
|
20
|
+
case True{}:
|
|
21
|
+
Unit
|
|
22
|
+
case False{}:
|
|
23
|
+
Empty
|
|
24
|
+
|
|
25
|
+
def true_not_false(different: {True{} == False{} : Bool}) -> Empty:
|
|
26
|
+
%different : true_discriminator(_)
|
|
27
|
+
Unit{}
|
|
28
|
+
|
|
29
|
+
def false_discriminator(value: Bool) -> Type:
|
|
30
|
+
match value:
|
|
31
|
+
case True{}:
|
|
32
|
+
Empty
|
|
33
|
+
case False{}:
|
|
34
|
+
Unit
|
|
35
|
+
|
|
36
|
+
def false_not_true(different: {False{} == True{} : Bool}) -> Empty:
|
|
37
|
+
%different : false_discriminator(_)
|
|
38
|
+
Unit{}
|
|
39
|
+
|
|
40
|
+
def not_true(-A: Type, different: {False{} == True{} : Bool}) -> A:
|
|
41
|
+
Empty.absurd(A, false_not_true(different))
|
|
42
|
+
|
|
43
|
+
def not_false(-A: Type, different: {True{} == False{} : Bool}) -> A:
|
|
44
|
+
Empty.absurd(A, true_not_false(different))
|
|
45
|
+
|
|
46
|
+
# Python effects
|
|
47
|
+
|
|
48
|
+
def Laws.detached_effect_rejected():
|
|
49
|
+
{==}
|
|
50
|
+
|
|
51
|
+
def Laws.accepted_effect_attached(state, next, accepted):
|
|
52
|
+
match state:
|
|
53
|
+
case Thread.Attached{}:
|
|
54
|
+
{==}
|
|
55
|
+
case Thread.Detached{}:
|
|
56
|
+
Empty.absurd({Thread.Detached{} == Thread.Attached{} : Thread.State}, none_not_some(next, accepted))
|
|
57
|
+
case Thread.AttachedNative{}:
|
|
58
|
+
Empty.absurd({Thread.AttachedNative{} == Thread.Attached{} : Thread.State}, none_not_some(next, accepted))
|
|
59
|
+
case Thread.DetachedNative{}:
|
|
60
|
+
Empty.absurd({Thread.DetachedNative{} == Thread.Attached{} : Thread.State}, none_not_some(next, accepted))
|
|
61
|
+
|
|
62
|
+
def Laws.native_only_leaves(state, operation, native, staying):
|
|
63
|
+
match state operation:
|
|
64
|
+
case Thread.Attached{} op:
|
|
65
|
+
not_true({Thread.step(Thread.Attached{}, op) == None{} : Maybe<Thread.State>}, native)
|
|
66
|
+
case Thread.Detached{} op:
|
|
67
|
+
not_true({Thread.step(Thread.Detached{}, op) == None{} : Maybe<Thread.State>}, native)
|
|
68
|
+
case Thread.AttachedNative{} Thread.Leave{outcome}:
|
|
69
|
+
not_false({Some{Thread.Attached{}} == None{} : Maybe<Thread.State>}, staying)
|
|
70
|
+
case Thread.DetachedNative{} Thread.Leave{outcome}:
|
|
71
|
+
not_false({Some{Thread.Detached{}} == None{} : Maybe<Thread.State>}, staying)
|
|
72
|
+
case Thread.AttachedNative{} Thread.Save{}:
|
|
73
|
+
{==}
|
|
74
|
+
case Thread.AttachedNative{} Thread.Restore{}:
|
|
75
|
+
{==}
|
|
76
|
+
case Thread.AttachedNative{} Thread.Enter{}:
|
|
77
|
+
{==}
|
|
78
|
+
case Thread.AttachedNative{} Thread.PythonEffect{}:
|
|
79
|
+
{==}
|
|
80
|
+
case Thread.AttachedNative{} Thread.AcquireLease{_}:
|
|
81
|
+
{==}
|
|
82
|
+
case Thread.AttachedNative{} Thread.ReturnLease{_, _, _, _}:
|
|
83
|
+
{==}
|
|
84
|
+
case Thread.DetachedNative{} Thread.Save{}:
|
|
85
|
+
{==}
|
|
86
|
+
case Thread.DetachedNative{} Thread.Restore{}:
|
|
87
|
+
{==}
|
|
88
|
+
case Thread.DetachedNative{} Thread.Enter{}:
|
|
89
|
+
{==}
|
|
90
|
+
case Thread.DetachedNative{} Thread.PythonEffect{}:
|
|
91
|
+
{==}
|
|
92
|
+
case Thread.DetachedNative{} Thread.AcquireLease{_}:
|
|
93
|
+
{==}
|
|
94
|
+
case Thread.DetachedNative{} Thread.ReturnLease{_, _, _, _}:
|
|
95
|
+
{==}
|
|
96
|
+
|
|
97
|
+
# A Python effect is not Leave, so this is a special case of native_only_leaves.
|
|
98
|
+
def Laws.native_effect_rejected(state, native):
|
|
99
|
+
Laws.native_only_leaves(state, Thread.PythonEffect{}, native, {==})
|
|
100
|
+
|
|
101
|
+
# Attachment
|
|
102
|
+
|
|
103
|
+
def Laws.save_restore():
|
|
104
|
+
{==}
|
|
105
|
+
|
|
106
|
+
def Laws.native_returns_attached(detach, outcome):
|
|
107
|
+
match detach:
|
|
108
|
+
case False{}:
|
|
109
|
+
{==}
|
|
110
|
+
case True{}:
|
|
111
|
+
{==}
|
|
112
|
+
|
|
113
|
+
def Laws.native_then_effect_accepted(detach, outcome):
|
|
114
|
+
match detach:
|
|
115
|
+
case False{}:
|
|
116
|
+
{==}
|
|
117
|
+
case True{}:
|
|
118
|
+
{==}
|
|
119
|
+
|
|
120
|
+
def Laws.release_before_restore_rejected(outcome):
|
|
121
|
+
{==}
|
|
122
|
+
|
|
123
|
+
def Laws.free_threaded_detaches(release_gil):
|
|
124
|
+
match release_gil:
|
|
125
|
+
case True{}:
|
|
126
|
+
{==}
|
|
127
|
+
case False{}:
|
|
128
|
+
{==}
|
|
129
|
+
|
|
130
|
+
# Leases
|
|
131
|
+
|
|
132
|
+
def Laws.acquire_requires_detached(state, pool, slot, attached):
|
|
133
|
+
match state:
|
|
134
|
+
case Thread.Attached{}:
|
|
135
|
+
{==}
|
|
136
|
+
case Thread.Detached{}:
|
|
137
|
+
Empty.absurd({Thread.detached_with(Thread.acquire(pool, slot)) == None{} : Maybe<Thread.Session>}, attached({==}))
|
|
138
|
+
case Thread.AttachedNative{}:
|
|
139
|
+
{==}
|
|
140
|
+
case Thread.DetachedNative{}:
|
|
141
|
+
{==}
|
|
142
|
+
|
|
143
|
+
def Laws.return_requires_detached(state, pool, slot, outcome, small_heap, cache_space, attached):
|
|
144
|
+
match state:
|
|
145
|
+
case Thread.Attached{}:
|
|
146
|
+
{==}
|
|
147
|
+
case Thread.Detached{}:
|
|
148
|
+
Empty.absurd({Thread.detached_with(Thread.release(pool, slot, outcome, small_heap, cache_space)) == None{} : Maybe<Thread.Session>}, attached({==}))
|
|
149
|
+
case Thread.AttachedNative{}:
|
|
150
|
+
{==}
|
|
151
|
+
case Thread.DetachedNative{}:
|
|
152
|
+
{==}
|
|
153
|
+
|
|
154
|
+
def Laws.reserved_unavailable(pool, slot):
|
|
155
|
+
match pool slot:
|
|
156
|
+
case [] _:
|
|
157
|
+
{==}
|
|
158
|
+
case _ <> _ 0n:
|
|
159
|
+
{==}
|
|
160
|
+
case _ <> tail 1n+pred:
|
|
161
|
+
Laws.reserved_unavailable(tail, pred)
|
|
162
|
+
|
|
163
|
+
def Laws.reserved_acquisition_rejected(pool, slot):
|
|
164
|
+
%Laws.reserved_unavailable(pool, slot) : {Thread.acquire(Thread.reserve(pool, slot), slot) == Thread.acquire_if(_, Thread.reserve(pool, slot), slot) : Maybe<List<&2, Thread.Context>>}
|
|
165
|
+
{==}
|
|
166
|
+
|
|
167
|
+
def pool_none_discriminator(value: Maybe<List<&2, Thread.Context>>) -> Type:
|
|
168
|
+
match value:
|
|
169
|
+
case None{}:
|
|
170
|
+
Unit
|
|
171
|
+
case Some{_}:
|
|
172
|
+
Empty
|
|
173
|
+
|
|
174
|
+
def pool_none_not_some(-next: List<&2, Thread.Context>,
|
|
175
|
+
acquired: {None{} == Some{next} : Maybe<List<&2, Thread.Context>>}) -> Empty:
|
|
176
|
+
%acquired : pool_none_discriminator(_)
|
|
177
|
+
Unit{}
|
|
178
|
+
|
|
179
|
+
def acquire_if_allowed(allowed: Bool, -pool: List<&2, Thread.Context>, -slot: Nat,
|
|
180
|
+
-next: List<&2, Thread.Context>,
|
|
181
|
+
acquired: {Thread.acquire_if(allowed, pool, slot) == Some{next} : Maybe<List<&2, Thread.Context>>})
|
|
182
|
+
-> {allowed == True{} : Bool}:
|
|
183
|
+
match allowed:
|
|
184
|
+
case True{}:
|
|
185
|
+
{==}
|
|
186
|
+
case False{}:
|
|
187
|
+
Empty.absurd({False{} == True{} : Bool}, pool_none_not_some(next, acquired))
|
|
188
|
+
|
|
189
|
+
def Laws.acquisition_requires_available(pool, slot, next, acquired):
|
|
190
|
+
acquire_if_allowed(Thread.available(pool, slot), pool, slot, next, acquired)
|
|
191
|
+
|
|
192
|
+
def Laws.reserved_returnable(pool, slot, free):
|
|
193
|
+
match pool slot:
|
|
194
|
+
case [] _:
|
|
195
|
+
not_true({False{} == True{} : Bool}, free)
|
|
196
|
+
case _ <> _ 0n:
|
|
197
|
+
{==}
|
|
198
|
+
case _ <> tail 1n+pred:
|
|
199
|
+
Laws.reserved_returnable(tail, pred, free)
|
|
200
|
+
|
|
201
|
+
def Laws.unleased_return_rejected(pool, slot, outcome, small_heap, cache_space, unleased):
|
|
202
|
+
%unleased : {Thread.release(pool, slot, outcome, small_heap, cache_space) == Thread.finish_if(_, pool, slot, outcome, small_heap, cache_space) : Maybe<List<&2, Thread.Context>>}
|
|
203
|
+
{==}
|
|
204
|
+
|
|
205
|
+
def completion_not_leased(outcome: Thread.Outcome, small_heap: Bool, cache_space: Bool)
|
|
206
|
+
-> {Thread.leased(Some{Thread.completion(outcome, small_heap, cache_space)}) == False{} : Bool}:
|
|
207
|
+
match outcome small_heap cache_space:
|
|
208
|
+
case Thread.Succeeded{} True{} True{}:
|
|
209
|
+
{==}
|
|
210
|
+
case Thread.Succeeded{} True{} False{}:
|
|
211
|
+
{==}
|
|
212
|
+
case Thread.Succeeded{} False{} _:
|
|
213
|
+
{==}
|
|
214
|
+
case Thread.Failed{} _ _:
|
|
215
|
+
{==}
|
|
216
|
+
|
|
217
|
+
def Laws.double_return_rejected(pool, slot, outcome, small_heap, cache_space):
|
|
218
|
+
match pool slot:
|
|
219
|
+
case [] _:
|
|
220
|
+
{==}
|
|
221
|
+
case _ <> _ 0n:
|
|
222
|
+
completion_not_leased(outcome, small_heap, cache_space)
|
|
223
|
+
case _ <> tail 1n+pred:
|
|
224
|
+
Laws.double_return_rejected(tail, pred, outcome, small_heap, cache_space)
|
|
225
|
+
|
|
226
|
+
def Laws.context_update_isolated(pool, target, other, value, different):
|
|
227
|
+
match pool target other:
|
|
228
|
+
case [] _ _:
|
|
229
|
+
{==}
|
|
230
|
+
case head <> _ 0n 0n:
|
|
231
|
+
Empty.absurd({Some{value} == Some{head} : Maybe<&2, Thread.Context>}, true_not_false(different))
|
|
232
|
+
case _ <> _ 0n 1n+_:
|
|
233
|
+
{==}
|
|
234
|
+
case _ <> _ 1n+_ 0n:
|
|
235
|
+
{==}
|
|
236
|
+
case _ <> tail 1n+pred 1n+rest:
|
|
237
|
+
Laws.context_update_isolated(tail, pred, rest, value, different)
|
|
238
|
+
|
|
239
|
+
def Laws.failure_isolated(small_heap, cache_space, pool, target, other, different):
|
|
240
|
+
Laws.context_update_isolated(pool, target, other, Thread.Discarded{}, different)
|
|
241
|
+
|
|
242
|
+
# Reuse
|
|
243
|
+
|
|
244
|
+
def Laws.failed_context_discarded(small_heap, cache_space):
|
|
245
|
+
{==}
|
|
246
|
+
|
|
247
|
+
def Laws.failed_context_unavailable(small_heap, cache_space, pool, slot):
|
|
248
|
+
match pool slot:
|
|
249
|
+
case [] _:
|
|
250
|
+
{==}
|
|
251
|
+
case _ <> _ 0n:
|
|
252
|
+
{==}
|
|
253
|
+
case _ <> tail 1n+pred:
|
|
254
|
+
Laws.failed_context_unavailable(small_heap, cache_space, tail, pred)
|
|
255
|
+
|
|
256
|
+
def Laws.successful_context_reusable():
|
|
257
|
+
{==}
|
|
258
|
+
|
|
259
|
+
def idle_discriminator(value: Thread.Context) -> Type:
|
|
260
|
+
match value:
|
|
261
|
+
case Thread.Idle{}:
|
|
262
|
+
Empty
|
|
263
|
+
case Thread.Leased{}:
|
|
264
|
+
Unit
|
|
265
|
+
case Thread.Discarded{}:
|
|
266
|
+
Unit
|
|
267
|
+
|
|
268
|
+
def discarded_empty(reusable: {Thread.Discarded{} == Thread.Idle{} : Thread.Context}) -> Empty:
|
|
269
|
+
%reusable : idle_discriminator(_)
|
|
270
|
+
Unit{}
|
|
271
|
+
|
|
272
|
+
def discarded_not_idle(-A: Type, reusable: {Thread.Discarded{} == Thread.Idle{} : Thread.Context}) -> A:
|
|
273
|
+
Empty.absurd(A, discarded_empty(reusable))
|
|
274
|
+
|
|
275
|
+
def Laws.reusable_requires_success(outcome, small_heap, cache_space, reusable):
|
|
276
|
+
match outcome small_heap cache_space:
|
|
277
|
+
case Thread.Succeeded{} _ _:
|
|
278
|
+
{==}
|
|
279
|
+
case Thread.Failed{} _ _:
|
|
280
|
+
discarded_not_idle({Thread.Failed{} == Thread.Succeeded{} : Thread.Outcome}, reusable)
|
|
281
|
+
|
|
282
|
+
def Laws.reusable_requires_small_heap(outcome, small_heap, cache_space, reusable):
|
|
283
|
+
match outcome small_heap cache_space:
|
|
284
|
+
case _ True{} _:
|
|
285
|
+
{==}
|
|
286
|
+
case Thread.Succeeded{} False{} _:
|
|
287
|
+
discarded_not_idle({False{} == True{} : Bool}, reusable)
|
|
288
|
+
case Thread.Failed{} False{} _:
|
|
289
|
+
discarded_not_idle({False{} == True{} : Bool}, reusable)
|
|
290
|
+
|
|
291
|
+
def Laws.reusable_requires_cache_space(outcome, small_heap, cache_space, reusable):
|
|
292
|
+
match outcome small_heap cache_space:
|
|
293
|
+
case _ _ True{}:
|
|
294
|
+
{==}
|
|
295
|
+
case Thread.Succeeded{} True{} False{}:
|
|
296
|
+
discarded_not_idle({False{} == True{} : Bool}, reusable)
|
|
297
|
+
case Thread.Succeeded{} False{} False{}:
|
|
298
|
+
discarded_not_idle({False{} == True{} : Bool}, reusable)
|
|
299
|
+
case Thread.Failed{} _ False{}:
|
|
300
|
+
discarded_not_idle({False{} == True{} : Bool}, reusable)
|
|
301
|
+
|
|
302
|
+
# Whole invocations
|
|
303
|
+
|
|
304
|
+
# Rounds start and end attached and never touch the pool.
|
|
305
|
+
def rounds_attached(detach: Bool, outcomes: List<&2, Thread.Outcome>, -rest: List<Thread.Operation>, -pool: List<&2, Thread.Context>)
|
|
306
|
+
-> {Thread.run_session(List.append(&1, Thread.Operation, Thread.rounds(detach, outcomes), rest), Thread.Session{Thread.Attached{}, pool}) == Thread.run_session(rest, Thread.Session{Thread.Attached{}, pool}) : Maybe<Thread.Session>}:
|
|
307
|
+
match detach outcomes:
|
|
308
|
+
case _ Nil{}:
|
|
309
|
+
{==}
|
|
310
|
+
case True{} _ <> tail:
|
|
311
|
+
rounds_attached(True{}, tail, rest, pool)
|
|
312
|
+
case False{} _ <> tail:
|
|
313
|
+
rounds_attached(False{}, tail, rest, pool)
|
|
314
|
+
|
|
315
|
+
# Returning a lease overwrites the Leased mark it was acquired with.
|
|
316
|
+
def set_twice(pool: List<&2, Thread.Context>, slot: Nat, -first: Thread.Context, -second: Thread.Context)
|
|
317
|
+
-> {List.set(&2, Thread.Context, List.set(&2, Thread.Context, pool, slot, first), slot, second) == List.set(&2, Thread.Context, pool, slot, second) : List<&2, Thread.Context>}:
|
|
318
|
+
match pool slot:
|
|
319
|
+
case [] _:
|
|
320
|
+
{==}
|
|
321
|
+
case _ <> _ 0n:
|
|
322
|
+
{==}
|
|
323
|
+
case head <> tail 1n+pred:
|
|
324
|
+
%set_twice(tail, pred, first, second) : {head <> List.set(&2, Thread.Context, List.set(&2, Thread.Context, tail, pred, first), pred, second) == head <> _ : List<&2, Thread.Context>}
|
|
325
|
+
{==}
|
|
326
|
+
|
|
327
|
+
# The operations after acquisition, and the session an invocation should end in.
|
|
328
|
+
def after_acquire(slot: Nat, detach: Bool, +outcomes: List<&2, Thread.Outcome>, small_heap: Bool, cache_space: Bool) -> List<Thread.Operation>:
|
|
329
|
+
Thread.Restore{} <> List.append(&1, Thread.Operation, Thread.rounds(detach, outcomes),
|
|
330
|
+
Thread.return_call(slot, Thread.health(outcomes), small_heap, cache_space))
|
|
331
|
+
|
|
332
|
+
def finished(pool: List<&2, Thread.Context>, slot: Nat, outcomes: List<&2, Thread.Outcome>, small_heap: Bool, cache_space: Bool) -> Maybe<Thread.Session>:
|
|
333
|
+
Some{Thread.Session{Thread.Attached{}, Thread.finish(pool, slot, Thread.health(outcomes), small_heap, cache_space)}}
|
|
334
|
+
|
|
335
|
+
def returned(slot: Nat, +outcomes: List<&2, Thread.Outcome>, small_heap: Bool, cache_space: Bool) -> List<Thread.Operation>:
|
|
336
|
+
Thread.return_call(slot, Thread.health(outcomes), small_heap, cache_space)
|
|
337
|
+
|
|
338
|
+
def Laws.invocation_returns_attached(pool, slot, detach, outcomes, small_heap, cache_space, free):
|
|
339
|
+
%Equal.sym(Bool, Thread.available(pool, slot), True{}, free) : {Maybe.bind(&1, Thread.Session, Thread.Session, Thread.detached_with(Thread.acquire_if(_, pool, slot)), next => Thread.run_session(after_acquire(slot, detach, outcomes, small_heap, cache_space), next)) == finished(pool, slot, outcomes, small_heap, cache_space) : Maybe<Thread.Session>}
|
|
340
|
+
%Equal.sym(Maybe<Thread.Session>,
|
|
341
|
+
Thread.run_session(List.append(&1, Thread.Operation, Thread.rounds(detach, outcomes), returned(slot, outcomes, small_heap, cache_space)), Thread.Session{Thread.Attached{}, Thread.reserve(pool, slot)}),
|
|
342
|
+
Thread.run_session(returned(slot, outcomes, small_heap, cache_space), Thread.Session{Thread.Attached{}, Thread.reserve(pool, slot)}),
|
|
343
|
+
rounds_attached(detach, outcomes, returned(slot, outcomes, small_heap, cache_space), Thread.reserve(pool, slot))) : {_ == finished(pool, slot, outcomes, small_heap, cache_space) : Maybe<Thread.Session>}
|
|
344
|
+
%Equal.sym(Bool, Thread.returnable(Thread.reserve(pool, slot), slot), True{}, Laws.reserved_returnable(pool, slot, free)) : {Maybe.bind(&1, Thread.Session, Thread.Session, Thread.detached_with(Thread.finish_if(_, Thread.reserve(pool, slot), slot, Thread.health(outcomes), small_heap, cache_space)), next => Thread.run_session([Thread.Restore{}], next)) == finished(pool, slot, outcomes, small_heap, cache_space) : Maybe<Thread.Session>}
|
|
345
|
+
%Equal.sym(List<&2, Thread.Context>,
|
|
346
|
+
List.set(&2, Thread.Context, Thread.reserve(pool, slot), slot, Thread.completion(Thread.health(outcomes), small_heap, cache_space)),
|
|
347
|
+
List.set(&2, Thread.Context, pool, slot, Thread.completion(Thread.health(outcomes), small_heap, cache_space)),
|
|
348
|
+
set_twice(pool, slot, Thread.Leased{}, Thread.completion(Thread.health(outcomes), small_heap, cache_space))) : {Some{Thread.Session{Thread.Attached{}, _}} == finished(pool, slot, outcomes, small_heap, cache_space) : Maybe<Thread.Session>}
|
|
349
|
+
{==}
|
|
350
|
+
|
|
351
|
+
def Laws.leased_invocation_rejected(pool, slot, detach, outcomes, small_heap, cache_space, busy):
|
|
352
|
+
%Equal.sym(Bool, Thread.available(pool, slot), False{}, busy) : {Maybe.bind(&1, Thread.Session, Thread.Session, Thread.detached_with(Thread.acquire_if(_, pool, slot)), next => Thread.run_session(after_acquire(slot, detach, outcomes, small_heap, cache_space), next)) == None{} : Maybe<Thread.Session>}
|
|
353
|
+
{==}
|
|
354
|
+
|
|
355
|
+
def Laws.failure_poisons_lease(before, after):
|
|
356
|
+
match before:
|
|
357
|
+
case []:
|
|
358
|
+
{==}
|
|
359
|
+
case Thread.Succeeded{} <> tail:
|
|
360
|
+
Laws.failure_poisons_lease(tail, after)
|
|
361
|
+
case Thread.Failed{} <> _:
|
|
362
|
+
{==}
|