preempt.c File Reference
Simple preemptive multitasking scheduler. More...
#include "cfg/cfg_proc.h"#include "proc_p.h"#include "proc.h"#include <kern/irq.h>#include <kern/monitor.h>#include <cpu/frame.h>#include <cpu/irq.h>#include <cfg/log.h>#include <cfg/module.h>#include <cfg/depend.h>Go to the source code of this file.
Functions | |
| void | preempt_yield (void) |
| Define function prototypes exported outside. | |
| int | preempt_needPreempt (void) |
| Check if we need to schedule another task. | |
| void | preempt_preempt (void) |
| Preempt the current task. | |
| void | preempt_switch (void) |
| Give the control of the CPU to another process. | |
| void | preempt_wakeup (Process *proc) |
| Immediately wakeup a process, dispatching it to the CPU. | |
| static void | preempt_schedule (void) |
| Call the scheduler and eventually replace the current running process. | |
Detailed Description
Simple preemptive multitasking scheduler.
Preemption is explicitly regulated at the exit of each interrupt service routine (ISR). Each task obtains a time quantum as soon as it is scheduled on the CPU and its quantum is decremented at each clock tick. The frequency of the timer determines the system tick granularity and CONFIG_KERN_QUANTUM the time sharing interval.
When the quantum expires the handler proc_needPreempt() checks if the preemption is enabled and in this case preempt_schedule() is called, that possibly replaces the current running thread with a different one.
The preemption can be disabled or enabled via proc_forbid() and proc_permit() primitives. This is implemented using a global atomic counter. When the counter is greater than 0 the task cannot be preempted; only when the counter reaches 0 the task can be preempted again.
Preemption-disabled sections may be nested. The preemption will be re-enabled when the outermost preemption-disabled section completes.
The voluntary preemption still happens via proc_switch() or proc_yield(). The first one assumes the current process has been already added to a private wait queue (e.g., on a semaphore or a signal), while the second one takes care of adding the process into the ready queue.
Context switch is done by CPU-dependent support routines. In case of a voluntary preemption the context switch routine must take care of saving/restoring only the callee-save registers (the voluntary-preemption is actually a function call). The kernel-preemption always happens inside a signal/interrupt context and it must take care of saving all registers. For this, in the entry point of each ISR the caller-save registers must be saved. In the ISR exit point, if the context switch must happen, we switch to user-context and call the same voluntary context switch routine that take care of saving/restoring also the callee-save registers. On resume from the switch, the interrupt exit point moves back to interrupt-context, resumes the caller-save registers (saved in the ISR entry point) and return from the interrupt-context.
- Note:
- Thread priority (if enabled by CONFIG_KERN_PRI) defines the order in the
proc_ready_listand the capability to deschedule a running process. A low-priority thread can't preempt a high-priority thread.
A high-priority process can preempt a low-priority process immediately (it will be descheduled and replaced in the interrupt exit point). Processes running at the same priority can be descheduled when they expire the time quantum.
- Note:
- Sleeping while preemption is disabled fallbacks to a busy-wait sleep. Voluntary preemption when preemption is disabled raises a kernel bug.
Definition in file preempt.c.
Function Documentation
| void preempt_switch | ( | void | ) |
Give the control of the CPU to another process.
- Note:
- Assume the current process has been already added to a wait queue.
- Warning:
- This should be considered an internal kernel function, even if it is allowed, usage from application code is strongly discouraged.
