Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/c-api/src/async.rs
1692 views
1
use std::ffi::c_void;
2
use std::future::Future;
3
use std::mem::{self, MaybeUninit};
4
use std::num::NonZeroU64;
5
use std::ops::Range;
6
use std::pin::Pin;
7
use std::sync::Arc;
8
use std::task::{Context, Poll, Waker};
9
use std::{ptr, str};
10
use wasmtime::{
11
AsContextMut, Func, Instance, Result, RootScope, StackCreator, StackMemory, Trap, Val,
12
};
13
14
use crate::{
15
WASMTIME_I32, WasmtimeCaller, WasmtimeStoreContextMut, bad_utf8, handle_result, to_str,
16
translate_args, wasm_config_t, wasm_functype_t, wasm_trap_t, wasmtime_caller_t,
17
wasmtime_error_t, wasmtime_instance_pre_t, wasmtime_linker_t, wasmtime_module_t,
18
wasmtime_val_t, wasmtime_val_union,
19
};
20
21
#[unsafe(no_mangle)]
22
pub extern "C" fn wasmtime_config_async_support_set(c: &mut wasm_config_t, enable: bool) {
23
c.config.async_support(enable);
24
}
25
26
#[unsafe(no_mangle)]
27
pub extern "C" fn wasmtime_config_async_stack_size_set(c: &mut wasm_config_t, size: usize) {
28
c.config.async_stack_size(size);
29
}
30
31
#[unsafe(no_mangle)]
32
pub extern "C" fn wasmtime_context_epoch_deadline_async_yield_and_update(
33
mut store: WasmtimeStoreContextMut<'_>,
34
delta: u64,
35
) {
36
store.epoch_deadline_async_yield_and_update(delta);
37
}
38
39
#[unsafe(no_mangle)]
40
pub extern "C" fn wasmtime_context_fuel_async_yield_interval(
41
mut store: WasmtimeStoreContextMut<'_>,
42
interval: Option<NonZeroU64>,
43
) -> Option<Box<wasmtime_error_t>> {
44
handle_result(
45
store.fuel_async_yield_interval(interval.map(|n| n.get())),
46
|()| {},
47
)
48
}
49
50
pub type wasmtime_func_async_callback_t = extern "C" fn(
51
*mut c_void,
52
*mut wasmtime_caller_t,
53
*const wasmtime_val_t,
54
usize,
55
*mut wasmtime_val_t,
56
usize,
57
&mut Option<Box<wasm_trap_t>>,
58
&mut wasmtime_async_continuation_t,
59
);
60
61
#[repr(C)]
62
pub struct wasmtime_async_continuation_t {
63
pub callback: wasmtime_func_async_continuation_callback_t,
64
pub env: *mut c_void,
65
pub finalizer: Option<extern "C" fn(*mut c_void)>,
66
}
67
68
unsafe impl Send for wasmtime_async_continuation_t {}
69
unsafe impl Sync for wasmtime_async_continuation_t {}
70
impl Drop for wasmtime_async_continuation_t {
71
fn drop(&mut self) {
72
if let Some(f) = self.finalizer {
73
f(self.env);
74
}
75
}
76
}
77
impl Future for wasmtime_async_continuation_t {
78
type Output = ();
79
fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
80
let this = self.get_mut();
81
let cb = this.callback;
82
if cb(this.env) {
83
Poll::Ready(())
84
} else {
85
Poll::Pending
86
}
87
}
88
}
89
90
/// Internal structure to add Send/Sync to a c_void member.
91
///
92
/// This is useful in closures that need to capture some C data.
93
#[derive(Debug)]
94
struct CallbackDataPtr {
95
pub ptr: *mut std::ffi::c_void,
96
}
97
98
unsafe impl Send for CallbackDataPtr {}
99
unsafe impl Sync for CallbackDataPtr {}
100
101
pub type wasmtime_func_async_continuation_callback_t = extern "C" fn(*mut c_void) -> bool;
102
103
async fn invoke_c_async_callback<'a>(
104
cb: wasmtime_func_async_callback_t,
105
data: CallbackDataPtr,
106
mut caller: WasmtimeCaller<'a>,
107
params: &'a [Val],
108
results: &'a mut [Val],
109
) -> Result<()> {
110
// Convert `params/results` to `wasmtime_val_t`. Use the previous
111
// storage in `hostcall_val_storage` to help avoid allocations all the
112
// time.
113
let mut hostcall_val_storage = mem::take(&mut caller.data_mut().hostcall_val_storage);
114
debug_assert!(hostcall_val_storage.is_empty());
115
hostcall_val_storage.reserve(params.len() + results.len());
116
hostcall_val_storage.extend(
117
params
118
.iter()
119
.cloned()
120
.map(|p| wasmtime_val_t::from_val_unscoped(&mut caller, p)),
121
);
122
hostcall_val_storage.extend((0..results.len()).map(|_| wasmtime_val_t {
123
kind: WASMTIME_I32,
124
of: wasmtime_val_union { i32: 0 },
125
}));
126
let (params, out_results) = hostcall_val_storage.split_at_mut(params.len());
127
128
// Invoke the C function pointer.
129
// The result will be a continuation which we will wrap in a Future.
130
let mut caller = wasmtime_caller_t { caller };
131
let mut trap = None;
132
extern "C" fn panic_callback(_: *mut c_void) -> bool {
133
panic!("callback must be set")
134
}
135
let mut continuation = wasmtime_async_continuation_t {
136
callback: panic_callback,
137
env: ptr::null_mut(),
138
finalizer: None,
139
};
140
cb(
141
data.ptr,
142
&mut caller,
143
params.as_ptr(),
144
params.len(),
145
out_results.as_mut_ptr(),
146
out_results.len(),
147
&mut trap,
148
&mut continuation,
149
);
150
continuation.await;
151
152
if let Some(trap) = trap {
153
return Err(trap.error);
154
}
155
156
// Translate the `wasmtime_val_t` results into the `results` space
157
for (i, result) in out_results.iter().enumerate() {
158
unsafe {
159
results[i] = result.to_val_unscoped(&mut caller.caller);
160
}
161
}
162
// Move our `vals` storage back into the store now that we no longer
163
// need it. This'll get picked up by the next hostcall and reuse our
164
// same storage.
165
hostcall_val_storage.truncate(0);
166
caller.caller.data_mut().hostcall_val_storage = hostcall_val_storage;
167
Ok(())
168
}
169
170
unsafe fn c_async_callback_to_rust_fn(
171
callback: wasmtime_func_async_callback_t,
172
data: *mut c_void,
173
finalizer: Option<extern "C" fn(*mut std::ffi::c_void)>,
174
) -> impl for<'a> Fn(
175
WasmtimeCaller<'a>,
176
&'a [Val],
177
&'a mut [Val],
178
) -> Box<dyn Future<Output = Result<()>> + Send + 'a>
179
+ Send
180
+ Sync
181
+ 'static {
182
let foreign = crate::ForeignData { data, finalizer };
183
move |caller, params, results| {
184
let _ = &foreign; // move entire foreign into this closure
185
let data = CallbackDataPtr { ptr: foreign.data };
186
Box::new(invoke_c_async_callback(
187
callback, data, caller, params, results,
188
))
189
}
190
}
191
192
#[repr(transparent)]
193
pub struct wasmtime_call_future_t<'a> {
194
underlying: Pin<Box<dyn Future<Output = ()> + 'a>>,
195
}
196
197
#[unsafe(no_mangle)]
198
pub extern "C" fn wasmtime_call_future_delete(_future: Box<wasmtime_call_future_t>) {}
199
200
#[unsafe(no_mangle)]
201
pub extern "C" fn wasmtime_call_future_poll(future: &mut wasmtime_call_future_t) -> bool {
202
match future
203
.underlying
204
.as_mut()
205
.poll(&mut Context::from_waker(Waker::noop()))
206
{
207
Poll::Ready(()) => true,
208
Poll::Pending => false,
209
}
210
}
211
212
fn handle_call_error(
213
err: wasmtime::Error,
214
trap_ret: &mut *mut wasm_trap_t,
215
err_ret: &mut *mut wasmtime_error_t,
216
) {
217
if err.is::<Trap>() {
218
*trap_ret = Box::into_raw(Box::new(wasm_trap_t::new(err)));
219
} else {
220
*err_ret = Box::into_raw(Box::new(wasmtime_error_t::from(err)));
221
}
222
}
223
224
async fn do_func_call_async(
225
mut store: RootScope<WasmtimeStoreContextMut<'_>>,
226
func: &Func,
227
args: impl ExactSizeIterator<Item = Val>,
228
results: &mut [MaybeUninit<wasmtime_val_t>],
229
trap_ret: &mut *mut wasm_trap_t,
230
err_ret: &mut *mut wasmtime_error_t,
231
) {
232
let mut params = mem::take(&mut store.as_context_mut().data_mut().wasm_val_storage);
233
let (wt_params, wt_results) = translate_args(&mut params, args, results.len());
234
let result = func.call_async(&mut store, wt_params, wt_results).await;
235
236
match result {
237
Ok(()) => {
238
for (slot, val) in results.iter_mut().zip(wt_results.iter()) {
239
crate::initialize(slot, wasmtime_val_t::from_val(&mut store, *val));
240
}
241
params.truncate(0);
242
store.as_context_mut().data_mut().wasm_val_storage = params;
243
}
244
Err(err) => handle_call_error(err, trap_ret, err_ret),
245
}
246
}
247
248
#[unsafe(no_mangle)]
249
pub unsafe extern "C" fn wasmtime_func_call_async<'a>(
250
store: WasmtimeStoreContextMut<'a>,
251
func: &'a Func,
252
args: *const wasmtime_val_t,
253
nargs: usize,
254
results: *mut MaybeUninit<wasmtime_val_t>,
255
nresults: usize,
256
trap_ret: &'a mut *mut wasm_trap_t,
257
err_ret: &'a mut *mut wasmtime_error_t,
258
) -> Box<wasmtime_call_future_t<'a>> {
259
let mut scope = RootScope::new(store);
260
let args = crate::slice_from_raw_parts(args, nargs)
261
.iter()
262
.map(|i| i.to_val(&mut scope))
263
.collect::<Vec<_>>();
264
let results = crate::slice_from_raw_parts_mut(results, nresults);
265
let fut = Box::pin(do_func_call_async(
266
scope,
267
func,
268
args.into_iter(),
269
results,
270
trap_ret,
271
err_ret,
272
));
273
Box::new(wasmtime_call_future_t { underlying: fut })
274
}
275
276
#[unsafe(no_mangle)]
277
pub unsafe extern "C" fn wasmtime_linker_define_async_func(
278
linker: &mut wasmtime_linker_t,
279
module: *const u8,
280
module_len: usize,
281
name: *const u8,
282
name_len: usize,
283
ty: &wasm_functype_t,
284
callback: crate::wasmtime_func_async_callback_t,
285
data: *mut c_void,
286
finalizer: Option<extern "C" fn(*mut std::ffi::c_void)>,
287
) -> Option<Box<wasmtime_error_t>> {
288
let ty = ty.ty().ty(linker.linker.engine());
289
let module = to_str!(module, module_len);
290
let name = to_str!(name, name_len);
291
let cb = c_async_callback_to_rust_fn(callback, data, finalizer);
292
293
handle_result(
294
linker.linker.func_new_async(module, name, ty, cb),
295
|_linker| (),
296
)
297
}
298
299
async fn do_linker_instantiate_async(
300
linker: &wasmtime_linker_t,
301
store: WasmtimeStoreContextMut<'_>,
302
module: &wasmtime_module_t,
303
instance_ptr: &mut Instance,
304
trap_ret: &mut *mut wasm_trap_t,
305
err_ret: &mut *mut wasmtime_error_t,
306
) {
307
let result = linker.linker.instantiate_async(store, &module.module).await;
308
match result {
309
Ok(instance) => *instance_ptr = instance,
310
Err(err) => handle_call_error(err, trap_ret, err_ret),
311
}
312
}
313
314
#[unsafe(no_mangle)]
315
pub extern "C" fn wasmtime_linker_instantiate_async<'a>(
316
linker: &'a wasmtime_linker_t,
317
store: WasmtimeStoreContextMut<'a>,
318
module: &'a wasmtime_module_t,
319
instance_ptr: &'a mut Instance,
320
trap_ret: &'a mut *mut wasm_trap_t,
321
err_ret: &'a mut *mut wasmtime_error_t,
322
) -> Box<crate::wasmtime_call_future_t<'a>> {
323
let fut = Box::pin(do_linker_instantiate_async(
324
linker,
325
store,
326
module,
327
instance_ptr,
328
trap_ret,
329
err_ret,
330
));
331
Box::new(crate::wasmtime_call_future_t { underlying: fut })
332
}
333
334
async fn do_instance_pre_instantiate_async(
335
instance_pre: &wasmtime_instance_pre_t,
336
store: WasmtimeStoreContextMut<'_>,
337
instance_ptr: &mut Instance,
338
trap_ret: &mut *mut wasm_trap_t,
339
err_ret: &mut *mut wasmtime_error_t,
340
) {
341
let result = instance_pre.underlying.instantiate_async(store).await;
342
match result {
343
Ok(instance) => *instance_ptr = instance,
344
Err(err) => handle_call_error(err, trap_ret, err_ret),
345
}
346
}
347
348
#[unsafe(no_mangle)]
349
pub extern "C" fn wasmtime_instance_pre_instantiate_async<'a>(
350
instance_pre: &'a wasmtime_instance_pre_t,
351
store: WasmtimeStoreContextMut<'a>,
352
instance_ptr: &'a mut Instance,
353
trap_ret: &'a mut *mut wasm_trap_t,
354
err_ret: &'a mut *mut wasmtime_error_t,
355
) -> Box<crate::wasmtime_call_future_t<'a>> {
356
let fut = Box::pin(do_instance_pre_instantiate_async(
357
instance_pre,
358
store,
359
instance_ptr,
360
trap_ret,
361
err_ret,
362
));
363
Box::new(crate::wasmtime_call_future_t { underlying: fut })
364
}
365
366
pub type wasmtime_stack_memory_get_callback_t =
367
extern "C" fn(env: *mut std::ffi::c_void, out_len: &mut usize) -> *mut u8;
368
369
#[repr(C)]
370
pub struct wasmtime_stack_memory_t {
371
env: *mut std::ffi::c_void,
372
get_stack_memory: wasmtime_stack_memory_get_callback_t,
373
finalizer: Option<extern "C" fn(arg1: *mut std::ffi::c_void)>,
374
}
375
376
struct CHostStackMemory {
377
foreign: crate::ForeignData,
378
get_memory: wasmtime_stack_memory_get_callback_t,
379
}
380
unsafe impl Send for CHostStackMemory {}
381
unsafe impl Sync for CHostStackMemory {}
382
unsafe impl StackMemory for CHostStackMemory {
383
fn top(&self) -> *mut u8 {
384
let mut len = 0;
385
let cb = self.get_memory;
386
cb(self.foreign.data, &mut len)
387
}
388
fn range(&self) -> Range<usize> {
389
let mut len = 0;
390
let cb = self.get_memory;
391
let top = cb(self.foreign.data, &mut len);
392
let base = unsafe { top.sub(len) as usize };
393
base..base + len
394
}
395
fn guard_range(&self) -> Range<*mut u8> {
396
std::ptr::null_mut()..std::ptr::null_mut()
397
}
398
}
399
400
pub type wasmtime_new_stack_memory_callback_t = extern "C" fn(
401
env: *mut std::ffi::c_void,
402
size: usize,
403
zeroed: bool,
404
stack_ret: &mut wasmtime_stack_memory_t,
405
) -> Option<Box<wasmtime_error_t>>;
406
407
#[repr(C)]
408
pub struct wasmtime_stack_creator_t {
409
env: *mut std::ffi::c_void,
410
new_stack: wasmtime_new_stack_memory_callback_t,
411
finalizer: Option<extern "C" fn(arg1: *mut std::ffi::c_void)>,
412
}
413
414
struct CHostStackCreator {
415
foreign: crate::ForeignData,
416
new_stack: wasmtime_new_stack_memory_callback_t,
417
}
418
unsafe impl Send for CHostStackCreator {}
419
unsafe impl Sync for CHostStackCreator {}
420
unsafe impl StackCreator for CHostStackCreator {
421
fn new_stack(&self, size: usize, zeroed: bool) -> Result<Box<dyn wasmtime::StackMemory>> {
422
extern "C" fn panic_callback(_env: *mut std::ffi::c_void, _out_len: &mut usize) -> *mut u8 {
423
panic!("a callback must be set");
424
}
425
let mut out = wasmtime_stack_memory_t {
426
env: ptr::null_mut(),
427
get_stack_memory: panic_callback,
428
finalizer: None,
429
};
430
let cb = self.new_stack;
431
let result = cb(self.foreign.data, size, zeroed, &mut out);
432
match result {
433
Some(error) => Err((*error).into()),
434
None => Ok(Box::new(CHostStackMemory {
435
foreign: crate::ForeignData {
436
data: out.env,
437
finalizer: out.finalizer,
438
},
439
get_memory: out.get_stack_memory,
440
})),
441
}
442
}
443
}
444
445
#[unsafe(no_mangle)]
446
pub unsafe extern "C" fn wasmtime_config_host_stack_creator_set(
447
c: &mut wasm_config_t,
448
creator: &wasmtime_stack_creator_t,
449
) {
450
c.config.with_host_stack(Arc::new(CHostStackCreator {
451
foreign: crate::ForeignData {
452
data: creator.env,
453
finalizer: creator.finalizer,
454
},
455
new_stack: creator.new_stack,
456
}));
457
}
458
459