feat(domain): add ThreadTable with spawn, get, destroy, and process filtering

This commit is contained in:
2026-10-17 23:29:46 +02:00
parent 6444de69b8
commit 14b18f7406
3 changed files with 120 additions and 0 deletions

View File

@@ -141,3 +141,66 @@ impl Thread {
}
}
}
pub const MAX_THREADS: usize = 256;
pub struct ThreadTable {
threads: [Option<Thread>; MAX_THREADS],
}
impl ThreadTable {
pub fn new() -> Self {
Self {
threads: [const { None }; MAX_THREADS],
}
}
pub fn spawn(
&mut self,
process: ProcessId,
priority: Priority,
time_slice: TimeSlice,
core_affinity: Option<CoreId>,
) -> Result<ThreadId, KernelError> {
let idx = self
.threads
.iter()
.position(|s| s.is_none())
.ok_or(KernelError::TooManyThreads)?;
let id = ThreadId::from_raw(idx as u16);
self.threads[idx] = Some(Thread::new(id, process, priority, time_slice, core_affinity));
Ok(id)
}
pub fn get(&self, id: ThreadId) -> Result<&Thread, KernelError> {
let idx = id.raw() as usize;
self.threads
.get(idx)
.and_then(|s| s.as_ref())
.ok_or(KernelError::InvalidThread(id))
}
pub fn get_mut(&mut self, id: ThreadId) -> Result<&mut Thread, KernelError> {
let idx = id.raw() as usize;
self.threads
.get_mut(idx)
.and_then(|s| s.as_mut())
.ok_or(KernelError::InvalidThread(id))
}
pub fn destroy(&mut self, id: ThreadId) -> Result<Thread, KernelError> {
let idx = id.raw() as usize;
self.threads
.get_mut(idx)
.and_then(|s| s.take())
.ok_or(KernelError::InvalidThread(id))
}
pub fn threads_for_process(&self, process: ProcessId) -> impl Iterator<Item = &Thread> {
self.threads
.iter()
.filter_map(|s| s.as_ref())
.filter(move |t| t.process() == process)
}
}

View File

@@ -156,3 +156,58 @@ fn time_slice_mut_ticks() {
let expired = t.time_slice_mut().tick();
assert!(!expired);
}
// --- ThreadTable tests ---
#[test]
fn table_spawn_and_lookup() {
let mut table = ThreadTable::new();
let id = table.spawn(process(0), prio(10), time_slice(), None).unwrap();
let t = table.get(id).unwrap();
assert_eq!(t.id(), id);
assert_eq!(t.process(), process(0));
}
#[test]
fn table_spawn_returns_unique_ids() {
let mut table = ThreadTable::new();
let a = table.spawn(process(0), prio(10), time_slice(), None).unwrap();
let b = table.spawn(process(0), prio(10), time_slice(), None).unwrap();
assert_ne!(a, b);
}
#[test]
fn table_destroy_then_get_fails() {
let mut table = ThreadTable::new();
let id = table.spawn(process(0), prio(10), time_slice(), None).unwrap();
table.destroy(id).unwrap();
assert!(table.get(id).is_err());
}
#[test]
fn table_threads_for_process_filters() {
let mut table = ThreadTable::new();
table.spawn(process(0), prio(10), time_slice(), None).unwrap();
table.spawn(process(1), prio(10), time_slice(), None).unwrap();
table.spawn(process(0), prio(5), time_slice(), None).unwrap();
let count = table.threads_for_process(process(0)).count();
assert_eq!(count, 2);
}
#[test]
fn table_get_mut_allows_state_transition() {
let mut table = ThreadTable::new();
let id = table.spawn(process(0), prio(10), time_slice(), None).unwrap();
table.get_mut(id).unwrap().set_running(core(0)).unwrap();
assert!(matches!(table.get(id).unwrap().state(), ThreadState::Running(_)));
}
#[test]
fn table_destroy_reuses_slot() {
let mut table = ThreadTable::new();
let id = table.spawn(process(0), prio(10), time_slice(), None).unwrap();
table.destroy(id).unwrap();
let new_id = table.spawn(process(0), prio(10), time_slice(), None).unwrap();
assert_eq!(id, new_id);
}