TaskPool

Struct TaskPool 

Source
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:

  1. Stable Box Memory: Tasks are stored in Box<[Option<Task>; MAX_TASKS]>. Box guarantees the underlying array pointer never moves after allocation, making &'static references safe in practice.

  2. Direct Indexing: task_id == index provides O(1) access without HashMap overhead. No rehashing or reallocation can occur.

  3. Scheduler Control: The scheduler controls all task removal and ensures that the currently running task is never removed during context switches.

  4. 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 references
  • TaskPool::get_task_mut() for mutable references
  • Scheduler::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: AtomicUsize

Implementations§

Source§

impl TaskPool

Source

fn new() -> Self

Source

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

Source

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

Source

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.

Source

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
Source

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:

  1. The task being removed is NOT currently running on any CPU
  2. No context switch is in progress for this task
  3. 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
Source

fn contains_task(&self, task_id: usize) -> bool

Auto Trait Implementations§

§

impl !Freeze for TaskPool

§

impl !RefUnwindSafe for TaskPool

§

impl Send for TaskPool

§

impl Sync for TaskPool

§

impl Unpin for TaskPool

§

impl !UnwindSafe for TaskPool

Blanket Implementations§

§

impl<T> Any for T
where T: 'static + ?Sized,

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Borrow<T> for T
where T: ?Sized,

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

impl<T> BorrowMut<T> for T
where T: ?Sized,

§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T, U> Into<U> for T
where U: From<T>,

§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.