From 8c3aad1c255bd9d3139ca11982ac98d7dae59757 Mon Sep 17 00:00:00 2001 From: Karl Fessel Date: Thu, 15 Apr 2021 14:57:49 +0200 Subject: [PATCH] sys/sched_round_robin: Add a round robin scheduler module --- sys/Makefile.dep | 9 ++ sys/auto_init/auto_init.c | 5 + sys/include/sched_round_robin.h | 87 ++++++++++++++++ sys/sched_round_robin/Kconfig | 19 ++++ sys/sched_round_robin/Makefile | 1 + sys/sched_round_robin/sched_round_robin.c | 118 ++++++++++++++++++++++ 6 files changed, 239 insertions(+) create mode 100644 sys/include/sched_round_robin.h create mode 100644 sys/sched_round_robin/Kconfig create mode 100644 sys/sched_round_robin/Makefile create mode 100644 sys/sched_round_robin/sched_round_robin.c diff --git a/sys/Makefile.dep b/sys/Makefile.dep index 50112e29f3..b5852f5811 100644 --- a/sys/Makefile.dep +++ b/sys/Makefile.dep @@ -356,6 +356,15 @@ ifneq (,$(filter schedstatistics,$(USEMODULE))) USEMODULE += sched_cb endif +ifneq (,$(filter sched_round_robin,$(USEMODULE))) +# this depends on either ztimer_usec or ztimer_msec if neither is used +# prior to this msec is preferred + ifeq (,$(filter ztimer_usec,$(USEMODULE))$(filter ztimer_msec,$(USEMODULE))) + USEMODULE += ztimer_msec + endif + USEMODULE += sched_runq_callback +endif + ifneq (,$(filter saul_reg,$(USEMODULE))) USEMODULE += saul endif diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index d28eccde1f..062c9a3fe8 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -49,6 +49,11 @@ void auto_init(void) extern void init_schedstatistics(void); init_schedstatistics(); } + if (IS_USED(MODULE_SCHED_ROUND_ROBIN)) { + LOG_DEBUG("Auto init sched_round_robin.\n"); + extern void sched_round_robin_init(void); + sched_round_robin_init(); + } if (IS_USED(MODULE_DUMMY_THREAD)) { extern void dummy_thread_create(void); dummy_thread_create(); diff --git a/sys/include/sched_round_robin.h b/sys/include/sched_round_robin.h new file mode 100644 index 0000000000..4e0e2381e7 --- /dev/null +++ b/sys/include/sched_round_robin.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2020 TUBA Freiberg + * + * 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 sched_round_robin Round Robin Scheduler + * @ingroup sys + * @brief This module module provides round robin scheduling for all + * runable threads within each not masked priority. + * Priority 0 is masked by default. + * This implementation tries to find a balance between + * low resources (static memory: a timer and an uint8), + * fairness in terms of CPU time share and simplicity. + * But it does round robin the runqueue when the timer ticks + * even if the thread just got the CPU. + * + * This module might be used if threads are not divisible + * into priorities and cooperation can not be ensured. + * + * @{ + * + * @file + * @brief Round Robin Scheduler + * + * @author Karl Fessel + * + */ +#ifndef SCHED_ROUND_ROBIN_H +#define SCHED_ROUND_ROBIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(SCHED_RR_TIMEOUT) || defined(DOXYGEN) +/** + * @brief Time between round robin calls in Units of SCHED_RR_TIMERBASE + * + * @details Defaults to 10ms + */ +#if MODULE_ZTIMER_MSEC +#define SCHED_RR_TIMEOUT 10 +#else +#define SCHED_RR_TIMEOUT 10000 +#endif +#endif + +#if !defined(SCHED_RR_TIMERBASE) || defined(DOXYGEN) +/** + * @brief ztimer to use for the round robin scheduler + * + * @details Defaults to ZTIMER_MSEC if available else it uses ZTIMER_USEC + */ +#if MODULE_ZTIMER_MSEC +#define SCHED_RR_TIMERBASE ZTIMER_MSEC +#else +#define SCHED_RR_TIMERBASE ZTIMER_USEC +#endif +#endif + +#if !defined(SCHED_RR_MASK) || defined(DOXYGEN) +/** + * @brief Masks off priorities that should not be scheduled default: 0 is masked + * + * @details Priority 0 (highest) should always be masked. + * Threads with that priority may not be programmed + * with the possibility of being scheduled in mind. + * Parts of this scheduler assume 0 current_rr_priority is uninitialised. + */ +#define SCHED_RR_MASK (1 << 0) +#endif + +/** + * @brief Initialises the Round Robin Scheduler + */ +void sched_round_robin_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* SCHED_ROUND_ROBIN_H */ +/** @} */ diff --git a/sys/sched_round_robin/Kconfig b/sys/sched_round_robin/Kconfig new file mode 100644 index 0000000000..dd109caa2e --- /dev/null +++ b/sys/sched_round_robin/Kconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2021 TUBA Freiberg +# +# 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. +# + +config MODULE_SCHED_ROUND_ROBIN + bool "round robin scheduling support" + depends on MODULE_ZTIMER_MSEC || MODULE_ZTIMER_USEC + depends on TEST_KCONFIG + select MODULE_SCHED_RUNQUEUE_API + +if MODULE_SCHED_ROUND_ROBIN +config SCHED_RR_TIMEOUT + int "timeout for round robin scheduling" + default 10000 + +endif diff --git a/sys/sched_round_robin/Makefile b/sys/sched_round_robin/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/sys/sched_round_robin/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/sched_round_robin/sched_round_robin.c b/sys/sched_round_robin/sched_round_robin.c new file mode 100644 index 0000000000..4cfed38592 --- /dev/null +++ b/sys/sched_round_robin/sched_round_robin.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2021 TUBA Freiberg + * + * 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. + */ +/** + * @ingroup sys + * @{ + * + * @file + * @brief Round Robin Scheduler implementation + * + * @author Karl Fessel + * + * @} + */ + +#include "sched.h" +#include "thread.h" +#include "ztimer.h" +#include "sched_round_robin.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +static void _sched_round_robin_cb(void *d); + +static ztimer_t _rr_timer = { .callback = _sched_round_robin_cb }; + +/* + * Assuming simple reads from and writes to a byte to be atomic on every board + * Value 0 is assumed to show this system is uninitialised. + * The timer will not be started for prio = 0; + */ +static uint8_t _current_rr_priority = 0; + +void sched_runq_callback(uint8_t prio); + +void _sched_round_robin_cb(void *d) +{ + (void)d; + /* + * reorder current Round Robin priority + * (put the current thread at the end of the run queue of its priority) + * and setup the scheduler to schedule when returning from the IRQ + */ + uint8_t prio = _current_rr_priority; + if (prio != 0xff) { + DEBUG_PUTS("Round_Robin"); + sched_runq_advance(prio); + _current_rr_priority = 0xff; + } + thread_t *active_thread = thread_get_active(); + if (active_thread) { + uint8_t active_priority = active_thread->priority; + if (active_priority == prio) { + thread_yield_higher(); + /* thread change will call the runqueue_change_cb */ + } + else { + sched_runq_callback(active_priority); + } + } +} + +static inline void _sched_round_robin_remove(void) +{ + _current_rr_priority = 0xff; + ztimer_remove(SCHED_RR_TIMERBASE, &_rr_timer); +} + +static inline void _sched_round_robin_set(uint8_t prio) +{ + if (prio == 0) { + return; + } + _current_rr_priority = prio; + ztimer_set(SCHED_RR_TIMERBASE, &_rr_timer, SCHED_RR_TIMEOUT); +} + +void sched_runq_callback(uint8_t prio) +{ + if (SCHED_RR_MASK & (1 << prio) || prio == 0) { + return; + } + + if (_current_rr_priority == prio) { + if (sched_runq_is_empty(prio)) { + _sched_round_robin_remove(); + thread_t *active_thread = thread_get_active(); + if (active_thread) { + prio = active_thread->priority; + } + else { + return; + } + } + } + + if (_current_rr_priority == 0xff && + !(SCHED_RR_MASK & (1 << prio)) && + sched_runq_more_than_one(prio)) { + _sched_round_robin_set(prio); + } +} + +void sched_round_robin_init(void) +{ + /* init _current_rr_priority */ + _current_rr_priority = 0xff; + /* check if applicable to active priority */ + thread_t *active_thread = thread_get_active(); + if (active_thread) { + sched_runq_callback(active_thread->priority); + } +}