veridian_kernel/ipc/
sync.rs1#![allow(dead_code)]
8
9#[cfg(feature = "alloc")]
10extern crate alloc;
11
12use core::sync::atomic::{AtomicU64, Ordering};
13
14use super::{
15 error::{IpcError, Result},
16 fast_path::{fast_receive, fast_send},
17 message::Message,
18};
19use crate::{
20 arch::entropy::read_timestamp,
21 process::{ProcessId, ProcessState},
22 sched::{current_process, find_process},
23};
24
25pub struct SyncIpcStats {
27 pub send_count: AtomicU64,
28 pub receive_count: AtomicU64,
29 pub fast_path_count: AtomicU64,
30 pub slow_path_count: AtomicU64,
31 pub avg_latency_cycles: AtomicU64,
32}
33
34static SYNC_STATS: SyncIpcStats = SyncIpcStats {
35 send_count: AtomicU64::new(0),
36 receive_count: AtomicU64::new(0),
37 fast_path_count: AtomicU64::new(0),
38 slow_path_count: AtomicU64::new(0),
39 avg_latency_cycles: AtomicU64::new(0),
40};
41
42#[cfg(test)]
44pub fn send_message(msg: Message, target_endpoint: u64) -> Result<()> {
45 sync_send(msg, target_endpoint)
46}
47
48pub fn sync_send(msg: Message, target_endpoint: u64) -> Result<()> {
52 let start = read_timestamp();
53 SYNC_STATS.send_count.fetch_add(1, Ordering::Relaxed);
54
55 match msg {
56 Message::Small(small_msg) => {
57 match fast_send(&small_msg, target_endpoint) {
59 Ok(()) => {
60 SYNC_STATS.fast_path_count.fetch_add(1, Ordering::Relaxed);
61 update_latency_stats(start);
62 Ok(())
63 }
64 Err(IpcError::WouldBlock) => {
65 SYNC_STATS.slow_path_count.fetch_add(1, Ordering::Relaxed);
67 sync_send_slow_path(Message::Small(small_msg), target_endpoint)?;
68 update_latency_stats(start);
69 Ok(())
70 }
71 Err(e) => Err(e),
72 }
73 }
74 Message::Large(large_msg) => {
75 SYNC_STATS.slow_path_count.fetch_add(1, Ordering::Relaxed);
77 sync_send_slow_path(Message::Large(large_msg), target_endpoint)?;
78 update_latency_stats(start);
79 Ok(())
80 }
81 }
82}
83
84pub fn sync_receive(endpoint: u64) -> Result<Message> {
88 let start = read_timestamp();
89 SYNC_STATS.receive_count.fetch_add(1, Ordering::Relaxed);
90
91 match fast_receive(endpoint, None) {
93 Ok(small_msg) => {
94 SYNC_STATS.fast_path_count.fetch_add(1, Ordering::Relaxed);
95 update_latency_stats(start);
96 Ok(Message::Small(small_msg))
97 }
98 Err(IpcError::WouldBlock) => {
99 SYNC_STATS.slow_path_count.fetch_add(1, Ordering::Relaxed);
101 let msg = sync_receive_slow_path(endpoint)?;
102 update_latency_stats(start);
103 Ok(msg)
104 }
105 Err(e) => Err(e),
106 }
107}
108
109pub fn sync_call(request: Message, target: u64) -> Result<Message> {
111 sync_send(request, target)?;
113
114 let current = current_process();
116 current.state = ProcessState::Blocked;
117
118 sync_receive(current.pid.0)
120}
121
122pub fn sync_reply(reply: Message, caller: u64) -> Result<()> {
124 let caller_process = find_process(ProcessId(caller)).ok_or(IpcError::ProcessNotFound)?;
126
127 if caller_process.state != ProcessState::Blocked {
129 return Err(IpcError::InvalidMessage);
130 }
131
132 sync_send(reply, caller)?;
134
135 crate::sched::ipc_blocking::wake_up_process(ProcessId(caller));
137 Ok(())
138}
139
140fn sync_send_slow_path(msg: Message, target_endpoint: u64) -> Result<()> {
142 validate_send_capability(&msg, target_endpoint)?;
144
145 #[cfg(feature = "alloc")]
147 {
148 const MAX_RETRIES: u32 = 3;
149 for _attempt in 0..MAX_RETRIES {
150 match crate::ipc::message_passing::send_to_endpoint(msg, target_endpoint) {
151 Ok(()) => {
152 crate::sched::ipc_blocking::wake_up_endpoint_waiters(target_endpoint);
154 return Ok(());
155 }
156 Err(IpcError::ChannelFull) => {
157 crate::sched::ipc_blocking::block_on_ipc(target_endpoint);
159 }
160 Err(e) => return Err(e),
161 }
162 }
163 Err(IpcError::ChannelFull)
164 }
165 #[cfg(not(feature = "alloc"))]
166 {
167 Err(IpcError::OutOfMemory)
168 }
169}
170
171fn sync_receive_slow_path(endpoint: u64) -> Result<Message> {
173 #[cfg(feature = "alloc")]
175 {
176 crate::ipc::message_passing::receive_from_endpoint(endpoint, true)
177 }
178 #[cfg(not(feature = "alloc"))]
179 {
180 Err(IpcError::OutOfMemory)
181 }
182}
183
184fn validate_send_capability(msg: &Message, endpoint_id: u64) -> Result<()> {
186 let cap_id = msg.capability();
187
188 let current_process = crate::process::current_process().ok_or(IpcError::ProcessNotFound)?;
190 let cap_space = current_process.capability_space.lock();
191
192 let cap_token = crate::cap::CapabilityToken::from_u64(cap_id);
194
195 crate::cap::ipc_integration::check_send_permission(cap_token, &cap_space).map_err(
198 |e| match e {
199 IpcError::InvalidCapability => IpcError::InvalidCapability,
200 IpcError::PermissionDenied => IpcError::PermissionDenied,
201 _ => IpcError::InvalidCapability,
202 },
203 )?;
204
205 #[cfg(feature = "alloc")]
211 {
212 if let Some((crate::cap::object::ObjectRef::Endpoint { endpoint }, _rights)) =
213 cap_space.lookup_entry(cap_token)
214 {
215 if endpoint.id() != endpoint_id {
216 return Err(IpcError::InvalidCapability);
217 }
218 }
219 }
220 #[cfg(not(feature = "alloc"))]
221 {
222 let _ = endpoint_id;
223 }
224
225 Ok(())
226}
227
228fn update_latency_stats(start_cycles: u64) {
230 let elapsed = read_timestamp() - start_cycles;
231 let count = SYNC_STATS.send_count.load(Ordering::Relaxed)
232 + SYNC_STATS.receive_count.load(Ordering::Relaxed);
233 let current_avg = SYNC_STATS.avg_latency_cycles.load(Ordering::Relaxed);
234
235 let new_avg = if count > 1 {
237 (current_avg * (count - 1) + elapsed) / count
238 } else {
239 elapsed
240 };
241
242 SYNC_STATS
243 .avg_latency_cycles
244 .store(new_avg, Ordering::Relaxed);
245
246 let is_fast_path = SYNC_STATS.fast_path_count.load(Ordering::Relaxed)
248 > SYNC_STATS.slow_path_count.load(Ordering::Relaxed);
249 crate::ipc::perf::IPC_PERF_STATS.record_operation(elapsed, is_fast_path);
250}
251
252pub fn get_sync_stats() -> SyncStatsSummary {
254 SyncStatsSummary {
255 send_count: SYNC_STATS.send_count.load(Ordering::Relaxed),
256 receive_count: SYNC_STATS.receive_count.load(Ordering::Relaxed),
257 fast_path_count: SYNC_STATS.fast_path_count.load(Ordering::Relaxed),
258 slow_path_count: SYNC_STATS.slow_path_count.load(Ordering::Relaxed),
259 avg_latency_cycles: SYNC_STATS.avg_latency_cycles.load(Ordering::Relaxed),
260 fast_path_percentage: {
261 let fast = SYNC_STATS.fast_path_count.load(Ordering::Relaxed);
262 let total = fast + SYNC_STATS.slow_path_count.load(Ordering::Relaxed);
263 if total > 0 {
264 (fast * 100) / total
265 } else {
266 0
267 }
268 },
269 }
270}
271
272pub struct SyncStatsSummary {
273 pub send_count: u64,
274 pub receive_count: u64,
275 pub fast_path_count: u64,
276 pub slow_path_count: u64,
277 pub avg_latency_cycles: u64,
278 pub fast_path_percentage: u64,
279}
280
281#[cfg(all(test, not(target_os = "none")))]
282mod tests {
283 use super::*;
284
285 #[test]
286 fn test_sync_stats() {
287 let stats = get_sync_stats();
288 assert_eq!(stats.send_count, 0);
289 assert_eq!(stats.receive_count, 0);
290 assert_eq!(stats.fast_path_percentage, 0);
291 }
292}