refactor(kernel): extract MockPlatform and test helpers into separate modules

This commit is contained in:
2026-10-18 01:16:24 +02:00
parent 192631d506
commit 241fefe2d4
3 changed files with 160 additions and 140 deletions

View File

@@ -0,0 +1,100 @@
use domain::memory::page_pool::PagePool;
use domain::resource::Resource;
use domain::scheduler::Scheduler;
use domain::thread::ThreadState;
use platform::Platform;
use types::{
address::PhysicalAddress,
bounded::{CapSlot, Priority},
id::{EndpointId, IrqId, ProcessId, ThreadId},
permission::PermissionSet,
time::TimeSlice,
};
use crate::Kernel;
use super::mock_platform::MockPlatform;
pub fn test_kernel() -> Kernel<MockPlatform> {
let mock = MockPlatform::new(1);
let pool = PagePool::new(PhysicalAddress::from_raw(0x8000_0000), 1024);
Kernel::new(mock, pool)
}
pub fn kernel_with_process() -> (Kernel<MockPlatform>, ProcessId) {
let mut kernel = test_kernel();
let (pid, _tid) = kernel
.boot(Priority::new(16).unwrap(), TimeSlice::new(100))
.unwrap();
(kernel, pid)
}
impl Kernel<MockPlatform> {
pub fn spawn_thread_for_test(
&mut self,
pid: ProcessId,
priority: Priority,
time_slice: TimeSlice,
) -> ThreadId {
let tid = self.threads.spawn(pid, priority, time_slice, None).expect("spawn");
let _ = self.processes.get_mut(pid).map(|p| p.add_thread(tid));
let core = self.platform.core_id();
self.scheduler.add(tid, priority, core);
tid
}
pub fn register_irq_for_test(&mut self, irq: IrqId, thread: ThreadId) {
let _ = self.irqs.register(irq, thread);
}
pub fn block_thread_for_test(
&mut self,
tid: ThreadId,
reason: domain::thread::BlockReason,
) {
let core = self.platform.core_id();
if let Ok(t) = self.threads.get_mut(tid) {
if matches!(t.state(), ThreadState::Ready) {
let _ = t.set_running(core);
}
let _ = t.block(reason);
}
self.scheduler.remove(tid);
}
pub fn switch_to_thread_for_test(&mut self, tid: ThreadId) {
let core = self.platform.core_id();
if let Some(current) = self.scheduler.current(core) {
if current == tid {
return;
}
if let Ok(t) = self.threads.get_mut(current) {
if matches!(t.state(), ThreadState::Running(_)) {
let priority = t.priority();
let _ = t.preempt();
self.scheduler.add(current, priority, core);
}
}
}
if let Ok(t) = self.threads.get(tid) {
if matches!(t.state(), ThreadState::Ready) {
self.scheduler.next(core);
let _ = self.threads.get_mut(tid).map(|t| t.set_running(core));
}
}
}
pub fn create_endpoint_for_test(&mut self) -> EndpointId {
self.endpoints.create().expect("create endpoint")
}
pub fn grant_cap_for_test(
&mut self,
pid: ProcessId,
resource: Resource,
permissions: PermissionSet,
) -> CapSlot {
self.grant_cap(pid, resource, permissions).expect("grant cap")
}
}

View File

@@ -0,0 +1,49 @@
use domain::memory::MemoryRegion;
use domain::thread::SavedContext;
use platform::Platform;
use types::{
address::{EntryPoint, StackPointer},
id::{CoreId, IrqId, ProcessId},
time::{Ticks, TimerDuration},
};
pub struct MockPlatform {
ticks: Ticks,
core: CoreId,
cores: u8,
}
impl MockPlatform {
pub fn new(num_cores: u8) -> Self {
Self {
ticks: Ticks::from_raw(0),
core: CoreId::from_raw(0),
cores: num_cores,
}
}
pub fn set_ticks(&mut self, ticks: Ticks) {
self.ticks = ticks;
}
}
impl Platform for MockPlatform {
fn configure_protection(&mut self, _process: ProcessId, _regions: &[MemoryRegion]) {}
fn context_switch(&mut self, _from: &mut SavedContext, _to: &SavedContext) {}
fn enable_user_mode(&mut self, _entry: EntryPoint, _stack: StackPointer) -> ! {
loop {}
}
fn set_timer(&mut self, _duration: TimerDuration) {}
fn current_ticks(&self) -> Ticks {
self.ticks
}
fn mask_irq(&mut self, _irq: IrqId) {}
fn unmask_irq(&mut self, _irq: IrqId) {}
fn send_ipi(&mut self, _target: CoreId) {}
fn core_id(&self) -> CoreId {
self.core
}
fn num_cores(&self) -> u8 {
self.cores
}
}

View File

