Phase 04
Tasking
Introduce multiple concurrent execution contexts in the kernel and make timer-driven preemption visible and understandable.
Learning goal
Understand what a task context actually contains.
Category
foundations
Components touched
Builds on
Unlocked by this phase
Why this phase matters
Introduce multiple concurrent execution contexts in the kernel and make timer-driven preemption visible and understandable.
How it works in m3OS
Phase 4 introduces cooperative multi-tasking to the kernel. Each task is an independent unit of execution with its own stack. The kernel switches between tasks by saving and restoring a small register frame — the context — without involving the CPU’s hardware task-switching mechanism (which is too heavy-weight for a microkernel).
How it builds on earlier phases
This phase builds on Interrupts and turns that foundation into Tasking.
Implementation outline
- Define the task model and saved register layout.
- Create kernel stacks for spawned tasks.
- Implement the assembly context switch with a narrow ABI.
- Add a ready queue and a simple scheduler.
- Trigger rescheduling from timer interrupts.
Task progress snapshot
18 of 18 tracked tasks are complete.
Documentation targets
- Documentation deliverables have not been listed yet.
Deferred follow-on work
- priorities and deadline scheduling
- sleep queues and timers beyond the basic tick
- SMP-aware run queues
Source materials
Important code
Code spotlight cards
Code spotlight
Define the kernel task structure and task states
Define the kernel task structure and task states. Why it matters: Every schedulable unit needs a descriptor holding its saved registers, state, stack pointer, and metadata. Focus on `Task` and `TaskState` in `kernel/src/task/mod.rs` while you trace the snippet.
pub struct Task {
/// Unique task identifier — not yet read outside this module.
#[allow(dead_code)]
pub id: TaskId,
/// Human-readable name — not yet read outside this module.
#[allow(dead_code)]
pub name: &'static str,
pub state: TaskState,
/// RSP saved by `switch_context` when this task is not running.
pub saved_rsp: u64,
/// Owns the allocated kernel stack — dropped when the `Task` is dropped.
_stack: Box<[u8]>,
} Code spotlight
Add a round-robin scheduler and ready queue
Add a round-robin scheduler and ready queue. Why it matters: The scheduler determines which task runs next and drives all cooperative and preemptive multitasking. Focus on `Scheduler` and `Ready` in `kernel/src/task/scheduler.rs` while you trace the snippet.
struct Scheduler {
tasks: Vec<Task>,
/// Index of the last non-idle task that was dispatched (for round-robin).
last_run: usize,
/// Index of the task currently holding the CPU, or `None` while the
/// scheduler loop itself is running.
current: Option<usize>,
/// Index of the dedicated idle task in `tasks`, registered via
/// [`spawn_idle`]. The idle task is excluded from the normal round-robin
/// rotation and is selected only when no non-idle task is `Ready`.
idle_task: Option<usize>,
} Code spotlight
Trigger scheduling from the timer interrupt
Trigger scheduling from the timer interrupt. Why it matters: Timer-driven preemption ensures no single task monopolizes the CPU, which is the foundation of a multitasking OS. Focus on `timer_handler` and `signal_reschedule` in `kernel/src/arch/x86_64/interrupts.rs` while you trace the snippet.
extern "x86-interrupt" fn timer_handler(_stack_frame: InterruptStackFrame) {
TICK_COUNT.fetch_add(1, Ordering::Relaxed);
crate::task::signal_reschedule();
unsafe {
PICS.lock()
.notify_end_of_interrupt(InterruptIndex::Timer as u8);
}
} Key files
How real OSes differ
- Mature schedulers handle priorities, CPU affinity, latency targets, and many blocking sources. A toy round-robin scheduler is intentionally unsophisticated because it makes context switching and task states easy to inspect and reason about.
Success criteria
- At least two kernel tasks can run and interleave output.
- Register state survives task switches.
- The idle task runs when there is no ready work.
- Scheduler behavior is simple enough to explain from logs.
Related phases