1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/core/include/sched.h
Marian Buschsieweke 4c3e92f183
core: Made thread state an enum
- Introduced enum type `thread_state_t` to replace preprocessor macros
- Moved thread states to `sched.h` for two reasons:
  a) Because of the interdependencies of `sched.h` and `thread.h` keeping it in
     `thread.h` would result in ugly code.
  b) Theses thread states are defined from the schedulers point of view, so it
     actually makes senses to have it defined there
2019-02-13 13:31:52 +01:00

236 lines
7.2 KiB
C

/*
* 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 <kaspar@schleiser.de>
*/
#ifndef SCHED_H
#define SCHED_H
#include <stddef.h>
#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;
/**
* @name Thread states supported by RIOT
* @{
*/
typedef enum {
STATUS_STOPPED, /**< has terminated */
STATUS_SLEEPING, /**< sleeping */
STATUS_MUTEX_BLOCKED, /**< waiting for a locked mutex */
STATUS_RECEIVE_BLOCKED, /**< waiting for a message */
STATUS_SEND_BLOCKED, /**< waiting for message to be delivered */
STATUS_REPLY_BLOCKED, /**< waiting for a message response */
STATUS_FLAG_BLOCKED_ANY, /**< waiting for any flag from flag_mask */
STATUS_FLAG_BLOCKED_ALL, /**< waiting for all flags in flag_mask */
STATUS_MBOX_BLOCKED, /**< waiting for get/put on mbox */
STATUS_COND_BLOCKED, /**< waiting for a condition variable */
STATUS_RUNNING, /**< currently running */
STATUS_PENDING, /**< waiting to be scheduled to run */
STATUS_NUMOF /**< number of supported thread states */
} thread_state_t;
/** @} */
/**
* @name 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_state_t)-1) /**< Describes an illegal thread status */
/** @} */
/**
* @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, thread_state_t 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 {
uint32_t laststart; /**< Time stamp of the last time this thread was
scheduled to run */
unsigned int schedules; /**< How often the thread was scheduled to run */
uint64_t runtime_ticks; /**< The total runtime of this thread in ticks */
} schedstat_t;
/**
* Thread statistics table
*/
extern schedstat_t 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 /* SCHED_H */
/** @} */