@@ -1,3 +1,6 @@
mod mock_platform;
mod helpers;
mod capability;
mod exit;
mod ipc;
@@ -6,144 +9,12 @@ mod memory;
mod simple;
mod tick;
use domain::memory::page_pool::PagePool;
use domain::memory::MemoryRegion;
use domain::resource::Resource;
use domain::scheduler::Scheduler;
use domain::thread::{SavedContext, ThreadState};
use platform::Platform;
use types::{
address::{EntryPoint, PhysicalAddress, StackPointer},
bounded::{CapSlot, Priority},
id::{CoreId, EndpointId, IrqId, ProcessId, ThreadId},
permission::PermissionSet,
time::{Ticks, TimerDuration, TimeSlice},
};
pub use mock_platform::MockPlatform;
pub use helpers::{test_kernel, kernel_with_process};
use crate::{Kernel, SyscallResult};
pub struct MockPlatform {
ticks: Ticks,
core: CoreId,
cores: u8,
}
impl MockPlatform {
pub fn new(num_cores: u8) -> Self {
Self {
ticks: Ticks::from_raw(0),
core: CoreId::from_raw(0),
cores: num_cores,
}
}
pub fn set_ticks(&mut self, ticks: Ticks) {
self.ticks = ticks;
}
}
impl Platform for MockPlatform {
fn configure_protection(&mut self, _process: ProcessId, _regions: &[MemoryRegion]) {}
fn context_switch(&mut self, _from: &mut SavedContext, _to: &SavedContext) {}
fn enable_user_mode(&mut self, _entry: EntryPoint, _stack: StackPointer) -> ! {
loop {}
}
fn set_timer(&mut self, _duration: TimerDuration) {}
fn current_ticks(&self) -> Ticks {
self.ticks
}
fn mask_irq(&mut self, _irq: IrqId) {}
fn unmask_irq(&mut self, _irq: IrqId) {}
fn send_ipi(&mut self, _target: CoreId) {}
fn core_id(&self) -> CoreId {
self.core
}
fn num_cores(&self) -> u8 {
self.cores
}
}
pub fn test_kernel() -> Kernel<MockPlatform> {
let mock = MockPlatform::new(1);
let pool = PagePool::new(PhysicalAddress::from_raw(0x8000_0000), 1024);
Kernel::new(mock, pool)
}
pub fn kernel_with_process() -> (Kernel<MockPlatform>, ProcessId) {
let mut kernel = test_kernel();
let (pid, _tid) = kernel
.boot(Priority::new(16).unwrap(), TimeSlice::new(100))
.unwrap();
(kernel, pid)
}
impl Kernel<MockPlatform> {
pub fn spawn_thread_for_test(
&mut self,
pid: ProcessId,
priority: Priority,
time_slice: TimeSlice,
) -> ThreadId {
let tid = self.threads.spawn(pid, priority, time_slice, None).expect("spawn");
let _ = self.processes.get_mut(pid).map(|p| p.add_thread(tid));
let core = self.platform.core_id();
self.scheduler.add(tid, priority, core);
tid
}
pub fn register_irq_for_test(&mut self, irq: IrqId, thread: ThreadId) {
let _ = self.irqs.register(irq, thread);
}
pub fn block_thread_for_test(
&mut self,
tid: ThreadId,
reason: domain::thread::BlockReason,
) {
let core = self.platform.core_id();
if let Ok(t) = self.threads.get_mut(tid) {
if matches!(t.state(), ThreadState::Ready) {
let _ = t.set_running(core);
}
let _ = t.block(reason);
}
self.scheduler.remove(tid);
}
pub fn switch_to_thread_for_test(&mut self, tid: ThreadId) {
let core = self.platform.core_id();
if let Some(current) = self.scheduler.current(core) {
if current == tid {
return;
}
if let Ok(t) = self.threads.get_mut(current) {
if matches!(t.state(), ThreadState::Running(_)) {
let priority = t.priority();
let _ = t.preempt();
self.scheduler.add(current, priority, core);
}
}
}
if let Ok(t) = self.threads.get(tid) {
if matches!(t.state(), ThreadState::Ready) {
self.scheduler.next(core);
let _ = self.threads.get_mut(tid).map(|t| t.set_running(core));
}
}
}
pub fn create_endpoint_for_test(&mut self) -> EndpointId {
self.endpoints.create().expect("create endpoint")
}
pub fn grant_cap_for_test(
&mut self,
pid: ProcessId,
resource: Resource,
permissions: PermissionSet,
) -> CapSlot {
self.grant_cap(pid, resource, permissions).expect("grant cap")
}
}
pub use crate::Kernel;
pub use types::address::PhysicalAddress;
pub use types::bounded::Priority;
pub use types::id::ProcessId;
pub use types::time::TimeSlice;
pub use domain::memory::page_pool::PagePool;