feat(domain): add ThreadTable with spawn, get, destroy, and process filtering
This commit is contained in:
@@ -15,4 +15,6 @@ pub enum KernelError {
|
|||||||
TooManyThreadsInProcess,
|
TooManyThreadsInProcess,
|
||||||
TooManyProcesses,
|
TooManyProcesses,
|
||||||
InvalidStateTransition(ThreadId),
|
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();
|
let expired = t.time_slice_mut().tick();
|
||||||
assert!(!expired);
|
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