wasmer_wasix/syscalls/wasix/
context_switch.rs1use crate::{WasiEnv, WasiError, state::context_switching::ContextSwitchError};
2use futures::FutureExt;
3use tracing::instrument;
4use wasmer::{AsyncFunctionEnvMut, FunctionEnvMut, RuntimeError};
5use wasmer_wasix_types::wasi::Errno;
6
7#[instrument(level = "trace", skip(ctx))]
17pub async fn context_switch(
18 mut ctx: AsyncFunctionEnvMut<WasiEnv>,
19 target_context_id: u64,
20) -> Result<Errno, RuntimeError> {
21 let mut write_lock = ctx.write().await;
22
23 let mut sync_env = write_lock.as_function_env_mut();
24 match WasiEnv::do_pending_operations(&mut sync_env) {
25 Ok(()) => {}
26 Err(e) => {
27 return Err(RuntimeError::user(e.into()));
28 }
29 }
30
31 let data = write_lock.data_mut();
32
33 let environment = match &data.context_switching_environment {
35 Some(c) => c,
36 None => {
37 tracing::warn!(
38 "The WASIX context-switching API is only available after entering the main function"
39 );
40 return Ok(Errno::Notsup);
41 }
42 };
43
44 let active_context_id = environment.active_context_id();
46
47 if active_context_id == target_context_id {
49 tracing::trace!("Switching context {active_context_id} to itself, which is a no-op");
50 return Ok(Errno::Success);
51 }
52
53 let wait_for_unblock = match environment.switch_context(target_context_id) {
57 Ok(wait_for_unblock) => wait_for_unblock,
58 Err(ContextSwitchError::SwitchTargetMissing) => {
59 tracing::trace!(
60 "Context {active_context_id} tried to switch to context {target_context_id} but it does not exist or is not suspended"
61 );
62 return Ok(Errno::Inval);
63 }
64 };
65
66 drop(write_lock);
68 tracing::trace!("Suspending context {active_context_id} to switch to {target_context_id}");
69
70 let result = wait_for_unblock.map(|v| v.map(|_| Errno::Success)).await;
72 tracing::trace!("Resumed context {active_context_id} after being switched back to");
73 if let Err(e) = &result {
74 tracing::trace!("But it has an error {e:?}");
75 }
76 result
77}
78
79#[instrument(level = "trace", skip(ctx))]
83pub fn context_switch_not_supported(
84 mut ctx: FunctionEnvMut<'_, WasiEnv>,
85 _target_context_id: u64,
86) -> Result<Errno, WasiError> {
87 WasiEnv::do_pending_operations(&mut ctx)?;
88
89 tracing::warn!(
90 "The WASIX context-switching API is only available in engines supporting async execution"
91 );
92 Ok(Errno::Notsup)
94}