pub struct TaskPool {
tasks: Mutex<Box<[Option<Task>; 1024]>>,
free_ids: Mutex<VecDeque<usize>>,
next_id: AtomicUsize,
}Expand description
Global task pool storing all tasks in a Box-ed fixed-size array
§Safety
This struct provides unsafe access to tasks through get_task() and get_task_mut()
which return &'static references without holding locks. This is safe because:
-
Stable Box Memory: Tasks are stored in
Box<[Option<Task>; MAX_TASKS]>. Box guarantees the underlying array pointer never moves after allocation, making&'staticreferences safe in practice. -
Direct Indexing:
task_id == indexprovides O(1) access without HashMap overhead. No rehashing or reallocation can occur. -
Scheduler Control: The scheduler controls all task removal and ensures that the currently running task is never removed during context switches.
-
Single-Core Execution: Current implementation is single-core, preventing concurrent access during context switches.
IMPORTANT: Do NOT directly access the tasks array. Always use:
TaskPool::get_task()for immutable referencesTaskPool::get_task_mut()for mutable referencesScheduler::get_task_by_id()which is the preferred public API
Direct array access could violate safety assumptions and cause undefined behavior.
§Memory Layout
The tasks array is allocated directly on heap via Vec→Box conversion:
- No intermediate stack allocation (824KB never touches stack)
- Box<[T]> provides stable pointer for &’static references
- Array size is fixed at compile time (MAX_TASKS = 1024)
Fields§
§tasks: Mutex<Box<[Option<Task>; 1024]>>§free_ids: Mutex<VecDeque<usize>>§next_id: AtomicUsizeImplementations§
Source§impl TaskPool
impl TaskPool
fn new() -> Self
Sourcepub fn allocate_id(&self) -> Option<usize>
pub fn allocate_id(&self) -> Option<usize>
Allocate a new task ID Tries to reuse freed IDs first, then allocates new ones sequentially Uses atomic operations for lock-free allocation
Sourcefn add_task(&self, task: Task) -> Result<usize, &'static str>
fn add_task(&self, task: Task) -> Result<usize, &'static str>
Add a task to the pool Allocates an ID, sets it on the task, and returns the ID
Sourcepub fn get_task(task_id: usize) -> Option<&'static Task>
pub fn get_task(task_id: usize) -> Option<&'static Task>
Get a task reference by ID Returns a static reference using raw pointer for lifetime extension
§Safety
This function is safe to use under the following conditions:
- The task must not be removed while the returned reference is in use
- In context switching scenarios, the currently running task is never removed
- Single-core execution ensures no concurrent removal during context switch
The returned reference points to a fixed location in the TaskPool’s Box-ed array (task_id == index), so the address is stable:
- Box guarantees the underlying array never moves
- Unlike Vec or HashMap, no reallocation can occur
- The pointer remains valid for the lifetime of the program
Important: Do NOT directly access TaskPool::tasks array.
Always use this method or get_task_mut() to ensure proper safety.
Sourcepub fn get_task_mut(task_id: usize) -> Option<&'static mut Task>
pub fn get_task_mut(task_id: usize) -> Option<&'static mut Task>
Get a mutable task reference by ID Returns a static mutable reference using raw pointer for lifetime extension
§Safety
This function is safe to use under the following conditions:
- The task must not be removed while the returned reference is in use
- In context switching scenarios, the currently running task is never removed
- Single-core execution ensures no concurrent access during context switch
The returned reference points to a fixed location in the TaskPool’s Box-ed array (task_id == index), so the address is stable:
- Box guarantees the underlying array never moves
- Unlike Vec or HashMap, no reallocation can occur
- The pointer remains valid for the lifetime of the program
Important: Do NOT directly access TaskPool::tasks array.
Always use this method or get_task() to ensure proper safety.
§Note
This is technically UB in Rust (returning &’static mut without holding lock), but safe in practice because:
- Box<[T]> provides stable memory location (pointer never changes)
- The scheduler ensures exclusive access during context switches
- Single-core execution prevents concurrent mutable access
- Currently running task is never removed
Sourcefn remove_task(&self, task_id: usize) -> Option<Task>
fn remove_task(&self, task_id: usize) -> Option<Task>
Remove a task from the pool
§Safety
CRITICAL: This method invalidates all &'static references returned by
get_task() and get_task_mut() for this task_id. The scheduler must ensure:
- The task being removed is NOT currently running on any CPU
- No context switch is in progress for this task
- No references to this task are held elsewhere
The scheduler enforces this by:
- Only removing tasks from zombie_queue (already exited)
- Never removing the currently running task
- Ensuring the task is not in ready/blocked queues before removal