/* * Copyright (C) 2014 Freie Universität Berlin * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. */ /** * @defgroup core_sched Scheduler * @ingroup core * @brief The RIOT scheduler * @details * * 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. * * ## Priorities: * * 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. * * ### Example: * * 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. * * ## Interrupts: * * 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. * * ## Voluntary Context Switches: * * 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. * * ## Implicit Context Switches: * * 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. * * * @{ * * @file * @brief Scheduler API definition * * @author Kaspar Schleiser */ #ifndef SCHEDULER_H #define SCHEDULER_H #include #include "kernel_defines.h" #include "bitarithm.h" #include "kernel_types.h" #include "native_sched.h" #include "clist.h" #ifdef __cplusplus extern "C" { #endif /** * @brief forward declaration for thread_t, defined in thread.h */ typedef struct _thread thread_t; /** * @def SCHED_PRIO_LEVELS * @brief The number of thread priority levels */ #ifndef SCHED_PRIO_LEVELS #define SCHED_PRIO_LEVELS 16 #endif /** * @brief Triggers the scheduler to schedule the next thread * @returns 1 if sched_active_thread/sched_active_pid was changed, 0 otherwise. */ int sched_run(void); /** * @brief Set the status of the specified process * * @param[in] process Pointer to the thread control block of the * targeted process * @param[in] status The new status of this thread */ void sched_set_status(thread_t *process, unsigned int status); /** * @brief Yield if approriate. * * @details 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 @ref sched_context_switch_request is set, * respectively. * * @param[in] other_prio The priority of the target thread. */ void sched_switch(uint16_t other_prio); /** * @brief Call context switching at thread exit */ NORETURN void cpu_switch_context_exit(void); /** * Flag indicating whether a context switch is necessary after handling an * interrupt. Supposed to be set in an ISR. */ extern volatile unsigned int sched_context_switch_request; /** * Thread table */ extern volatile thread_t *sched_threads[KERNEL_PID_LAST + 1]; /** * Currently active thread */ extern volatile thread_t *sched_active_thread; /** * Number of running (non-terminated) threads */ extern volatile int sched_num_threads; /** * Process ID of active thread */ extern volatile kernel_pid_t sched_active_pid; /** * List of runqueues per priority level */ extern clist_node_t sched_runqueues[SCHED_PRIO_LEVELS]; /** * @brief Removes thread from scheduler and set status to #STATUS_STOPPED */ NORETURN void sched_task_exit(void); #ifdef MODULE_SCHEDSTATISTICS /** * Scheduler statistics */ typedef struct { unsigned int laststart; /**< Time stamp of the last time this thread was scheduled to run */ unsigned int schedules; /**< How often the thread was scheduled to run */ unsigned long runtime_ticks; /**< The total runtime of this thread in ticks */ } schedstat; /** * Thread statistics table */ extern schedstat sched_pidlist[KERNEL_PID_LAST + 1]; /** * @brief Register a callback that will be called on every scheduler run * * @param[in] callback The callback functions the will be called */ void sched_register_cb(void (*callback)(uint32_t, uint32_t)); #endif /* MODULE_SCHEDSTATISTICS */ #ifdef __cplusplus } #endif #endif /* SCHEDULER_H */ /** @} */