strat9_kernel/ipc/
quota.rs1use core::sync::atomic::{AtomicU32, AtomicU64, Ordering};
7
8pub const MAX_CHANNELS_PER_PROCESS: u32 = 256;
10
11pub const MAX_QUEUE_SLOTS_PER_PROCESS: u64 = 65_536;
14
15pub const MAX_BUFFERED_BYTES_PER_PROCESS: u64 = MAX_QUEUE_SLOTS_PER_PROCESS * 256;
20
21#[derive(Debug)]
29pub struct IpcQuota {
30 pub channels: AtomicU32,
32 pub queue_slots: AtomicU64,
34 pub buffered_bytes: AtomicU64,
37}
38
39impl IpcQuota {
40 pub const fn new() -> Self {
42 IpcQuota {
43 channels: AtomicU32::new(0),
44 queue_slots: AtomicU64::new(0),
45 buffered_bytes: AtomicU64::new(0),
46 }
47 }
48
49 pub fn try_reserve(&self, capacity: usize) -> Result<(), QuotaExceeded> {
54 let new_channels = self
55 .channels
56 .load(Ordering::Relaxed)
57 .checked_add(1)
58 .ok_or(QuotaExceeded)?;
59 if new_channels > MAX_CHANNELS_PER_PROCESS {
60 return Err(QuotaExceeded);
61 }
62
63 let slots = capacity as u64;
64 let new_slots = self
65 .queue_slots
66 .load(Ordering::Relaxed)
67 .checked_add(slots)
68 .ok_or(QuotaExceeded)?;
69 if new_slots > MAX_QUEUE_SLOTS_PER_PROCESS {
70 return Err(QuotaExceeded);
71 }
72
73 let bytes = slots * core::mem::size_of::<crate::ipc::message::IpcMessage>() as u64;
74 let new_bytes = self
75 .buffered_bytes
76 .load(Ordering::Relaxed)
77 .checked_add(bytes)
78 .ok_or(QuotaExceeded)?;
79 if new_bytes > MAX_BUFFERED_BYTES_PER_PROCESS {
80 return Err(QuotaExceeded);
81 }
82
83 self.channels.store(new_channels, Ordering::Release);
85 self.queue_slots.store(new_slots, Ordering::Release);
86 self.buffered_bytes.store(new_bytes, Ordering::Release);
87 Ok(())
88 }
89
90 pub fn release(&self, capacity: usize) {
96 let _ = self.channels.fetch_sub(1, Ordering::AcqRel);
97
98 let slots = capacity as u64;
99 let _ = self.queue_slots.fetch_sub(slots, Ordering::AcqRel);
100
101 let bytes = slots * core::mem::size_of::<crate::ipc::message::IpcMessage>() as u64;
102 let _ = self.buffered_bytes.fetch_sub(bytes, Ordering::AcqRel);
103 }
104
105 pub fn snapshot(&self) -> QuotaSnapshot {
107 QuotaSnapshot {
108 channels: self.channels.load(Ordering::Relaxed),
109 queue_slots: self.queue_slots.load(Ordering::Relaxed),
110 buffered_bytes: self.buffered_bytes.load(Ordering::Relaxed),
111 }
112 }
113}
114
115impl Default for IpcQuota {
116 fn default() -> Self {
117 Self::new()
118 }
119}
120
121#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123pub struct QuotaExceeded;
124
125#[derive(Debug, Clone, Copy)]
127pub struct QuotaSnapshot {
128 pub channels: u32,
129 pub queue_slots: u64,
130 pub buffered_bytes: u64,
131}