strat9_kernel/ipc/
test.rs1use crate::{
19 ipc::{self, channel, IpcMessage, PortId},
20 process::{add_task, Task, TaskPriority},
21 sync::SpinLock,
22};
23use core::sync::atomic::{AtomicU64, Ordering};
24
25static TEST_PORT_ID: AtomicU64 = AtomicU64::new(0);
32
33pub fn create_ipc_test_tasks() {
35 let task_a = Task::new_kernel_task(ipc_sender_main, "ipc-sender", TaskPriority::Normal)
36 .expect("Failed to create IPC sender task");
37 add_task(task_a);
38
39 let task_b = Task::new_kernel_task(ipc_receiver_main, "ipc-recv", TaskPriority::Normal)
40 .expect("Failed to create IPC receiver task");
41 add_task(task_b);
42}
43
44extern "C" fn ipc_sender_main() -> ! {
46 crate::serial_println!("[ipc-test] Task A (sender): starting");
47
48 let my_id = crate::process::current_task_id().unwrap();
50 crate::serial_println!("[ipc-test] Task A: creating port...");
51
52 let port_id = ipc::create_port(my_id);
53 crate::serial_println!("[ipc-test] Task A: port {} created", port_id);
54
55 TEST_PORT_ID.store(port_id.as_u64(), Ordering::Release);
57
58 crate::process::yield_task();
61 crate::process::yield_task();
62
63 let mut msg = IpcMessage::new(42); msg.payload[0] = b'H';
66 msg.payload[1] = b'i';
67 msg.payload[2] = b'!';
68
69 crate::serial_println!("[ipc-test] Task A: sending message (type=42)...");
70 let port = ipc::get_port(port_id).expect("port should exist");
71 port.send(msg).expect("send should succeed");
72 crate::serial_println!("[ipc-test] Task A: message sent, exiting");
73
74 crate::process::scheduler::exit_current_task(0);
75}
76
77extern "C" fn ipc_receiver_main() -> ! {
79 crate::serial_println!("[ipc-test] Task B (receiver): starting");
80
81 let port_id = loop {
83 let id = TEST_PORT_ID.load(Ordering::Acquire);
84 if id != 0 {
85 break PortId(id);
86 }
87 crate::process::yield_task();
88 };
89
90 crate::serial_println!("[ipc-test] Task B: found port {}, calling recv...", port_id);
91
92 let port = ipc::get_port(port_id).expect("port should exist");
93 let msg = port.recv().expect("recv should succeed");
94
95 let sender = msg.sender;
96 let msg_type = msg.msg_type;
97 crate::serial_println!(
98 "[ipc-test] Task B: received message (type={}, sender={})",
99 msg_type,
100 sender,
101 );
102
103 if msg_type == 42 && msg.payload[0] == b'H' && msg.payload[1] == b'i' && msg.payload[2] == b'!'
105 {
106 crate::serial_println!("[ipc-test] IPC ping-pong test PASSED");
107 } else {
108 crate::serial_println!("[ipc-test] IPC ping-pong test FAILED (unexpected data)");
109 }
110
111 crate::process::scheduler::exit_current_task(0);
112}
113
114static CHAN_TX1: SpinLock<Option<channel::Sender<u64>>> = SpinLock::new(None);
130static CHAN_TX2: SpinLock<Option<channel::Sender<u64>>> = SpinLock::new(None);
131static CHAN_RX: SpinLock<Option<channel::Receiver<u64>>> = SpinLock::new(None);
132
133pub fn create_channel_test_tasks() {
135 let (tx, rx) = channel::channel::<u64>(4);
136 let tx2 = tx.clone(); *CHAN_TX1.lock() = Some(tx);
139 *CHAN_TX2.lock() = Some(tx2);
140 *CHAN_RX.lock() = Some(rx);
141
142 let producer1 = Task::new_kernel_task(chan_producer1_main, "chan-prod-1", TaskPriority::Normal)
143 .expect("chan-prod-1 alloc failed");
144 let producer2 = Task::new_kernel_task(chan_producer2_main, "chan-prod-2", TaskPriority::Normal)
145 .expect("chan-prod-2 alloc failed");
146 let consumer = Task::new_kernel_task(chan_consumer_main, "chan-consumer", TaskPriority::Normal)
147 .expect("chan-consumer alloc failed");
148
149 add_task(producer1);
150 add_task(producer2);
151 add_task(consumer);
152}
153
154extern "C" fn chan_producer1_main() -> ! {
156 crate::serial_println!("[chan-test] Producer-1: starting");
157 let tx = CHAN_TX1.lock().take().expect("CHAN_TX1 empty");
158
159 for v in [1u64, 2, 3] {
160 crate::serial_println!("[chan-test] Producer-1: sending {}", v);
161 tx.send(v).expect("prod1 send failed");
162 }
163
164 crate::serial_println!("[chan-test] Producer-1: done");
165 drop(tx); crate::process::scheduler::exit_current_task(0);
167}
168
169extern "C" fn chan_producer2_main() -> ! {
171 crate::serial_println!("[chan-test] Producer-2: starting");
172 let tx = CHAN_TX2.lock().take().expect("CHAN_TX2 empty");
173
174 crate::process::yield_task(); for v in [4u64, 5] {
177 crate::serial_println!("[chan-test] Producer-2: sending {}", v);
178 tx.send(v).expect("prod2 send failed");
179 }
180
181 crate::serial_println!("[chan-test] Producer-2: done");
182 drop(tx); crate::process::scheduler::exit_current_task(0);
184}
185
186extern "C" fn chan_consumer_main() -> ! {
188 crate::serial_println!("[chan-test] Consumer: starting");
189 let rx = CHAN_RX.lock().take().expect("CHAN_RX empty");
190
191 let mut received: u64 = 0;
192 loop {
193 match rx.recv() {
194 Ok(v) => {
195 crate::serial_println!("[chan-test] Consumer: got {}", v);
196 received += 1;
197 }
198 Err(channel::ChannelError::Disconnected) => {
199 crate::serial_println!(
200 "[chan-test] Consumer: disconnected after {} msgs",
201 received
202 );
203 break;
204 }
205 Err(e) => {
206 crate::serial_println!("[chan-test] Consumer: unexpected error {:?}", e);
207 break;
208 }
209 }
210 }
211
212 if received == 5 {
213 crate::serial_println!(
214 "[chan-test] SyncChannel MPMC test PASSED ({} msgs)",
215 received
216 );
217 } else {
218 crate::serial_println!(
219 "[chan-test] SyncChannel MPMC test FAILED (expected 5, got {})",
220 received
221 );
222 }
223
224 crate::process::scheduler::exit_current_task(0);
225}
226
227static SEM_TEST_ID: AtomicU64 = AtomicU64::new(0);
232static SEM_TEST_RESULT: SpinLock<Option<bool>> = SpinLock::new(None);
233
234pub fn create_ipc_04_05_test_task() {
236 let task = Task::new_kernel_task(ipc_04_05_main, "ipc-04-05-test", TaskPriority::Normal)
237 .expect("Failed to create ipc-04-05-test task");
238 add_task(task);
239}
240
241extern "C" fn ipc_04_05_main() -> ! {
243 crate::serial_println!("[ipc-04-05] start");
244
245 let ring_id = match ipc::shared_ring::create_ring(8192) {
246 Ok(id) => id,
247 Err(e) => {
248 crate::serial_println!("[ipc-04-05] FAIL ring create: {:?}", e);
249 crate::process::scheduler::exit_current_task(1);
250 }
251 };
252
253 let ring = match ipc::shared_ring::get_ring(ring_id) {
254 Some(r) => r,
255 None => {
256 crate::serial_println!("[ipc-04-05] FAIL ring lookup");
257 crate::process::scheduler::exit_current_task(1);
258 }
259 };
260 let pages = ring.page_count();
261 let addrs = ring.frame_phys_addrs();
262 if pages < 2 || addrs.len() != pages {
263 crate::serial_println!(
264 "[ipc-04-05] FAIL ring layout pages={} addrs={}",
265 pages,
266 addrs.len()
267 );
268 let _ = ipc::shared_ring::destroy_ring(ring_id);
269 crate::process::scheduler::exit_current_task(1);
270 }
271
272 if ipc::shared_ring::destroy_ring(ring_id).is_err()
273 || ipc::shared_ring::get_ring(ring_id).is_some()
274 {
275 crate::serial_println!("[ipc-04-05] FAIL ring destroy");
276 crate::process::scheduler::exit_current_task(1);
277 }
278
279 let sem_id = match ipc::semaphore::create_semaphore(0) {
280 Ok(id) => id,
281 Err(e) => {
282 crate::serial_println!("[ipc-04-05] FAIL sem create: {:?}", e);
283 crate::process::scheduler::exit_current_task(1);
284 }
285 };
286 SEM_TEST_ID.store(sem_id.as_u64(), Ordering::Release);
287
288 let poster = Task::new_kernel_task(sem_poster_main, "ipc-sem-poster", TaskPriority::Normal)
289 .expect("Failed to create ipc-sem-poster task");
290 add_task(poster);
291
292 let sem = ipc::semaphore::get_semaphore(sem_id).expect("sem should exist");
293
294 if !matches!(
295 sem.try_wait(),
296 Err(ipc::semaphore::SemaphoreError::WouldBlock)
297 ) {
298 crate::serial_println!("[ipc-04-05] FAIL sem try_wait should block");
299 let _ = ipc::semaphore::destroy_semaphore(sem_id);
300 crate::process::scheduler::exit_current_task(1);
301 }
302
303 let wait_ok = sem.wait().is_ok();
304 *SEM_TEST_RESULT.lock() = Some(wait_ok);
305
306 if !wait_ok {
307 crate::serial_println!("[ipc-04-05] FAIL sem wait");
308 let _ = ipc::semaphore::destroy_semaphore(sem_id);
309 crate::process::scheduler::exit_current_task(1);
310 }
311
312 if ipc::semaphore::destroy_semaphore(sem_id).is_err() {
313 crate::serial_println!("[ipc-04-05] FAIL sem destroy");
314 crate::process::scheduler::exit_current_task(1);
315 }
316
317 crate::serial_println!("[ipc-04-05] PASSED");
318 crate::process::scheduler::exit_current_task(0);
319}
320
321extern "C" fn sem_poster_main() -> ! {
323 for _ in 0..4 {
324 crate::process::yield_task();
325 }
326 let sem_id = ipc::semaphore::SemId::from_u64(SEM_TEST_ID.load(Ordering::Acquire));
327 if let Some(sem) = ipc::semaphore::get_semaphore(sem_id) {
328 let _ = sem.post();
329 }
330 crate::process::scheduler::exit_current_task(0);
331}