use crate::cap::pool::POOL; use crate::ipc::IpcOutcome; use crate::ipc::notification; use crate::proc::{PROCESSES, ProcessState}; use crate::tests::helpers::alloc_notification_cap; use lancer_core::object_layout::NotificationObject; crate::kernel_test!( fn signal_sets_word_bits() { let (id, generation, cap) = alloc_notification_cap(); let mut ptable = PROCESSES.lock(); notification::do_signal(&cap, 0x0F, &mut ptable).expect("signal"); let pool = POOL.lock(); let notif = pool .read_as::(id, generation) .expect("read notification"); assert!(notif.word == 0x0F, "word should have bits set"); drop(pool); drop(ptable); let _ = POOL.lock().dec_ref_phys(id, generation); } ); crate::kernel_test!( fn signal_accumulates_bits() { let (id, generation, cap) = alloc_notification_cap(); let mut ptable = PROCESSES.lock(); notification::do_signal(&cap, 0x01, &mut ptable).expect("signal 1"); notification::do_signal(&cap, 0x02, &mut ptable).expect("signal 2"); let pool = POOL.lock(); let notif = pool .read_as::(id, generation) .expect("read notification"); assert!(notif.word == 0x03, "bits should accumulate via OR"); drop(pool); drop(ptable); let _ = POOL.lock().dec_ref_phys(id, generation); } ); crate::kernel_test!( fn poll_returns_word_and_clears() { let (id, generation, cap) = alloc_notification_cap(); { let mut pool = POOL.lock(); let notif = pool .write_as::(id, generation) .expect("write notification"); notif.word = 0xFF; } let val = notification::do_poll(&cap).expect("poll"); assert!(val == 0xFF, "poll should return accumulated word"); let val2 = notification::do_poll(&cap).expect("poll again"); assert!(val2 == 0, "second poll should return 0 after clear"); let _ = POOL.lock().dec_ref_phys(id, generation); } ); crate::kernel_test!( fn wait_with_pending_returns_immediately() { let (id, generation, cap) = alloc_notification_cap(); let mut allocator = crate::mem::phys::BitmapFrameAllocator; let mut ptable = PROCESSES.lock(); let created = ptable.allocate(&mut allocator).expect("alloc"); ptable.start(created).expect("start"); let pid = created.pid(); ptable.simulate_dispatch(pid); { let mut pool = POOL.lock(); let notif = pool .write_as::(id, generation) .expect("write notification"); notif.word = 0xAB; } let result = notification::do_wait(&cap, pid, &mut ptable).expect("wait"); match result { IpcOutcome::Done(bits) => assert!(bits == 0xAB, "should return pending word"), IpcOutcome::Blocked => panic!("should not block when word is pending"), } ptable.destroy(pid, &mut allocator); let _ = POOL.lock().dec_ref_phys(id, generation); } ); crate::kernel_test!( fn wait_without_pending_blocks() { let (id, generation, cap) = alloc_notification_cap(); let mut allocator = crate::mem::phys::BitmapFrameAllocator; let mut ptable = PROCESSES.lock(); let created = ptable.allocate(&mut allocator).expect("alloc"); ptable.start(created).expect("start"); let pid = created.pid(); ptable.simulate_dispatch(pid); let result = notification::do_wait(&cap, pid, &mut ptable).expect("wait"); match result { IpcOutcome::Blocked => { assert!( ptable[pid].state() == ProcessState::Blocked, "process should be Blocked" ); } IpcOutcome::Done(_) => panic!("should block when no word pending"), } ptable.destroy(pid, &mut allocator); let _ = POOL.lock().dec_ref_phys(id, generation); } ); crate::kernel_test!( fn signal_wakes_blocked_waiter() { let (id, generation, cap) = alloc_notification_cap(); let mut allocator = crate::mem::phys::BitmapFrameAllocator; let mut ptable = PROCESSES.lock(); let created = ptable.allocate(&mut allocator).expect("alloc"); ptable.start(created).expect("start"); let pid = created.pid(); ptable.simulate_dispatch(pid); let result = notification::do_wait(&cap, pid, &mut ptable).expect("wait"); assert!(matches!(result, IpcOutcome::Blocked)); notification::do_signal(&cap, 0xDEAD, &mut ptable).expect("signal"); assert!( ptable[pid].state() == ProcessState::Ready, "waiter should be unblocked after signal" ); assert!( ptable.exec(pid).unwrap().saved_context.rdx == 0xDEAD, "waiter's rdx should hold the signaled word" ); assert!( ptable.exec(pid).unwrap().saved_context.rax == 0, "waiter's rax should be 0 (success)" ); ptable.destroy(pid, &mut allocator); let _ = POOL.lock().dec_ref_phys(id, generation); } ); crate::kernel_test!( fn poll_on_empty_returns_zero() { let (id, generation, cap) = alloc_notification_cap(); let val = notification::do_poll(&cap).expect("poll"); assert!(val == 0, "poll on fresh notification should return 0"); let _ = POOL.lock().dec_ref_phys(id, generation); } );