Round Robin Scheduler
Relevant source files
Purpose and Scope
This document covers the Round Robin scheduler implementation (RRScheduler) in the scheduler crate, which provides preemptive scheduling based on time quantum allocation. The Round Robin scheduler ensures fair CPU time distribution among tasks by rotating execution using fixed time slices.
For information about the unified scheduler interface, see Core Architecture. For comparisons with other scheduling algorithms, see Scheduler Comparison.
Architecture Overview
The Round Robin scheduler consists of two main components: the RRTask wrapper that adds time slice tracking to tasks, and the RRScheduler that implements the preemptive scheduling logic using a FIFO queue with time quantum management.
Round Robin Scheduler Components
flowchart TD
subgraph subGraph1["Round Robin Scheduler System"]
RRScheduler["RRScheduler<T, MAX_TIME_SLICE>"]
VecDeque["VecDeque<Arc<RRTask>>"]
RRTask["RRTask<T, MAX_TIME_SLICE>"]
AtomicIsize["AtomicIsize time_slice"]
subgraph subGraph0["BaseScheduler Interface"]
AddTask["add_task()"]
RemoveTask["remove_task()"]
PickNext["pick_next_task()"]
PutPrev["put_prev_task()"]
TaskTick["task_tick()"]
SetPriority["set_priority()"]
end
end
RRScheduler --> AddTask
RRScheduler --> PickNext
RRScheduler --> PutPrev
RRScheduler --> RemoveTask
RRScheduler --> SetPriority
RRScheduler --> TaskTick
RRScheduler --> VecDeque
RRTask --> AtomicIsize
VecDeque --> RRTask
Sources: src/round_robin.rs(L1 - L114)
RRTask Wrapper
The RRTask wrapper extends any task type T with time slice management capabilities. It maintains an atomic counter that tracks the remaining time slice for preemption decisions.
RRTask Structure and Methods
| Method | Purpose | Atomicity |
|---|---|---|
| new(inner: T) | Creates wrapper with initial time slice set toMAX_TIME_SLICE | - |
| time_slice() | Returns current time slice value | Acquireordering |
| reset_time_slice() | Resets time slice toMAX_TIME_SLICE | Releaseordering |
| inner() | Provides access to wrapped task | - |
The time slice counter is implemented as an AtomicIsize to ensure thread-safe access during concurrent scheduler operations.
Sources: src/round_robin.rs(L7 - L44)
RRScheduler Implementation
The RRScheduler implements the BaseScheduler trait using a VecDeque as the ready queue. This provides O(1) insertion and removal at both ends, but O(n) removal from arbitrary positions.
Scheduler Data Structure and Core Methods
flowchart TD
subgraph subGraph2["RRScheduler Operations"]
ReadyQueue["ready_queue: VecDeque"]
subgraph subGraph1["Time Management"]
TaskTick["task_tick()"]
TimeSlice["time_slice counter"]
end
subgraph subGraph0["Task Management"]
AddTask["add_task()"]
PickNext["pick_next_task()"]
PutPrev["put_prev_task()"]
RemoveTask["remove_task()"]
end
end
AddTask --> ReadyQueue
PutPrev --> ReadyQueue
ReadyQueue --> PickNext
RemoveTask --> ReadyQueue
TaskTick --> TimeSlice
TimeSlice --> PutPrev
Key Implementation Details
- Ready Queue: Uses
VecDeque<Arc<RRTask<T, MAX_TIME_SLICE>>>for task storage - Task Addition: New tasks are added to the back of the queue via
push_back() - Task Selection: Next task is selected from the front via
pop_front() - Task Removal: Requires O(n) search using
Arc::ptr_eq()for pointer comparison - Priority Support: Not supported -
set_priority()always returnsfalse
Sources: src/round_robin.rs(L58 - L113)
Time Slice Management
The Round Robin scheduler's core feature is its time quantum management system. Each task receives a fixed time slice that determines how long it can execute before being preempted.
Time Slice Lifecycle
flowchart TD
subgraph subGraph0["put_prev_task() Logic"]
PutPrev["put_prev_task(prev, preempt)"]
CheckPreempt["preempt && time_slice > 0?"]
QueueFront["push_front()"]
ResetAndBack["reset_time_slice() + push_back()"]
end
TaskCreated["Task Created"]
InitTimeSlice["time_slice = MAX_TIME_SLICE"]
Running["Task Running"]
TimerTick["Timer Tick Occurs"]
DecrementSlice["time_slice--"]
CheckSlice["time_slice <= 0?"]
Preempted["Task Preempted"]
ResetSlice["reset_time_slice()"]
BackToQueue["Added to Queue Back"]
BackToQueue --> QueueFront
BackToQueue --> ResetAndBack
CheckPreempt --> QueueFront
CheckPreempt --> ResetAndBack
CheckSlice --> Preempted
CheckSlice --> Running
DecrementSlice --> CheckSlice
InitTimeSlice --> Running
Preempted --> ResetSlice
PutPrev --> CheckPreempt
ResetSlice --> BackToQueue
Running --> TimerTick
TaskCreated --> InitTimeSlice
TimerTick --> DecrementSlice
Timer Tick Implementation
The task_tick() method implements the time slice decrement logic:
// From src/round_robin.rs:105-108
fn task_tick(&mut self, current: &Self::SchedItem) -> bool {
let old_slice = current.time_slice.fetch_sub(1, Ordering::Release);
old_slice <= 1
}
This atomic operation decrements the time slice and returns true when the task should be preempted (when the slice reaches zero).
Sources: src/round_robin.rs(L105 - L108)
Scheduling Behavior
The Round Robin scheduler exhibits specific behavior patterns that distinguish it from other scheduling algorithms in the crate.
Task State Transitions
| Scheduler Method | Action | Queue Position | Time Slice Action |
|---|---|---|---|
| add_task() | Add new task | Back of queue | Set toMAX_TIME_SLICE |
| pick_next_task() | Select task | Remove from front | No change |
| put_prev_task()(preempted, slice > 0) | Voluntary yield | Front of queue | No change |
| put_prev_task()(preempted, slice = 0) | Time expired | Back of queue | Reset toMAX_TIME_SLICE |
| put_prev_task()(not preempted) | Cooperative yield | Back of queue | Reset toMAX_TIME_SLICE |
Preemption Logic
The scheduler distinguishes between voluntary and involuntary preemption in its put_prev_task() implementation:
- Voluntary Preemption: Task still has time slice remaining and yielded voluntarily - placed at front of queue
- Time Expiration: Task's time slice reached zero - time slice reset and task placed at back of queue
- Cooperative Yield: Task not preempted (blocking I/O, etc.) - time slice reset and task placed at back of queue
Sources: src/round_robin.rs(L96 - L103)
Performance Characteristics
Computational Complexity
| Operation | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| add_task() | O(1) | O(1) | VecDeque::push_back() |
| pick_next_task() | O(1) | O(1) | VecDeque::pop_front() |
| remove_task() | O(n) | O(1) | Linear search withArc::ptr_eq() |
| put_prev_task() | O(1) | O(1) | VecDeque::push_front()orpush_back() |
| task_tick() | O(1) | O(1) | Atomic decrement operation |
Design Tradeoffs
- Fairness: Provides time-based fairness through fixed time slices
- Preemption: Supports timer-based preemption unlike FIFO scheduler
- Simplicity: Simpler than CFS but more complex than FIFO
- Performance: O(n) task removal limits scalability for workloads with frequent task removal
- Priority: No priority support - all tasks receive equal time allocation
Sources: src/round_robin.rs(L84 - L90) src/round_robin.rs(L110 - L112)