lunatic_registry_api/
lib.rs

1use std::future::Future;
2
3use anyhow::Result;
4use lunatic_common_api::{get_memory, IntoTrap};
5use lunatic_process::state::ProcessState;
6use lunatic_process_api::ProcessCtx;
7use wasmtime::{Caller, Linker};
8
9// Register the registry APIs to the linker
10pub fn register<T: ProcessState + ProcessCtx<T> + Send + Sync + 'static>(
11    linker: &mut Linker<T>,
12) -> Result<()> {
13    linker.func_wrap4_async("lunatic::registry", "put", put)?;
14    linker.func_wrap4_async("lunatic::registry", "get", get)?;
15    linker.func_wrap2_async("lunatic::registry", "remove", remove)?;
16
17    #[cfg(feature = "metrics")]
18    metrics::describe_counter!(
19        "lunatic.registry.write",
20        metrics::Unit::Count,
21        "number of new entries written to the registry"
22    );
23    #[cfg(feature = "metrics")]
24    metrics::describe_counter!(
25        "lunatic.timers.read",
26        metrics::Unit::Count,
27        "number of entries read from the registry"
28    );
29    #[cfg(feature = "metrics")]
30    metrics::describe_counter!(
31        "lunatic.timers.deletion",
32        metrics::Unit::Count,
33        "number of entries deleted from the registry"
34    );
35    #[cfg(feature = "metrics")]
36    metrics::describe_gauge!(
37        "lunatic.timers.registered",
38        metrics::Unit::Count,
39        "number of processes currently registered"
40    );
41
42    Ok(())
43}
44
45// Registers process with ID under `name`.
46//
47// Traps:
48// * If the process ID doesn't exist.
49// * If any memory outside the guest heap space is referenced.
50fn put<T: ProcessState + ProcessCtx<T> + Send + Sync>(
51    mut caller: Caller<T>,
52    name_str_ptr: u32,
53    name_str_len: u32,
54    node_id: u64,
55    process_id: u64,
56) -> Box<dyn Future<Output = Result<()>> + Send + '_> {
57    Box::new(async move {
58        let memory = get_memory(&mut caller)?;
59        let (memory_slice, state) = memory.data_and_store_mut(&mut caller);
60        let name = memory_slice
61            .get(name_str_ptr as usize..(name_str_ptr + name_str_len) as usize)
62            .or_trap("lunatic::registry::put")?;
63        let name = std::str::from_utf8(name).or_trap("lunatic::registry::put")?;
64
65        state
66            .registry()
67            .write()
68            .await
69            .insert(name.to_owned(), (node_id, process_id));
70
71        #[cfg(feature = "metrics")]
72        metrics::increment_counter!("lunatic.registry.write");
73
74        #[cfg(feature = "metrics")]
75        metrics::increment_gauge!("lunatic.registry.registered", 1.0);
76
77        Ok(())
78    })
79}
80
81// Looks up process under `name` and returns 0 if it was found or 1 if not found.
82//
83// Traps:
84// * If any memory outside the guest heap space is referenced.
85fn get<T: ProcessState + ProcessCtx<T> + Send + Sync>(
86    mut caller: Caller<T>,
87    name_str_ptr: u32,
88    name_str_len: u32,
89    node_id_ptr: u32,
90    process_id_ptr: u32,
91) -> Box<dyn Future<Output = Result<u32>> + Send + '_> {
92    Box::new(async move {
93        let memory = get_memory(&mut caller)?;
94        let (memory_slice, state) = memory.data_and_store_mut(&mut caller);
95        let name = memory_slice
96            .get(name_str_ptr as usize..(name_str_ptr + name_str_len) as usize)
97            .or_trap("lunatic::registry::get")?;
98        let name = std::str::from_utf8(name).or_trap("lunatic::registry::get")?;
99
100        #[cfg(feature = "metrics")]
101        metrics::increment_counter!("lunatic.registry.read");
102
103        let (node_id, process_id) = if let Some(process) = state.registry().read().await.get(name) {
104            *process
105        } else {
106            return Ok(1);
107        };
108
109        memory
110            .write(&mut caller, node_id_ptr as usize, &node_id.to_le_bytes())
111            .or_trap("lunatic::registry::get")?;
112
113        memory
114            .write(
115                &mut caller,
116                process_id_ptr as usize,
117                &process_id.to_le_bytes(),
118            )
119            .or_trap("lunatic::registry::get")?;
120        Ok(0)
121    })
122}
123
124// Removes process under `name` if it exists.
125//
126// Traps:
127// * If any memory outside the guest heap space is referenced.
128fn remove<T: ProcessState + ProcessCtx<T> + Send + Sync>(
129    mut caller: Caller<T>,
130    name_str_ptr: u32,
131    name_str_len: u32,
132) -> Box<dyn Future<Output = Result<()>> + Send + '_> {
133    Box::new(async move {
134        let memory = get_memory(&mut caller)?;
135        let (memory_slice, state) = memory.data_and_store_mut(&mut caller);
136        let name = memory_slice
137            .get(name_str_ptr as usize..(name_str_ptr + name_str_len) as usize)
138            .or_trap("lunatic::registry::get")?;
139        let name = std::str::from_utf8(name).or_trap("lunatic::registry::get")?;
140
141        state.registry().write().await.remove(name);
142
143        #[cfg(feature = "metrics")]
144        metrics::increment_counter!("lunatic.registry.deletion");
145
146        #[cfg(feature = "metrics")]
147        metrics::decrement_gauge!("lunatic.registry.registered", 1.0);
148
149        Ok(())
150    })
151}