wasmer_wasix/syscalls/wasix/
futex_wake.rs

1use super::*;
2use crate::syscalls::*;
3
4/// Wake up one thread that's blocked on futex_wait on this futex.
5/// Returns true if this actually woke up such a thread,
6/// or false if no thread was waiting on this futex.
7///
8/// ## Parameters
9///
10/// * `futex` - Memory location that holds a futex that others may be waiting on
11#[instrument(level = "trace", skip_all, fields(futex_idx = field::Empty, woken = field::Empty), ret)]
12pub fn futex_wake<M: MemorySize>(
13    mut ctx: FunctionEnvMut<'_, WasiEnv>,
14    futex_ptr: WasmPtr<u32, M>,
15    ret_woken: WasmPtr<Bool, M>,
16) -> Result<Errno, WasiError> {
17    WasiEnv::do_pending_operations(&mut ctx)?;
18
19    let env = ctx.data();
20    let memory = unsafe { env.memory_view(&ctx) };
21    let state = env.state.deref();
22
23    let pointer: u64 = futex_ptr.offset().into();
24    Span::current().record("futex_idx", pointer);
25
26    let mut woken = false;
27    let woken = {
28        let mut guard = state.futexs.lock().unwrap();
29        if let Some(futex) = guard.futexes.get_mut(&pointer) {
30            let first = futex.wakers.keys().copied().next();
31            if let Some(id) = first {
32                if let Some(Some(w)) = futex.wakers.remove(&id) {
33                    w.wake();
34                }
35            }
36            if futex.wakers.is_empty() {
37                guard.futexes.remove(&pointer);
38            }
39            tracing::trace!("wake(hit) on {pointer}");
40            true
41        } else {
42            tracing::trace!("wake(miss) on {pointer}");
43            true
44        }
45    };
46    Span::current().record("woken", woken);
47
48    let woken = match woken {
49        false => Bool::False,
50        true => Bool::True,
51    };
52    wasi_try_mem_ok!(ret_woken.write(&memory, woken));
53
54    Ok(Errno::Success)
55}