Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/test-programs/src/bin/async_cancel_callee.rs
1693 views
1
mod bindings {
2
wit_bindgen::generate!({
3
path: "../misc/component-async-tests/wit",
4
world: "cancel-callee",
5
});
6
}
7
8
use test_programs::async_::{
9
CALLBACK_CODE_EXIT, CALLBACK_CODE_WAIT, EVENT_CANCELLED, EVENT_NONE, EVENT_SUBTASK,
10
STATUS_RETURN_CANCELLED, STATUS_RETURNED, STATUS_STARTED, context_get, context_set,
11
subtask_cancel, subtask_drop, task_cancel, waitable_join, waitable_set_drop, waitable_set_new,
12
};
13
14
#[cfg(target_arch = "wasm32")]
15
#[link(wasm_import_module = "[export]local:local/sleep-with-options")]
16
unsafe extern "C" {
17
#[link_name = "[task-return][async]sleep-millis"]
18
fn task_return_sleep_millis();
19
}
20
#[cfg(not(target_arch = "wasm32"))]
21
unsafe extern "C" fn task_return_sleep_millis() {
22
unreachable!()
23
}
24
25
#[cfg(target_arch = "wasm32")]
26
#[link(wasm_import_module = "local:local/sleep")]
27
unsafe extern "C" {
28
#[link_name = "[async]sleep-millis"]
29
fn sleep_millis(_: u64);
30
}
31
#[cfg(not(target_arch = "wasm32"))]
32
unsafe fn sleep_millis(_: u64) {
33
unreachable!()
34
}
35
36
#[cfg(target_arch = "wasm32")]
37
#[link(wasm_import_module = "local:local/sleep")]
38
unsafe extern "C" {
39
#[link_name = "[async-lower][async]sleep-millis"]
40
fn sleep_millis_async(ms: u64) -> u32;
41
}
42
#[cfg(not(target_arch = "wasm32"))]
43
unsafe fn sleep_millis_async(_ms: u64) -> u32 {
44
unreachable!()
45
}
46
47
const ON_CANCEL_TASK_RETURN: u8 = 0;
48
const ON_CANCEL_TASK_CANCEL: u8 = 1;
49
50
const _MODE_NORMAL: u8 = 0;
51
const _MODE_TRAP_CANCEL_GUEST_AFTER_START_CANCELLED: u8 = 1;
52
const _MODE_TRAP_CANCEL_GUEST_AFTER_RETURN_CANCELLED: u8 = 2;
53
const _MODE_TRAP_CANCEL_GUEST_AFTER_RETURN: u8 = 3;
54
const MODE_TRAP_CANCEL_HOST_AFTER_RETURN_CANCELLED: u8 = 4;
55
const MODE_TRAP_CANCEL_HOST_AFTER_RETURN: u8 = 5;
56
const MODE_LEAK_TASK_AFTER_CANCEL: u8 = 6;
57
58
#[derive(Clone, Copy)]
59
struct SleepParams {
60
time_in_millis: u64,
61
on_cancel: u8,
62
on_cancel_delay_millis: u64,
63
synchronous_delay: bool,
64
mode: u8,
65
}
66
67
enum State {
68
S0(SleepParams),
69
S1 {
70
set: u32,
71
waitable: u32,
72
params: SleepParams,
73
},
74
S2 {
75
set: u32,
76
waitable: u32,
77
params: SleepParams,
78
},
79
}
80
81
#[unsafe(export_name = "local:local/backpressure#set-backpressure")]
82
unsafe extern "C" fn export_set_backpressure(enabled: bool) {
83
wit_bindgen::backpressure_set(enabled);
84
}
85
86
#[unsafe(export_name = "local:local/sleep#[async]sleep-millis")]
87
unsafe extern "C" fn export_sleep_sleep_millis(time_in_millis: u64) {
88
unsafe {
89
sleep_millis(time_in_millis);
90
}
91
}
92
93
#[unsafe(export_name = "[async-lift]local:local/sleep-with-options#[async]sleep-millis")]
94
unsafe extern "C" fn export_sleep_with_options_sleep_millis(
95
time_in_millis: u64,
96
on_cancel: u8,
97
on_cancel_delay_millis: u64,
98
synchronous_delay: bool,
99
mode: u8,
100
) -> u32 {
101
unsafe {
102
context_set(
103
u32::try_from(Box::into_raw(Box::new(State::S0(SleepParams {
104
time_in_millis,
105
on_cancel,
106
on_cancel_delay_millis,
107
synchronous_delay,
108
mode,
109
}))) as usize)
110
.unwrap(),
111
);
112
callback_sleep_with_options_sleep_millis(EVENT_NONE, 0, 0)
113
}
114
}
115
116
#[unsafe(export_name = "[callback][async-lift]local:local/sleep-with-options#[async]sleep-millis")]
117
unsafe extern "C" fn callback_sleep_with_options_sleep_millis(
118
event0: u32,
119
event1: u32,
120
event2: u32,
121
) -> u32 {
122
unsafe {
123
let state = &mut *(usize::try_from(context_get()).unwrap() as *mut State);
124
match state {
125
State::S0(params) => {
126
assert_eq!(event0, EVENT_NONE);
127
128
let status = sleep_millis_async(params.time_in_millis);
129
130
let waitable = status >> 4;
131
let status = status & 0xF;
132
133
assert_eq!(status, STATUS_STARTED);
134
135
let set = waitable_set_new();
136
waitable_join(waitable, set);
137
138
*state = State::S1 {
139
set,
140
waitable,
141
params: *params,
142
};
143
144
CALLBACK_CODE_WAIT | (set << 4)
145
}
146
147
State::S1 {
148
set,
149
waitable,
150
params,
151
} => {
152
assert_eq!(event0, EVENT_CANCELLED);
153
154
let result = subtask_cancel(*waitable);
155
156
assert_eq!(result, STATUS_RETURN_CANCELLED);
157
158
if params.mode == MODE_TRAP_CANCEL_HOST_AFTER_RETURN_CANCELLED {
159
// This should trap, since `waitable` has already been
160
// cancelled:
161
subtask_cancel(*waitable);
162
unreachable!()
163
}
164
165
waitable_join(*waitable, 0);
166
167
if params.mode != MODE_LEAK_TASK_AFTER_CANCEL {
168
subtask_drop(*waitable);
169
}
170
171
if params.on_cancel_delay_millis == 0 {
172
match params.on_cancel {
173
ON_CANCEL_TASK_RETURN => task_return_sleep_millis(),
174
ON_CANCEL_TASK_CANCEL => task_cancel(),
175
_ => unreachable!(),
176
}
177
178
CALLBACK_CODE_EXIT
179
} else if params.synchronous_delay {
180
sleep_millis(params.on_cancel_delay_millis);
181
182
match params.on_cancel {
183
ON_CANCEL_TASK_RETURN => task_return_sleep_millis(),
184
ON_CANCEL_TASK_CANCEL => task_cancel(),
185
_ => unreachable!(),
186
}
187
188
CALLBACK_CODE_EXIT
189
} else {
190
let status = sleep_millis_async(params.on_cancel_delay_millis);
191
192
let waitable = status >> 4;
193
let status = status & 0xF;
194
195
assert_eq!(status, STATUS_STARTED);
196
197
waitable_join(waitable, *set);
198
199
let set = *set;
200
201
*state = State::S2 {
202
set,
203
waitable,
204
params: *params,
205
};
206
207
CALLBACK_CODE_WAIT | (set << 4)
208
}
209
}
210
211
State::S2 {
212
set,
213
waitable,
214
params,
215
} => {
216
assert_eq!(event0, EVENT_SUBTASK);
217
assert_eq!(event1, *waitable);
218
assert_eq!(event2, STATUS_RETURNED);
219
220
if params.mode == MODE_TRAP_CANCEL_HOST_AFTER_RETURN {
221
// This should trap, since `waitable` has already returned:
222
subtask_cancel(*waitable);
223
unreachable!()
224
}
225
226
waitable_join(*waitable, 0);
227
subtask_drop(*waitable);
228
waitable_set_drop(*set);
229
230
match params.on_cancel {
231
ON_CANCEL_TASK_RETURN => task_return_sleep_millis(),
232
ON_CANCEL_TASK_CANCEL => task_cancel(),
233
_ => unreachable!(),
234
}
235
236
CALLBACK_CODE_EXIT
237
}
238
}
239
}
240
}
241
242
// Unused function; required since this file is built as a `bin`:
243
fn main() {}
244
245