#[path = "../../../os-handles/lifetime/handles.rs"] mod handles; use handles::{CloseResult, Error, Object, Rights, SharedObjects, WaitResult}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct ProcessId { slot: u32, generation: u64 } const A: ProcessId = ProcessId { slot: 1, generation: 4 }; const B: ProcessId = ProcessId { slot: 2, generation: 7 }; const STALE_B: ProcessId = ProcessId { slot: 2, generation: 8 }; #[test] fn os_handles_close_positive() { let mut table = SharedObjects::::new(); let first = table.open_kernel(A, Object::Channel(52), Rights::WRITE).unwrap(); let second = table.grant_kernel(A, B, first, Rights::WRITE).unwrap(); assert_eq!(table.handles(), 2); assert_eq!(table.owned(A), 1); assert_eq!(table.owned(B), 1); assert_eq!(table.live_resources(), 1); assert_eq!(table.snapshot().resources[0], Some((Object::Channel(52), 2, false))); assert_eq!(table.query(A, first), Ok(Object::Channel(52))); assert_eq!(table.query(B, second), Ok(Object::Channel(52))); assert_eq!(table.close(A, first), Ok(CloseResult::Remaining(1))); assert_eq!(table.handles(), 1); assert_eq!(table.live_resources(), 1); assert_eq!(table.query(A, first), Err(Error::BadFd)); assert_eq!(table.query(B, second), Ok(Object::Channel(52))); assert_eq!(table.close(B, second), Ok(CloseResult::LastClosed)); assert_eq!(table.handles(), 0); assert_eq!(table.live_resources(), 0); assert_eq!(table.snapshot().resources, [None; 3]); assert_eq!(table.query(B, second), Err(Error::BadFd)); } #[test] fn os_handles_close_negative() { let mut table = SharedObjects::::new(); let first = table.open_kernel(A, Object::Channel(52), Rights::WRITE).unwrap(); let second = table.grant_kernel(A, B, first, Rights::WRITE).unwrap(); let wait = table.watch_close(B, second).unwrap(); assert_eq!(table.poll_close(B, wait), Ok(WaitResult::Pending)); let before = table.snapshot(); assert_eq!(table.poll_close(STALE_B, wait), Err(Error::BadFd)); assert_eq!(table.grant_kernel(STALE_B, A, second, Rights::WRITE), Err(Error::BadFd)); assert_eq!(table.snapshot(), before); assert_eq!(table.close(A, first), Ok(CloseResult::Remaining(1))); assert_eq!(table.poll_close(B, wait), Ok(WaitResult::Pending)); assert_eq!(table.close(B, second), Ok(CloseResult::LastClosed)); assert_eq!(table.handles(), 0); assert_eq!(table.live_resources(), 0); assert_eq!(table.snapshot().resources[0], Some((Object::Channel(52), 0, true))); assert_eq!(table.poll_close(B, wait), Ok(WaitResult::Closed)); assert_eq!(table.snapshot().resources, [None; 2]); let after = table.snapshot(); assert_eq!(table.poll_close(B, wait), Err(Error::BadFd)); assert_eq!(table.snapshot(), after); let healthy = table.open_kernel(A, Object::Channel(53), Rights::WRITE).unwrap(); assert_eq!(table.query(A, healthy), Ok(Object::Channel(53))); assert_eq!(table.close(A, healthy), Ok(CloseResult::LastClosed)); assert_eq!(table.live_resources(), 0); } #[test] fn failed_grant_and_watch_do_not_publish() { let mut table = SharedObjects::::new(); let first = table.open_kernel(A, Object::File(41), Rights::READ_WRITE).unwrap(); let before = table.snapshot(); assert_eq!(table.grant_kernel(A, B, first, Rights::READ), Err(Error::Full)); assert_eq!(table.grant_kernel(A, A, first, Rights::READ), Err(Error::Access)); assert_eq!(table.open_kernel(B, Object::File(41), Rights::READ), Err(Error::InvalidObject)); assert_eq!(table.snapshot(), before); let wait = table.watch_close(A, first).unwrap(); assert_eq!(table.watch_close(A, first), Err(Error::Full)); assert_eq!(table.close(A, first), Ok(CloseResult::LastClosed)); assert_eq!(table.poll_close(A, wait), Ok(WaitResult::Closed)); assert_eq!(table.snapshot().resources, [None; 1]); }