From 68d1f4b5625f401c5c0782f34007225b13b31077 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Mon, 12 Sep 2016 11:35:26 -0400 Subject: [PATCH] unified: Add timeslice support Change-Id: I5b6c1ef5c015d1ddaea21b1c5447336b1b04db39 Signed-off-by: Peter Mitsis --- arch/arm/core/exc_exit.S | 8 ++++---- arch/x86/core/intstub.S | 13 ++++++++----- kernel/unified/Kconfig | 32 ++++++++++++++++++++++++++++++++ kernel/unified/sched.c | 16 ++++++++++++++++ kernel/unified/sys_clock.c | 28 ++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 9 deletions(-) diff --git a/arch/arm/core/exc_exit.S b/arch/arm/core/exc_exit.S index 8643a6b81e2..1ac0aa6980a 100644 --- a/arch/arm/core/exc_exit.S +++ b/arch/arm/core/exc_exit.S @@ -38,7 +38,7 @@ GTEXT(_IntExit) GDATA(_nanokernel) #ifdef CONFIG_KERNEL_V2 -GTEXT(__must_switch_threads) +GTEXT(_is_next_thread_current) #endif #if CONFIG_GDB_INFO @@ -113,11 +113,11 @@ SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, _ExcExit) bxgt lr push {lr} - blx __must_switch_threads + blx _is_next_thread_current pop {lr} cmp r0, #0 - it eq - bxeq lr + it ne + bxne lr #else diff --git a/arch/x86/core/intstub.S b/arch/x86/core/intstub.S index 3801b106cc6..aa9b2705963 100644 --- a/arch/x86/core/intstub.S +++ b/arch/x86/core/intstub.S @@ -46,7 +46,7 @@ GTEXT(_Swap) #ifdef CONFIG_KERNEL_V2 - GTEXT(__must_switch_threads) + GTEXT(_is_next_thread_current) #endif #ifdef CONFIG_SYS_POWER_MANAGEMENT @@ -357,9 +357,9 @@ _IntExitWithCli: /* reschedule only if the scheduler says that we must do so */ - call __must_switch_threads - cmpl $0, %eax - je noReschedule + call _is_next_thread_current + testl %eax, %eax + jnz noReschedule #else /* * Determine whether the execution of the ISR requires a context @@ -386,7 +386,10 @@ _IntExitWithCli: #if defined(CONFIG_FP_SHARING) || defined(CONFIG_GDB_INFO) #ifdef CONFIG_KERNEL_V2 - /* reload _nanokernel.current: __must_switch_threads may clobber it */ + /* + * Reload _nanokernel.current as _is_next_thread_current() + * might have clobbered it. + */ movl _nanokernel + __tNANO_current_OFFSET, %edx #endif orl $INT_ACTIVE, __tTCS_flags_OFFSET(%edx) diff --git a/kernel/unified/Kconfig b/kernel/unified/Kconfig index f8704b2b2b4..5db434e1380 100644 --- a/kernel/unified/Kconfig +++ b/kernel/unified/Kconfig @@ -245,4 +245,36 @@ config ATOMIC_OPERATIONS_C set, or haven't been implemented yet during bring-up, and also the compiler does not have support for the atomic __sync_* builtins. +menu "Timer API Options" + +config TIMESLICING + bool "Thread time slicing" + default y + depends on SYS_CLOCK_EXISTS && (NUM_PREEMPT_PRIORITIES != 0) + help + This option enables time slicing between preemptible threads of + equal priority. + +config TIMESLICE_SIZE + int "Time slice size (in ms)" + default 0 + range 0 2147483647 + depends on TIMESLICING + help + This option specifies the maximum amount of time a thread can execute + before other threads of equal priority are given an opportunity to run. + A time slice size of zero means "no limit" (i.e. an infinitely large + time slice). + +config TIMESLICE_PRIORITY + int "Time slicing thread priority ceiling" + default 0 + range 0 NUM_PREEMPT_PRIORITIES + depends on TIMESLICING + help + This option specifies the thread priority level at which time slicing + takes effect; threads having a higher priority than this ceiling are + not subject to time slicing. + +endmenu endmenu diff --git a/kernel/unified/sched.c b/kernel/unified/sched.c index 70ee798b617..fc2924b1a98 100644 --- a/kernel/unified/sched.c +++ b/kernel/unified/sched.c @@ -285,3 +285,19 @@ void _dump_ready_q(void) sys_dlist_peek_head(&_ready_q.q[prio])); } } + +#ifdef CONFIG_TIMESLICING +extern int32_t _time_slice_duration; /* Measured in ms */ +extern int32_t _time_slice_elapsed; /* Measured in ms */ +extern int _time_slice_prio_ceiling; + +void k_sched_time_slice_set(int32_t duration_in_ms, int prio) +{ + __ASSERT(duration_in_ms >= 0, ""); + __ASSERT((prio >= 0) && (prio < CONFIG_NUM_PREEMPT_PRIORITIES), ""); + + _time_slice_duration = duration_in_ms; + _time_slice_elapsed = 0; + _time_slice_prio_ceiling = prio; +} +#endif /* CONFIG_TIMESLICING */ diff --git a/kernel/unified/sys_clock.c b/kernel/unified/sys_clock.c index f4f0b0acf04..aedfb7129bd 100644 --- a/kernel/unified/sys_clock.c +++ b/kernel/unified/sys_clock.c @@ -169,6 +169,31 @@ static inline void handle_expired_timeouts(int32_t ticks) #define handle_expired_timeouts(ticks) do { } while ((0)) #endif +#ifdef CONFIG_TIMESLICING +int32_t _time_slice_elapsed; +int32_t _time_slice_duration = CONFIG_TIMESLICE_SIZE; +int _time_slice_prio_ceiling = CONFIG_TIMESLICE_PRIORITY; + +static void handle_time_slicing(int32_t ticks) +{ + if (_time_slice_duration == 0) { + return; + } + + if (_is_prio_higher(_current->prio, _time_slice_prio_ceiling)) { + return; + } + + _time_slice_elapsed += _ticks_to_ms(ticks); + if (_time_slice_elapsed >= _time_slice_duration) { + _time_slice_elapsed = 0; + _remove_thread_from_ready_q(_current); + _add_thread_to_ready_q(_current); + } +} +#else +#define handle_time_slicing(ticks) do { } while (0) +#endif /** * * @brief Announce a tick to the nanokernel @@ -188,6 +213,9 @@ void _nano_sys_clock_tick_announce(int32_t ticks) key = irq_lock(); _sys_clock_tick_count += ticks; handle_expired_timeouts(ticks); + + handle_time_slicing(ticks); + irq_unlock(key); }