pub trait Scheduler<C: Chip> {
// Required methods
fn next(&self) -> SchedulingDecision;
fn result(
&self,
result: StoppedExecutingReason,
execution_time_us: Option<u32>,
);
// Provided methods
unsafe fn execute_kernel_work(&self, chip: &C) { ... }
unsafe fn do_kernel_work_now(&self, chip: &C) -> bool { ... }
unsafe fn continue_process(&self, _id: ProcessId, chip: &C) -> bool { ... }
}
Expand description
Trait which any scheduler must implement.
Required Methods§
sourcefn next(&self) -> SchedulingDecision
fn next(&self) -> SchedulingDecision
Decide which process to run next.
The scheduler must decide whether to run a process, and if so, which one. If the scheduler chooses not to run a process, it can request that the chip enter sleep mode.
If the scheduler selects a process to run it must provide its ProcessId
and an optional timeslice length in microseconds to provide to that
process. If the timeslice is None
, the process will be run
cooperatively (i.e. without preemption). Otherwise the process will run
with a timeslice set to the specified length.
sourcefn result(&self, result: StoppedExecutingReason, execution_time_us: Option<u32>)
fn result(&self, result: StoppedExecutingReason, execution_time_us: Option<u32>)
Inform the scheduler of why the last process stopped executing, and how
long it executed for. Notably, execution_time_us
will be None
if the the scheduler requested this process be run cooperatively.
Provided Methods§
sourceunsafe fn execute_kernel_work(&self, chip: &C)
unsafe fn execute_kernel_work(&self, chip: &C)
Tell the scheduler to execute kernel work such as interrupt bottom halves and dynamic deferred calls. Most schedulers will use this default implementation, but schedulers which at times wish to defer interrupt handling will reimplement it.
Providing this interface allows schedulers to fully manage how the main kernel loop executes. For example, a more advanced scheduler that attempts to help processes meet their deadlines may need to defer bottom half interrupt handling or to selectively service certain interrupts. Or, a power aware scheduler may want to selectively choose what work to complete at any time to meet power requirements.
Custom implementations of this function must be very careful, however, as this function is called in the core kernel loop.
sourceunsafe fn do_kernel_work_now(&self, chip: &C) -> bool
unsafe fn do_kernel_work_now(&self, chip: &C) -> bool
Ask the scheduler whether to take a break from executing userspace processes to handle kernel tasks. Most schedulers will use this default implementation, which always prioritizes kernel work, but schedulers that wish to defer interrupt handling may reimplement it.
sourceunsafe fn continue_process(&self, _id: ProcessId, chip: &C) -> bool
unsafe fn continue_process(&self, _id: ProcessId, chip: &C) -> bool
Ask the scheduler whether to continue trying to execute a process.
Once a process is scheduled the kernel will try to execute it until it has no more work to do or exhausts its timeslice. The kernel will call this function before every loop to check with the scheduler if it wants to continue trying to execute this process.
Most schedulers will use this default implementation, which causes the
do_process()
loop to return if there are interrupts or deferred calls
that need to be serviced. However, schedulers which wish to defer
interrupt handling may change this, or priority schedulers which wish to
check if the execution of the current process has caused a higher
priority process to become ready (such as in the case of IPC). If this
returns false
, then do_process
will exit with a KernelPreemption
.
id
is the identifier of the currently active process.