wasmer_wasix/syscalls/wasi/
proc_exit.rs

1use super::*;
2use crate::syscalls::*;
3
4/// ### `proc_exit()`
5/// Terminate the process normally. An exit code of 0 indicates successful
6/// termination of the program. The meanings of other values is dependent on
7/// the environment.
8/// Inputs:
9/// - `ExitCode`
10///   Exit code to return to the operating system
11#[instrument(level = "trace", skip_all)]
12pub fn proc_exit<M: MemorySize>(
13    mut ctx: FunctionEnvMut<'_, WasiEnv>,
14    code: ExitCode,
15) -> Result<(), WasiError> {
16    WasiEnv::do_pending_operations(&mut ctx)?;
17
18    debug!(%code);
19
20    // If we are in a vfork we need to return to the point we left off
21    if let Some(mut vfork) = ctx.data_mut().vfork.take() {
22        tracing::debug!(
23            parent_pid = %vfork.env.process.pid(),
24            child_pid = %ctx.data().process.pid(),
25            "proc_exit from vfork, returning control to parent process"
26        );
27
28        // Prepare the child env for teardown by closing its FDs
29        InlineWaker::block_on(
30            unsafe { ctx.data().get_memory_and_wasi_state(&ctx, 0) }
31                .1
32                .fs
33                .close_all(),
34        );
35
36        // Restore the WasiEnv to the point when we vforked
37        vfork.env.swap_inner(ctx.data_mut());
38        std::mem::swap(vfork.env.as_mut(), ctx.data_mut());
39        let mut child_env = *vfork.env;
40        child_env.owned_handles.push(vfork.handle);
41
42        // Terminate the child process
43        child_env.process.terminate(code);
44
45        // Jump back to the vfork point and current on execution
46        let child_pid = child_env.process.pid();
47        let rewind_stack = vfork.rewind_stack.freeze();
48        let store_data = vfork.store_data;
49        unwind::<M, _>(ctx, move |mut ctx, _, _| {
50            // Now rewind the previous stack and carry on from where we did the vfork
51            match rewind::<M, _>(
52                ctx,
53                None,
54                rewind_stack,
55                store_data,
56                ForkResult {
57                    pid: child_pid.raw() as Pid,
58                    ret: Errno::Success,
59                },
60            ) {
61                Errno::Success => OnCalledAction::InvokeAgain,
62                err => {
63                    warn!("fork failed - could not rewind the stack - errno={}", err);
64                    OnCalledAction::Trap(Box::new(WasiError::Exit(err.into())))
65                }
66            }
67        })?;
68        return Ok(());
69    }
70
71    // Otherwise just exit
72    Err(WasiError::Exit(code))
73}