wasmer_wasix/syscalls/legacy/
snapshot0.rs

1#![allow(clippy::result_large_err)]
2
3use tracing::{field, instrument, trace_span};
4use wasmer::{AsStoreMut, AsStoreRef, FunctionEnvMut, Memory, WasmPtr};
5use wasmer_wasix_types::wasi::{
6    Errno, Event, EventFdReadwrite, Eventrwflags, Eventtype, ExitCode, Fd, Filesize, Filestat,
7    Filetype, Snapshot0Event, Snapshot0Filestat, Snapshot0Subscription, Snapshot0Whence,
8    Subscription, Whence,
9};
10
11use crate::{
12    Memory32, MemorySize, WasiEnv, WasiError, mem_error_to_wasi,
13    os::task::thread::WasiThread,
14    state::{PollEventBuilder, PollEventSet},
15    syscalls::types,
16    syscalls::{self, handle_rewind, to_offset},
17};
18
19/// Wrapper around `syscalls::fd_filestat_get` for old Snapshot0
20#[instrument(level = "trace", skip_all, ret)]
21pub fn fd_filestat_get(
22    mut ctx: FunctionEnvMut<WasiEnv>,
23    fd: Fd,
24    buf: WasmPtr<Snapshot0Filestat, Memory32>,
25) -> Errno {
26    syscalls::fd_filestat_get_old::<Memory32>(ctx.as_mut(), fd, buf)
27}
28
29/// Wrapper around `syscalls::path_filestat_get` for old Snapshot0
30#[instrument(level = "trace", skip_all, ret)]
31pub fn path_filestat_get(
32    mut ctx: FunctionEnvMut<WasiEnv>,
33    fd: Fd,
34    flags: types::LookupFlags,
35    path: WasmPtr<u8, Memory32>,
36    path_len: u32,
37    buf: WasmPtr<Snapshot0Filestat, Memory32>,
38) -> Errno {
39    syscalls::path_filestat_get_old::<Memory32>(ctx.as_mut(), fd, flags, path, path_len, buf)
40}
41
42/// Wrapper around `syscalls::fd_seek` with extra logic to remap the values
43/// of `Whence`
44#[instrument(level = "trace", skip_all, ret)]
45pub fn fd_seek(
46    ctx: FunctionEnvMut<WasiEnv>,
47    fd: Fd,
48    offset: types::FileDelta,
49    whence: Snapshot0Whence,
50    newoffset: WasmPtr<Filesize, Memory32>,
51) -> Result<Errno, WasiError> {
52    let new_whence = match whence {
53        Snapshot0Whence::Cur => Whence::Cur,
54        Snapshot0Whence::End => Whence::End,
55        Snapshot0Whence::Set => Whence::Set,
56        _ => return Ok(Errno::Inval),
57    };
58    syscalls::fd_seek::<Memory32>(ctx, fd, offset, new_whence, newoffset)
59}
60
61/// Wrapper around `syscalls::poll_oneoff` with extra logic to add the removed
62/// userdata field back
63#[instrument(level = "trace", skip_all, fields(timeout_ms = field::Empty, fd_guards = field::Empty, seen = field::Empty), ret)]
64pub fn poll_oneoff<M: MemorySize>(
65    mut ctx: FunctionEnvMut<WasiEnv>,
66    in_: WasmPtr<Snapshot0Subscription, Memory32>,
67    out_: WasmPtr<Snapshot0Event, Memory32>,
68    nsubscriptions: u32,
69    nevents: WasmPtr<u32, Memory32>,
70) -> Result<Errno, WasiError> {
71    WasiEnv::do_pending_operations(&mut ctx)?;
72
73    let env = ctx.data();
74    let memory = unsafe { env.memory_view(&ctx) };
75
76    wasi_try_ok!(syscalls::validate_poll_subscriptions_count(
77        env,
78        nsubscriptions as usize,
79    ));
80    let nsubscriptions_offset = wasi_try_ok!(to_offset::<Memory32>(nsubscriptions as usize));
81
82    let in_origs = wasi_try_mem_ok!(in_.slice(&memory, nsubscriptions_offset));
83    let in_origs = wasi_try_mem_ok!(in_origs.read_to_vec());
84    let mut subscriptions = Vec::new();
85    wasi_try_ok!(
86        subscriptions
87            .try_reserve_exact(in_origs.len())
88            .map_err(|_| Errno::Nomem)
89    );
90    for in_orig in in_origs {
91        subscriptions.push((
92            None,
93            PollEventSet::default(),
94            Into::<Subscription>::into(in_orig),
95        ));
96    }
97
98    // Function to invoke once the poll is finished
99    let process_events = |ctx: &FunctionEnvMut<'_, WasiEnv>, triggered_events: Vec<Event>| {
100        let env = ctx.data();
101        let memory = unsafe { env.memory_view(&ctx) };
102
103        // Process all the events that were triggered
104        let mut events_seen: u32 = 0;
105        let event_array = wasi_try_mem!(out_.slice(&memory, nsubscriptions_offset));
106        for event in triggered_events {
107            let event = Snapshot0Event {
108                userdata: event.userdata,
109                error: event.error,
110                type_: Eventtype::FdRead,
111                fd_readwrite: match event.type_ {
112                    Eventtype::FdRead => unsafe { event.u.fd_readwrite },
113                    Eventtype::FdWrite => unsafe { event.u.fd_readwrite },
114                    Eventtype::Clock => EventFdReadwrite {
115                        nbytes: 0,
116                        flags: Eventrwflags::empty(),
117                    },
118                    _ => return Errno::Inval,
119                },
120            };
121            wasi_try_mem!(event_array.index(events_seen as u64).write(event));
122            events_seen += 1;
123        }
124        let out_ptr = nevents.deref(&memory);
125        wasi_try_mem!(out_ptr.write(events_seen));
126        Errno::Success
127    };
128
129    // We clear the number of events
130    wasi_try_mem_ok!(nevents.write(&memory, 0));
131
132    // Poll and receive all the events that triggered
133    syscalls::poll_oneoff_internal::<M, _>(ctx, subscriptions, process_events)
134}