wasmer_wasi/
runtime.rs

1use std::fmt;
2use std::ops::Deref;
3use std::sync::atomic::{AtomicU32, Ordering};
4use thiserror::Error;
5use wasmer_vbus::{UnsupportedVirtualBus, VirtualBus};
6use wasmer_vnet::VirtualNetworking;
7use wasmer_wasi_types::wasi::Errno;
8
9use super::WasiError;
10use super::WasiThreadId;
11
12#[derive(Error, Debug)]
13pub enum WasiThreadError {
14    #[error("Multithreading is not supported")]
15    Unsupported,
16    #[error("The method named is not an exported function")]
17    MethodNotFound,
18}
19
20impl From<WasiThreadError> for Errno {
21    fn from(a: WasiThreadError) -> Errno {
22        match a {
23            WasiThreadError::Unsupported => Errno::Notsup,
24            WasiThreadError::MethodNotFound => Errno::Inval,
25        }
26    }
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
30pub struct WasiTtyState {
31    pub cols: u32,
32    pub rows: u32,
33    pub width: u32,
34    pub height: u32,
35    pub stdin_tty: bool,
36    pub stdout_tty: bool,
37    pub stderr_tty: bool,
38    pub echo: bool,
39    pub line_buffered: bool,
40}
41
42/// Represents an implementation of the WASI runtime - by default everything is
43/// unimplemented.
44pub trait WasiRuntimeImplementation: fmt::Debug + Sync {
45    /// For WASI runtimes that support it they can implement a message BUS implementation
46    /// which allows runtimes to pass serialized messages between each other similar to
47    /// RPC's. BUS implementation can be implemented that communicate across runtimes
48    /// thus creating a distributed computing architecture.
49    fn bus(&self) -> &(dyn VirtualBus);
50
51    /// Provides access to all the networking related functions such as sockets.
52    /// By default networking is not implemented.
53    fn networking(&self) -> &(dyn VirtualNetworking);
54
55    /// Generates a new thread ID
56    fn thread_generate_id(&self) -> WasiThreadId;
57
58    /// Gets the TTY state
59    fn tty_get(&self) -> WasiTtyState {
60        WasiTtyState {
61            rows: 25,
62            cols: 80,
63            width: 800,
64            height: 600,
65            stdin_tty: false,
66            stdout_tty: false,
67            stderr_tty: false,
68            echo: true,
69            line_buffered: true,
70        }
71    }
72
73    /// Sets the TTY state
74    fn tty_set(&self, _tty_state: WasiTtyState) {}
75
76    /// Spawns a new thread by invoking the
77    fn thread_spawn(
78        &self,
79        _callback: Box<dyn FnOnce() + Send + 'static>,
80    ) -> Result<(), WasiThreadError> {
81        Err(WasiThreadError::Unsupported)
82    }
83
84    /// Returns the amount of parallelism that is possible on this platform
85    fn thread_parallelism(&self) -> Result<usize, WasiThreadError> {
86        Err(WasiThreadError::Unsupported)
87    }
88
89    /// Invokes whenever a WASM thread goes idle. In some runtimes (like singlethreaded
90    /// execution environments) they will need to do asynchronous work whenever the main
91    /// thread goes idle and this is the place to hook for that.
92    fn yield_now(&self, _id: WasiThreadId) -> Result<(), WasiError> {
93        std::thread::yield_now();
94        Ok(())
95    }
96
97    /// Gets the current process ID
98    fn getpid(&self) -> Option<u32> {
99        None
100    }
101}
102
103#[derive(Debug)]
104pub struct PluggableRuntimeImplementation {
105    pub bus: Box<dyn VirtualBus + Sync>,
106    pub networking: Box<dyn VirtualNetworking + Sync>,
107    pub thread_id_seed: AtomicU32,
108}
109
110impl PluggableRuntimeImplementation {
111    pub fn set_bus_implementation<I>(&mut self, bus: I)
112    where
113        I: VirtualBus + Sync,
114    {
115        self.bus = Box::new(bus)
116    }
117
118    pub fn set_networking_implementation<I>(&mut self, net: I)
119    where
120        I: VirtualNetworking + Sync,
121    {
122        self.networking = Box::new(net)
123    }
124}
125
126impl Default for PluggableRuntimeImplementation {
127    fn default() -> Self {
128        Self {
129            #[cfg(not(feature = "host-vnet"))]
130            networking: Box::new(wasmer_vnet::UnsupportedVirtualNetworking::default()),
131            #[cfg(feature = "host-vnet")]
132            networking: Box::new(wasmer_wasi_local_networking::LocalNetworking::default()),
133            bus: Box::new(UnsupportedVirtualBus::default()),
134            thread_id_seed: Default::default(),
135        }
136    }
137}
138
139impl WasiRuntimeImplementation for PluggableRuntimeImplementation {
140    fn bus(&self) -> &(dyn VirtualBus) {
141        self.bus.deref()
142    }
143
144    fn networking(&self) -> &(dyn VirtualNetworking) {
145        self.networking.deref()
146    }
147
148    fn thread_generate_id(&self) -> WasiThreadId {
149        self.thread_id_seed.fetch_add(1, Ordering::Relaxed).into()
150    }
151}