1use super::{
11 lockfree_ring::{LockFreeRing, RingError},
12 mailbox::IntrusiveMailbox,
13 n3::{MigrationState, N3Transport},
14};
15use crate::{process, silo::SiloId, sync::SpinLock};
16use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
17use core::sync::atomic::{AtomicU32, AtomicU64, Ordering};
18#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
24#[repr(u8)]
25pub enum TransportLevel {
26 TypeSafe = 1,
28 LockFree = 2,
30 Mmu = 3,
32}
33
34#[derive(Debug, Clone, Copy)]
40pub struct TransportCapabilities {
41 pub max_message_size: usize,
43 pub blocking: bool,
45 pub zero_copy: bool,
47 pub vectored: bool,
49 pub directions: u8,
51 pub estimated_cost_cycles: u32,
53}
54
55pub trait IpcTransport: Send + Sync {
57 fn level(&self) -> TransportLevel;
59 fn capabilities(&self) -> TransportCapabilities;
61 fn name(&self) -> &'static str;
63}
64
65pub trait IpcProducer: IpcTransport {
67 fn send(&self, msg: &[u8]) -> Result<(), IpcError>;
69 fn try_send(&self, msg: &[u8]) -> Result<(), IpcError>;
71 fn send_vectored(&self, bufs: &[&[u8]]) -> Result<(), IpcError> {
76 let total: usize = bufs.iter().map(|b| b.len()).sum();
77 if total > self.capabilities().max_message_size {
78 return Err(IpcError::MessageTooLarge);
79 }
80 let mut buf = alloc::vec![0u8; total];
81 let mut offset = 0;
82 for b in bufs {
83 buf[offset..offset + b.len()].copy_from_slice(b);
84 offset += b.len();
85 }
86 self.send(&buf)
87 }
88}
89
90pub trait IpcConsumer: IpcTransport {
92 fn recv(&self, buf: &mut [u8]) -> Result<usize, IpcError>;
94 fn try_recv(&self, buf: &mut [u8]) -> Result<Option<usize>, IpcError>;
96}
97
98pub trait IpcNotification: IpcTransport {
100 fn notify_consumer(&self);
102 fn notify_producer(&self);
104 fn wait_notification(&self) -> Result<(), IpcError>;
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
114pub enum IpcError {
115 WouldBlock,
117 Disconnected,
119 MessageTooLarge,
121 BufferTooSmall,
123 TransportNotFound,
125 PermissionDenied,
127 TransportFailed,
129 InvalidRip,
131 TimedOut,
133}
134
135#[derive(Debug, Clone)]
141pub enum TransportEndpoint {
142 Mailbox(Arc<IntrusiveMailbox>),
144 LockFree(Arc<LockFreeRing>),
146 Mmu(Arc<super::n3::N3Transport>),
148}
149
150impl IpcTransport for TransportEndpoint {
151 fn level(&self) -> TransportLevel {
152 match self {
153 Self::Mailbox(_) => TransportLevel::TypeSafe,
154 Self::LockFree(_) => TransportLevel::LockFree,
155 Self::Mmu(_) => TransportLevel::Mmu,
156 }
157 }
158
159 fn capabilities(&self) -> TransportCapabilities {
160 match self {
161 Self::Mailbox(m) => m.capabilities(),
162 Self::LockFree(r) => r.capabilities(),
163 Self::Mmu(n) => n.capabilities(),
164 }
165 }
166
167 fn name(&self) -> &'static str {
168 match self {
169 Self::Mailbox(_) => "mailbox",
170 Self::LockFree(_) => "lockfree",
171 Self::Mmu(n) => n.name(),
172 }
173 }
174}
175
176impl IpcProducer for TransportEndpoint {
177 fn send(&self, msg: &[u8]) -> Result<(), IpcError> {
178 match self {
179 Self::Mailbox(m) => m.send(msg),
180 Self::LockFree(r) => r.send(msg),
181 Self::Mmu(n) => n.send(msg),
182 }
183 }
184
185 fn try_send(&self, msg: &[u8]) -> Result<(), IpcError> {
186 match self {
187 Self::Mailbox(m) => m.try_send(msg),
188 Self::LockFree(r) => r.try_send(msg),
189 Self::Mmu(n) => n.try_send(msg),
190 }
191 }
192}
193
194impl IpcConsumer for TransportEndpoint {
195 fn recv(&self, buf: &mut [u8]) -> Result<usize, IpcError> {
196 match self {
197 Self::Mailbox(m) => m.recv(buf),
198 Self::LockFree(r) => r.recv(buf),
199 Self::Mmu(n) => n.recv(buf),
200 }
201 }
202
203 fn try_recv(&self, buf: &mut [u8]) -> Result<Option<usize>, IpcError> {
204 match self {
205 Self::Mailbox(m) => m.try_recv(buf),
206 Self::LockFree(r) => r.try_recv(buf),
207 Self::Mmu(n) => n.try_recv(buf),
208 }
209 }
210}
211
212impl IpcTransport for LockFreeRing {
214 fn level(&self) -> TransportLevel {
215 TransportLevel::LockFree
216 }
217
218 fn capabilities(&self) -> TransportCapabilities {
219 TransportCapabilities {
220 max_message_size: 2048,
221 blocking: true,
222 zero_copy: false,
225 vectored: true,
226 directions: 2,
227 estimated_cost_cycles: 400,
228 }
229 }
230
231 fn name(&self) -> &'static str {
232 "lockfree"
233 }
234}
235
236impl IpcProducer for LockFreeRing {
237 fn send(&self, msg: &[u8]) -> Result<(), IpcError> {
238 self.write(msg).map_err(ring_to_ipc_error)?;
239 self.notify_consumer_raw();
240 Ok(())
241 }
242
243 fn try_send(&self, msg: &[u8]) -> Result<(), IpcError> {
244 self.write(msg).map_err(ring_to_ipc_error)?;
245 self.notify_consumer_raw();
246 Ok(())
247 }
248}
249
250impl IpcConsumer for LockFreeRing {
251 fn recv(&self, buf: &mut [u8]) -> Result<usize, IpcError> {
252 self.read(buf).map_err(ring_to_ipc_error)
253 }
254
255 fn try_recv(&self, buf: &mut [u8]) -> Result<Option<usize>, IpcError> {
256 self.try_read(buf).map_err(ring_to_ipc_error)
257 }
258}
259
260fn ring_to_ipc_error(e: RingError) -> IpcError {
261 match e {
262 RingError::Full => IpcError::WouldBlock,
263 RingError::Empty => IpcError::WouldBlock,
264 RingError::MessageTooLarge => IpcError::MessageTooLarge,
265 RingError::BufferTooSmall => IpcError::BufferTooSmall,
266 _ => IpcError::TransportFailed,
267 }
268}
269
270#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
276pub struct TransportId(u64);
277
278impl TransportId {
279 fn new() -> Self {
280 static NEXT: AtomicU64 = AtomicU64::new(1);
281 TransportId(NEXT.fetch_add(1, Ordering::Relaxed))
282 }
283
284 pub fn from_u64(raw: u64) -> Self {
286 TransportId(raw)
287 }
288
289 pub fn as_u64(self) -> u64 {
291 self.0
292 }
293}
294
295#[derive(Debug, Clone)]
297pub struct TransportCreateResult {
298 pub id: TransportId,
299 pub local: TransportEndpoint,
300 pub remote: TransportEndpoint,
301 pub level: TransportLevel,
302 pub(crate) pair: (u32, u32),
304}
305
306#[derive(Debug, Clone)]
312pub struct TransportConfig {
313 pub min_level: TransportLevel,
315 pub ring_capacity: Option<u32>,
317 pub slot_size: Option<usize>,
319}
320
321#[derive(Debug, Clone)]
327struct TransportPolicyEntry {
328 level: TransportLevel,
329 ring_capacity: u32,
330}
331
332const DECISION_MATRIX: [[TransportPolicyEntry; 3]; 3] = [
334 [
336 TransportPolicyEntry {
337 level: TransportLevel::TypeSafe,
338 ring_capacity: 0,
339 },
340 TransportPolicyEntry {
341 level: TransportLevel::TypeSafe,
342 ring_capacity: 0,
343 },
344 TransportPolicyEntry {
345 level: TransportLevel::LockFree,
346 ring_capacity: 256,
347 },
348 ],
349 [
351 TransportPolicyEntry {
352 level: TransportLevel::TypeSafe,
353 ring_capacity: 0,
354 },
355 TransportPolicyEntry {
356 level: TransportLevel::LockFree,
357 ring_capacity: 256,
358 },
359 TransportPolicyEntry {
360 level: TransportLevel::LockFree,
361 ring_capacity: 256,
362 },
363 ],
364 [
366 TransportPolicyEntry {
367 level: TransportLevel::LockFree,
368 ring_capacity: 256,
369 },
370 TransportPolicyEntry {
371 level: TransportLevel::LockFree,
372 ring_capacity: 256,
373 },
374 TransportPolicyEntry {
375 level: TransportLevel::Mmu,
378 ring_capacity: 0,
379 },
380 ],
381];
382
383#[derive(Debug, Clone)]
385pub struct TransportStats {
386 pub created: u64,
388 pub sent: u64,
390 pub received: u64,
392 pub errors: u64,
394 pub level: TransportLevel,
396}
397
398impl TransportStats {
399 const fn new(level: TransportLevel) -> Self {
400 TransportStats {
401 created: 0,
402 sent: 0,
403 received: 0,
404 errors: 0,
405 level,
406 }
407 }
408}
409
410impl TransportEndpoint {
415 pub fn has_data(&self) -> bool {
417 match self {
418 Self::Mailbox(m) => !m.is_empty(),
419 Self::LockFree(r) => r.has_data(),
420 Self::Mmu(n) => {
421 let frame = n.frame();
422 frame.msg_len > 0 && frame.generation.load(Ordering::Acquire) > 0
423 }
424 }
425 }
426
427 pub fn has_space(&self) -> bool {
429 match self {
430 Self::Mailbox(_) => true,
431 Self::LockFree(r) => r.has_space(),
432 Self::Mmu(n) => {
433 let frame = n.frame();
434 frame.state.load(Ordering::Acquire) == MigrationState::Ready as u8
435 }
436 }
437 }
438}
439
440pub struct TransportManager {
450 decision_matrix: [[TransportPolicyEntry; 3]; 3],
452 policy_overrides: SpinLock<BTreeMap<(u32, u32), TransportPolicyEntry>>,
454 active: SpinLock<BTreeMap<TransportId, TransportCreateResult>>,
456 cache: SpinLock<TransportCache>,
458 pub stats: SpinLock<TransportStats>,
460}
461
462impl TransportManager {
463 pub const fn new() -> Self {
465 TransportManager {
466 decision_matrix: DECISION_MATRIX,
467 policy_overrides: SpinLock::new(BTreeMap::new()),
468 active: SpinLock::new(BTreeMap::new()),
469 cache: SpinLock::new(TransportCache::new()),
470 stats: SpinLock::new(TransportStats::new(TransportLevel::LockFree)),
471 }
472 }
473
474 pub fn establish(
481 &self,
482 src: SiloId,
483 dst: SiloId,
484 config: TransportConfig,
485 ) -> Result<TransportCreateResult, IpcError> {
486 let pair = (src.sid, dst.sid);
487
488 {
490 let mut cache = self.cache.lock();
491 if let Some(cached) = cache.get(pair) {
492 if cached.level as u8 >= config.min_level as u8 {
493 return Ok(cached.clone());
494 }
495 }
496 }
497
498 {
500 let overrides = self.policy_overrides.lock();
501 if let Some(entry) = overrides.get(&pair) {
502 return self.create(pair, entry.level, entry.ring_capacity);
503 }
504 }
505
506 let entry = &self.decision_matrix[src.tier as usize][dst.tier as usize];
508 let level = if entry.level < config.min_level {
509 config.min_level
510 } else {
511 entry.level
512 };
513 self.create(
514 pair,
515 level,
516 config.ring_capacity.unwrap_or(entry.ring_capacity),
517 )
518 }
519
520 fn create(
522 &self,
523 _pair: (u32, u32),
524 level: TransportLevel,
525 capacity: u32,
526 ) -> Result<TransportCreateResult, IpcError> {
527 let id = TransportId::new();
528
529 let (local, remote) = match level {
530 TransportLevel::TypeSafe => {
531 let mb = IntrusiveMailbox::new();
532 let arc = Arc::new(mb);
533 (
534 TransportEndpoint::Mailbox(arc.clone()),
535 TransportEndpoint::Mailbox(arc),
536 )
537 }
538 TransportLevel::LockFree => {
539 let ring = LockFreeRing::new(capacity.max(4), 2048)
540 .map_err(|_| IpcError::TransportFailed)?;
541 (
542 TransportEndpoint::LockFree(ring.clone()),
543 TransportEndpoint::LockFree(ring),
544 )
545 }
546 TransportLevel::Mmu => {
547 let sender = process::current_task_clone().ok_or(IpcError::TransportFailed)?;
554 let sender_id = sender.id;
555
556 let all_tasks = process::get_all_tasks().ok_or(IpcError::TransportFailed)?;
558 let receiver_task = all_tasks
559 .iter()
560 .find(|t| {
561 crate::silo::try_silo_id_for_task(t.id).map_or(false, |sid| sid == _pair.1)
562 })
563 .cloned()
564 .ok_or(IpcError::Disconnected)?;
565
566 let transport = N3Transport::new(sender_id, receiver_task.id)?;
567 let arc = Arc::new(transport);
568 (
569 TransportEndpoint::Mmu(arc.clone()),
570 TransportEndpoint::Mmu(arc),
571 )
572 }
573 };
574
575 let result = TransportCreateResult {
576 id,
577 local,
578 remote: remote.clone(),
579 level,
580 pair: _pair,
581 };
582
583 self.stats.lock().created += 1;
585
586 {
587 let mut cache = self.cache.lock();
588 cache.put(_pair, result.clone());
589 }
590 {
591 let mut active = self.active.lock();
592 active.insert(id, result.clone());
593 }
594
595 Ok(result)
596 }
597
598 pub fn get_endpoint(&self, id: TransportId) -> Option<TransportEndpoint> {
600 let active = self.active.lock();
601 active.get(&id).map(|r| r.local.clone())
602 }
603
604 pub fn close(&self, id: TransportId) -> Result<(), IpcError> {
607 let mut active = self.active.lock();
608 let removed = active.remove(&id).ok_or(IpcError::TransportNotFound)?;
609 let mut cache = self.cache.lock();
611 cache.invalidate(removed.pair);
612 Ok(())
613 }
614
615 pub fn set_policy(&self, src: u32, dst: u32, level: TransportLevel, capacity: u32) {
617 let mut overrides = self.policy_overrides.lock();
618 overrides.insert(
619 (src, dst),
620 TransportPolicyEntry {
621 level,
622 ring_capacity: capacity,
623 },
624 );
625 }
626}
627
628const CACHE_SIZE: usize = 128;
633
634struct TransportCache {
635 entries: [((u32, u32), Option<TransportCreateResult>); CACHE_SIZE],
636 next: usize,
637}
638
639impl TransportCache {
640 const fn new() -> Self {
641 const NONE: ((u32, u32), Option<TransportCreateResult>) = ((0, 0), None);
642 TransportCache {
643 entries: [NONE; CACHE_SIZE],
644 next: 0,
645 }
646 }
647
648 fn get(&mut self, key: (u32, u32)) -> Option<&TransportCreateResult> {
649 self.entries
650 .iter()
651 .find_map(|(k, v)| if *k == key { v.as_ref() } else { None })
652 }
653
654 fn put(&mut self, key: (u32, u32), value: TransportCreateResult) {
655 let idx = self.next;
656 self.entries[idx] = (key, Some(value));
657 self.next = (self.next + 1) % CACHE_SIZE;
658 }
659
660 fn invalidate(&mut self, key: (u32, u32)) {
662 if let Some(entry) = self.entries.iter_mut().find(|(k, _)| *k == key) {
663 entry.1 = None;
664 }
665 }
666}
667
668use core::marker::PhantomData;
673
674pub struct Producer;
676
677pub struct Consumer;
679
680pub struct TypedLockFreeRing<Role> {
686 inner: Arc<LockFreeRing>,
687 _role: PhantomData<Role>,
688}
689
690impl TypedLockFreeRing<Producer> {
691 pub fn write(&self, data: &[u8]) -> Result<(), RingError> {
693 self.inner.write(data)
694 }
695}
696
697impl<T> TypedLockFreeRing<T> {
698 pub fn read(&self, buf: &mut [u8]) -> Result<usize, RingError> {
700 self.inner.read(buf)
701 }
702}
703
704pub fn create_spsc_pair(
706 cap: u32,
707 slot_size: usize,
708) -> Result<(TypedLockFreeRing<Producer>, TypedLockFreeRing<Consumer>), RingError> {
709 let ring = LockFreeRing::new(cap, slot_size)?;
710 Ok((
711 TypedLockFreeRing {
712 inner: ring.clone(),
713 _role: PhantomData,
714 },
715 TypedLockFreeRing {
716 inner: ring,
717 _role: PhantomData,
718 },
719 ))
720}