use crate::{WasiEnv, WasiError, state::context_switching::ContextSwitchError};
use futures::FutureExt;
use tracing::instrument;
use wasmer::{AsyncFunctionEnvMut, FunctionEnvMut, RuntimeError};
use wasmer_wasix_types::wasi::Errno;
#[instrument(level = "trace", skip(ctx))]
pub async fn context_switch(
mut ctx: AsyncFunctionEnvMut<WasiEnv>,
target_context_id: u64,
) -> Result<Errno, RuntimeError> {
let mut write_lock = ctx.write().await;
let mut sync_env = write_lock.as_function_env_mut();
match WasiEnv::do_pending_operations(&mut sync_env) {
Ok(()) => {}
Err(e) => {
return Err(RuntimeError::user(e.into()));
}
}
let data = write_lock.data_mut();
let environment = match &data.context_switching_environment {
Some(c) => c,
None => {
tracing::warn!(
"The WASIX context-switching API is only available after entering the main function"
);
return Ok(Errno::Notsup);
}
};
let active_context_id = environment.active_context_id();
if active_context_id == target_context_id {
tracing::trace!("Switching context {active_context_id} to itself, which is a no-op");
return Ok(Errno::Success);
}
let wait_for_unblock = match environment.switch_context(target_context_id) {
Ok(wait_for_unblock) => wait_for_unblock,
Err(ContextSwitchError::SwitchTargetMissing) => {
tracing::trace!(
"Context {active_context_id} tried to switch to context {target_context_id} but it does not exist or is not suspended"
);
return Ok(Errno::Inval);
}
};
drop(write_lock);
tracing::trace!("Suspending context {active_context_id} to switch to {target_context_id}");
let result = wait_for_unblock.map(|v| v.map(|_| Errno::Success)).await;
tracing::trace!("Resumed context {active_context_id} after being switched back to");
if let Err(e) = &result {
tracing::trace!("But it has an error {e:?}");
}
result
}
#[instrument(level = "trace", skip(ctx))]
pub fn context_switch_not_supported(
mut ctx: FunctionEnvMut<'_, WasiEnv>,
_target_context_id: u64,
) -> Result<Errno, WasiError> {
WasiEnv::do_pending_operations(&mut ctx)?;
tracing::warn!(
"The WASIX context-switching API is only available in engines supporting async execution"
);
Ok(Errno::Notsup)
}