strat9_kernel/ipc/
port.rs1use super::message::IpcMessage;
8use crate::{
9 process::TaskId,
10 sync::{SpinLock, WaitQueue},
11};
12use alloc::{collections::BTreeMap, sync::Arc};
13use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
14use crossbeam_queue::ArrayQueue;
15
16const PORT_QUEUE_CAPACITY: usize = 16;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
21pub struct PortId(pub u64);
22
23impl PortId {
24 pub fn as_u64(self) -> u64 {
26 self.0
27 }
28
29 pub fn from_u64(raw: u64) -> Self {
31 PortId(raw)
32 }
33}
34
35impl core::fmt::Display for PortId {
36 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
38 write!(f, "{}", self.0)
39 }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
43pub enum IpcError {
44 #[error("port not found")]
45 PortNotFound,
46 #[error("not owner of port")]
47 NotOwner,
48 #[error("port destroyed")]
49 PortDestroyed,
50 #[error("port queue full")]
51 WouldBlock,
52 #[error("interrupted by signal")]
53 Interrupted,
54}
55
56pub struct Port {
58 pub id: PortId,
60 pub owner: TaskId,
62 queue: ArrayQueue<IpcMessage>,
64 destroyed: AtomicBool,
66 send_waitq: WaitQueue,
68 recv_waitq: WaitQueue,
70}
71
72impl Port {
73 fn new(id: PortId, owner: TaskId) -> Self {
75 Port {
76 id,
77 owner,
78 queue: ArrayQueue::new(PORT_QUEUE_CAPACITY),
79 destroyed: AtomicBool::new(false),
80 send_waitq: WaitQueue::new(),
81 recv_waitq: WaitQueue::new(),
82 }
83 }
84
85 pub fn send(&self, msg: IpcMessage) -> Result<(), IpcError> {
91 let result = self.send_waitq.wait_until(|| {
92 if crate::process::signal::has_pending_signals() {
94 return Some(Err(IpcError::Interrupted));
95 }
96 if self.destroyed.load(Ordering::Acquire) {
97 return Some(Err(IpcError::PortDestroyed));
98 }
99 match self.queue.push(msg) {
100 Ok(()) => Some(Ok(())),
101 Err(_) => None,
102 }
103 });
104 if result.is_ok() {
105 self.recv_waitq.wake_one();
106 }
107 result
108 }
109
110 pub fn recv(&self) -> Result<IpcMessage, IpcError> {
116 let result = self.recv_waitq.wait_until(|| {
117 if let Some(msg) = self.queue.pop() {
118 return Some(Ok(msg));
119 }
120 if crate::process::signal::has_pending_signals() {
122 return Some(Err(IpcError::Interrupted));
123 }
124 if self.destroyed.load(Ordering::Acquire) {
125 return Some(Err(IpcError::PortDestroyed));
126 }
127 None
128 });
129 if result.is_ok() {
130 self.send_waitq.wake_one();
131 }
132 result
133 }
134
135 pub fn try_send(&self, msg: IpcMessage) -> Result<(), IpcError> {
140 match self.queue.push(msg) {
141 Ok(()) => {
142 self.recv_waitq.wake_one();
143 Ok(())
144 }
145 Err(_) => Err(IpcError::WouldBlock),
146 }
147 }
148
149 pub fn try_recv(&self) -> Result<Option<IpcMessage>, IpcError> {
154 if let Some(msg) = self.queue.pop() {
155 self.send_waitq.wake_one();
156 return Ok(Some(msg));
157 }
158 if self.destroyed.load(Ordering::Acquire) {
159 return Err(IpcError::PortDestroyed);
160 }
161 Ok(None)
162 }
163
164 fn destroy(&self) {
166 self.destroyed.store(true, Ordering::Release);
167 self.send_waitq.wake_all();
168 self.recv_waitq.wake_all();
169 }
170
171 pub fn has_messages(&self) -> bool {
173 !self.queue.is_empty()
174 }
175
176 pub fn can_send(&self) -> bool {
178 !self.destroyed.load(Ordering::Acquire) && !self.queue.is_full()
179 }
180
181 pub fn is_destroyed(&self) -> bool {
183 self.destroyed.load(Ordering::Acquire)
184 }
185}
186
187static NEXT_PORT_ID: AtomicU64 = AtomicU64::new(1);
193
194static PORTS: SpinLock<Option<BTreeMap<PortId, Arc<Port>>>> = SpinLock::new(None);
196
197fn ensure_registry(guard: &mut Option<BTreeMap<PortId, Arc<Port>>>) {
199 if guard.is_none() {
200 *guard = Some(BTreeMap::new());
201 }
202}
203
204pub fn create_port(owner: TaskId) -> PortId {
206 let id = PortId(NEXT_PORT_ID.fetch_add(1, Ordering::Relaxed));
207 let port = Arc::new(Port::new(id, owner));
208
209 let mut registry = PORTS.lock();
210 ensure_registry(&mut *registry);
211 registry.as_mut().unwrap().insert(id, port);
212
213 log::debug!("IPC: created port {} (owner={})", id, owner);
214 id
215}
216
217pub fn get_port(id: PortId) -> Option<Arc<Port>> {
219 let registry = PORTS.lock();
220 registry.as_ref().and_then(|map| map.get(&id).cloned())
221}
222
223pub fn destroy_port(id: PortId, caller: TaskId) -> Result<(), IpcError> {
227 let port = {
228 let mut registry = PORTS.lock();
229 let map = registry.as_mut().ok_or(IpcError::PortNotFound)?;
230 let port = map.get(&id).ok_or(IpcError::PortNotFound)?;
231 if port.owner != caller {
232 return Err(IpcError::NotOwner);
233 }
234 let port = port.clone();
235 map.remove(&id);
236 port
237 };
238
239 port.destroy();
240 log::debug!("IPC: destroyed port {} (by task {})", id, caller);
241 Ok(())
242}
243
244pub fn cleanup_ports_for_task(owner: TaskId) {
253 super::reply::cancel_replies_waiting_on(owner);
254
255 let owned: alloc::vec::Vec<Arc<Port>> = {
256 let mut registry = PORTS.lock();
257 let Some(map) = registry.as_mut() else { return };
258 let ids: alloc::vec::Vec<PortId> = map
259 .iter()
260 .filter(|(_, p)| p.owner == owner)
261 .map(|(id, _)| *id)
262 .collect();
263 let mut ports = alloc::vec::Vec::with_capacity(ids.len());
264 for id in ids {
265 if let Some(p) = map.remove(&id) {
266 ports.push(p);
267 }
268 }
269 ports
270 };
271
272 for port in owned {
273 port.destroy();
274 while let Some(msg) = port.queue.pop() {
275 let sender = TaskId::from_u64(msg.sender);
276 if sender == owner {
277 continue;
278 }
279 let mut err_reply = IpcMessage::new(0x80);
280 let epipe: u32 = 32;
281 err_reply.payload[0..4].copy_from_slice(&epipe.to_le_bytes());
282 let _ = super::reply::deliver_reply(owner, sender, err_reply);
284 }
285 }
286}