feat(domain): add ThreadTable with spawn, get, destroy, and process filtering
This commit is contained in:
@@ -15,4 +15,6 @@ pub enum KernelError {
|
||||
TooManyThreadsInProcess,
|
||||
TooManyProcesses,
|
||||
InvalidStateTransition(ThreadId),
|
||||
InvalidThread(ThreadId),
|
||||
TooManyThreads,
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user