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
// TODO: should be behind a different , tokio specific feature flag.
#[cfg(feature = "sys-thread")]
pub mod tokio;
use std::{pin::Pin, time::Duration};
use ::tokio::runtime::Handle;
use futures::Future;
use wasmer::{Memory, MemoryType, Module, Store, StoreMut};
use crate::os::task::thread::WasiThreadError;
#[derive(Debug)]
pub struct SpawnedMemory {
pub ty: MemoryType,
}
#[derive(Debug)]
pub enum SpawnType {
Create,
CreateWithType(SpawnedMemory),
NewThread(Memory),
}
/// An implementation of task management
#[async_trait::async_trait]
#[allow(unused_variables)]
pub trait VirtualTaskManager: std::fmt::Debug + Send + Sync + 'static {
/// Build a new Webassembly memory.
///
/// May return `None` if the memory can just be auto-constructed.
fn build_memory(
&self,
store: &mut StoreMut,
spawn_type: SpawnType,
) -> Result<Option<Memory>, WasiThreadError>;
/// Invokes whenever a WASM thread goes idle. In some runtimes (like singlethreaded
/// execution environments) they will need to do asynchronous work whenever the main
/// thread goes idle and this is the place to hook for that.
async fn sleep_now(&self, time: Duration);
/// Starts an asynchronous task that will run on a shared worker pool
/// This task must not block the execution or it could cause a deadlock
fn task_shared(
&self,
task: Box<
dyn FnOnce() -> Pin<Box<dyn Future<Output = ()> + Send + 'static>> + Send + 'static,
>,
) -> Result<(), WasiThreadError>;
/// Returns a runtime that can be used for asynchronous tasks
fn runtime(&self) -> &Handle;
/// Enters a runtime context
#[allow(dyn_drop)]
fn runtime_enter<'g>(&'g self) -> Box<dyn std::ops::Drop + 'g>;
/// Starts an asynchronous task will will run on a dedicated thread
/// pulled from the worker pool that has a stateful thread local variable
/// It is ok for this task to block execution and any async futures within its scope
fn task_wasm(
&self,
task: Box<dyn FnOnce(Store, Module, Option<Memory>) + Send + 'static>,
store: Store,
module: Module,
spawn_type: SpawnType,
) -> Result<(), WasiThreadError>;
/// Starts an asynchronous task will will run on a dedicated thread
/// pulled from the worker pool. It is ok for this task to block execution
/// and any async futures within its scope
fn task_dedicated(
&self,
task: Box<dyn FnOnce() + Send + 'static>,
) -> Result<(), WasiThreadError>;
/// Returns the amount of parallelism that is possible on this platform
fn thread_parallelism(&self) -> Result<usize, WasiThreadError>;
}
impl dyn VirtualTaskManager {
/// Execute a future and return the output.
/// This method blocks until the future is complete.
// This needs to be a generic impl on `dyn T` because it is generic, and hence not object-safe.
pub fn block_on<'a, A>(&self, task: impl Future<Output = A> + 'a) -> A {
self.runtime().block_on(task)
}
}
/// Generic utility methods for VirtualTaskManager
pub trait VirtualTaskManagerExt {
fn block_on<'a, A>(&self, task: impl Future<Output = A> + 'a) -> A;
}
impl<'a, T: VirtualTaskManager> VirtualTaskManagerExt for &'a T {
fn block_on<'x, A>(&self, task: impl Future<Output = A> + 'x) -> A {
self.runtime().block_on(task)
}
}
impl<T: VirtualTaskManager + ?Sized> VirtualTaskManagerExt for std::sync::Arc<T> {
fn block_on<'x, A>(&self, task: impl Future<Output = A> + 'x) -> A {
self.runtime().block_on(task)
}
}