use crate::cap::object::{NotificationData, ObjectData, ObjectTag}; use crate::cap::pool::POOL; use crate::cap::table::{CapRef, Rights}; use crate::ipc::IpcOutcome; use crate::ipc::notification; use crate::proc::{PROCESSES, ProcessState}; fn alloc_notification() -> (crate::types::ObjectId, crate::types::Generation, CapRef) { let (id, generation) = POOL .lock() .allocate(ObjectData::Notification(NotificationData::new())) .expect("alloc notification"); let cap = CapRef::new(ObjectTag::Notification, id, Rights::ALL, generation); (id, generation, cap) } crate::kernel_test!( fn signal_sets_word_bits() { let (id, generation, cap) = alloc_notification(); let mut ptable = PROCESSES.lock(); notification::do_signal(&cap, 0x0F, &mut ptable).expect("signal"); let mut pool = POOL.lock(); let notif = pool .get_mut(id, generation) .unwrap() .as_notification_mut() .unwrap(); assert!(notif.word == 0x0F, "word should have bits set"); drop(pool); drop(ptable); let _ = POOL.lock().dec_ref(id, generation); } ); crate::kernel_test!( fn signal_accumulates_bits() { let (id, generation, cap) = alloc_notification(); 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 mut pool = POOL.lock(); let notif = pool .get_mut(id, generation) .unwrap() .as_notification_mut() .unwrap(); assert!(notif.word == 0x03, "bits should accumulate via OR"); drop(pool); drop(ptable); let _ = POOL.lock().dec_ref(id, generation); } ); crate::kernel_test!( fn poll_returns_word_and_clears() { let (id, generation, cap) = alloc_notification(); { let mut pool = POOL.lock(); pool.get_mut(id, generation) .unwrap() .as_notification_mut() .unwrap() .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(id, generation); } ); crate::kernel_test!( fn wait_with_pending_returns_immediately() { let (id, generation, cap) = alloc_notification(); 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[pid] .transition_to(ProcessState::Running) .expect("-> Running"); { let mut pool = POOL.lock(); pool.get_mut(id, generation) .unwrap() .as_notification_mut() .unwrap() .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(id, generation); } ); crate::kernel_test!( fn wait_without_pending_blocks() { let (id, generation, cap) = alloc_notification(); 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[pid] .transition_to(ProcessState::Running) .expect("-> Running"); 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(id, generation); } ); crate::kernel_test!( fn signal_wakes_blocked_waiter() { let (id, generation, cap) = alloc_notification(); 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[pid] .transition_to(ProcessState::Running) .expect("-> Running"); 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[pid].saved_context.rdx == 0xDEAD, "waiter's rdx should hold the signaled word" ); assert!( ptable[pid].saved_context.rax == 0, "waiter's rax should be 0 (success)" ); ptable.destroy(pid, &mut allocator); let _ = POOL.lock().dec_ref(id, generation); } ); crate::kernel_test!( fn poll_on_empty_returns_zero() { let (id, generation, cap) = alloc_notification(); let val = notification::do_poll(&cap).expect("poll"); assert!(val == 0, "poll on fresh notification should return 0"); let _ = POOL.lock().dec_ref(id, generation); } );