The RIOT scheduler. More...
The RIOT scheduler.
RIOT features a tickless, preemptive, priority based scheduler. Context switches can occur either preemptively (i.e. on interrupts), voluntarily, or when a blocking operation (like msg_receive()
) is executed. Being tickless means it does not have a timer that fires periodically in order to emulate concurrent execution by switching threads continuously.
Every thread is given a priority on creation. The priority values are "order" or "nice" values, i.e. a higher value means a lower priority.
Given threads with priorities A=6, B=1, and C=3, B has the highest priority.
A higher priority means that the scheduler will run this thread whenever it becomes runnable instead of a thread with a lower priority. In case of equal priorities, the threads are scheduled in a semi-cooperative fashion. That means that unless an interrupt happens, threads with the same priority will only switch due to voluntary or implicit context switches.
When an interrupt occurs, e.g. because a timer fired or a network packet was received, the active context is saved and an interrupt service routine (ISR) that handles the interrupt is executed in another context. When the ISR is finished, the sched_context_switch_request
flag can be checked. In case it is set, the sched_run()
function is called to determine the next active thread. (In the special case that the ISR knows that it can not enable a thread switch, this check can of course be omitted.) If the flag is not set, the original context is being restored and the thread resumes immediately.
There are two function calls that can lead to a voluntary context switch: thread_yield()
and thread_sleep()
. While the latter disables (think blocks) the thread until it is woken (think unblocked) again via thread_wakeup()
, the former only leads to a context switch in case there is another runnable thread with at least the same priority.
Some functions that unblock another thread, e.g. msg_send()
or mutex_unlock()
, can cause a thread switch, if the target had a higher priority.
Modules | |
Scheduler for native | |
The RIOT scheduler for the native platform. | |
Files | |
file | sched.h |
Scheduler API definition. | |
Macros | |
#define | MAXTHREADS 32 |
The maximum number of threads to be scheduled. | |
#define | KERNEL_PID_UNDEF 0 |
Canonical identifier for an invalid PID. | |
#define | KERNEL_PID_FIRST (KERNEL_PID_UNDEF + 1) |
The first valid PID (inclusive). | |
#define | KERNEL_PID_LAST (KERNEL_PID_FIRST + MAXTHREADS - 1) |
The last valid PID (inclusive). | |
#define | PRIkernel_pid PRIi16 |
Macro for printing formatter. | |
#define | SCHED_PRIO_LEVELS 16 |
The number of thread priority levels. | |
Typedefs | |
typedef int16_t | kernel_pid_t |
Unique process identifier. | |
typedef struct _thread | thread_t |
forward declaration for thread_t, defined in thread.h | |
typedef void(* | sched_callback_t) (kernel_pid_t active, kernel_pid_t next) |
Scheduler run callback. More... | |
Functions | |
static int | pid_is_valid (kernel_pid_t pid) |
Determine if the given pid is valid. More... | |
thread_t * | sched_run (void) |
Triggers the scheduler to schedule the next thread. More... | |
void | sched_set_status (thread_t *process, thread_status_t status) |
Set the status of the specified process. More... | |
void | sched_switch (uint16_t other_prio) |
Yield if appropriate. More... | |
NORETURN void | cpu_switch_context_exit (void) |
Call context switching at thread exit. | |
NORETURN void | sched_task_exit (void) |
Removes thread from scheduler and set status to STATUS_STOPPED. | |
void | sched_arch_idle (void) |
Set CPU to idle mode (CPU dependent) More... | |
void | sched_register_cb (sched_callback_t callback) |
Register a callback that will be called on every scheduler run. More... | |
Variables | |
volatile unsigned int | sched_context_switch_request |
Flag indicating whether a context switch is necessary after handling an interrupt. More... | |
volatile thread_t * | sched_threads [KERNEL_PID_LAST+1] |
Thread table. | |
volatile int | sched_num_threads |
Number of running (non-terminated) threads. | |
clist_node_t | sched_runqueues [SCHED_PRIO_LEVELS] |
List of runqueues per priority level. | |
Thread states supported by RIOT | |
Keep in sync with OpenOCD src/rtos/riot.c | |
enum | thread_status_t { STATUS_STOPPED, STATUS_ZOMBIE, STATUS_SLEEPING, STATUS_MUTEX_BLOCKED, STATUS_RECEIVE_BLOCKED, STATUS_SEND_BLOCKED, STATUS_REPLY_BLOCKED, STATUS_FLAG_BLOCKED_ANY, STATUS_FLAG_BLOCKED_ALL, STATUS_MBOX_BLOCKED, STATUS_COND_BLOCKED, STATUS_RUNNING, STATUS_PENDING, STATUS_NUMOF } |
Helpers to work with thread states | |
#define | STATUS_ON_RUNQUEUE STATUS_RUNNING |
to check if on run queue: st >= STATUS_ON_RUNQUEUE | |
#define | STATUS_NOT_FOUND ((thread_status_t)-1) |
Describes an illegal thread status. | |
typedef void(* sched_callback_t) (kernel_pid_t active, kernel_pid_t next) |
enum thread_status_t |
|
inlinestatic |
void sched_arch_idle | ( | void | ) |
Set CPU to idle mode (CPU dependent)
Only used when there's no idle thread.
This function will be called by the scheduler when there's no runnable thread. It will be called from ISR context, and must allow other ISR handlers to be run. E.g., on Cortex-M, the PendSV priority is temporarily lowered (set to higher value) in order to enable other exceptions to be run.
This function should also invoke setting a low power mode, e.g., by calling 'pm_set_lowest()'.
void sched_register_cb | ( | sched_callback_t | callback | ) |
Register a callback that will be called on every scheduler run.
[in] | callback | The callback functions that will be called |
thread_t* sched_run | ( | void | ) |
Triggers the scheduler to schedule the next thread.
void sched_set_status | ( | thread_t * | process, |
thread_status_t | status | ||
) |
Set the status of the specified process.
[in] | process | Pointer to the thread control block of the targeted process |
[in] | status | The new status of this thread |
void sched_switch | ( | uint16_t | other_prio | ) |
Yield if appropriate.
Either yield if other_prio is higher than the current priority, or if the current thread is not on the runqueue.
Depending on whether the current execution is in an ISR (irq_is_in()), thread_yield_higher() is called or sched_context_switch_request is set, respectively.
[in] | other_prio | The priority of the target thread. |
volatile unsigned int sched_context_switch_request |
Flag indicating whether a context switch is necessary after handling an interrupt.
Supposed to be set in an ISR.