From 6ac33f2b9f51588d68c7511c90596034b879c363 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 7 Oct 2015 13:53:24 -0400 Subject: [PATCH] kernel: Introduce sys_thread_busy_wait() API Provides a way for a fiber or task to busy wait for a specified period of time. This is useful in situations where a delay needs to be performed without switching execution to another context, such as: 1) It would take longer to switch to another context and then switch back again than to simply busy wait. 2) A delay is required by the kernel's main task (i.e. the nanokernel's background task or the microkernel's idle task). This task is not allowed to voluntarily relinquish the CPU because this would leave the kernel with nothing to execute in its place. Change-Id: Icbe28613014f659e9528893ae58f7b8008c18a61 Original-work-by: Jeff Blais Further-adapted-by: Benjamin Walsh Signed-off-by: Allan Stephens --- include/nanokernel.h | 17 ++++++++++++++++ kernel/nanokernel/nano_context.c | 33 ++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/include/nanokernel.h b/include/nanokernel.h index 3813caa1846..c3b753cb262 100644 --- a/include/nanokernel.h +++ b/include/nanokernel.h @@ -125,6 +125,23 @@ extern nano_context_type_t sys_execution_context_type_get(void); extern int _is_thread_essential(nano_thread_id_t pCtx); +/** + * + * @brief Busy wait the currently executing thread + * + * This routine causes the current task or fiber to execute a "do nothing" + * loop for a specified period of time. + * + * @warning This routine utilizes the system clock, so it must not be invoked + * until the system clock is fully operational or while interrupts + * are locked. + * + * @param usec_to_wait Number of microseconds to busy wait. + * + * @return N/A + */ +extern void sys_thread_busy_wait(uint32_t usec_to_wait); + /** * @brief Nanokernel Fibers * @defgroup nanokernel_fiber Nanokernel Fibers diff --git a/kernel/nanokernel/nano_context.c b/kernel/nanokernel/nano_context.c index 88f1a09db83..e623b8d4f5b 100644 --- a/kernel/nanokernel/nano_context.c +++ b/kernel/nanokernel/nano_context.c @@ -41,6 +41,8 @@ tasks or fibers. #include #include +#include +#include nano_thread_id_t sys_thread_self_get(void) @@ -105,6 +107,37 @@ int _is_thread_essential(struct tcs *pCtx /* pointer to thread */ return ((pCtx == NULL) ? _nanokernel.current : pCtx)->flags & ESSENTIAL; } +/* + * Don't build sys_thread_busy_wait() for ARM, since intrinsics libraries in + * current Zephyr SDK use non-Thumb code that isn't supported on Cortex-M CPUs. + * For the time being any ARM-based application that attempts to use this API + * will get a link error (which is preferable to a mysterious exception). + */ + +#ifndef CONFIG_ARM + +void sys_thread_busy_wait(uint32_t usec_to_wait) +{ + /* use 64-bit math to prevent overflow when multiplying */ + uint32_t cycles_to_wait = (uint32_t)( + (uint64_t)usec_to_wait * + (uint64_t)sys_clock_hw_cycles_per_sec / + (uint64_t)USEC_PER_SEC + ); + uint32_t start_cycles = _sys_clock_cycle_get(); + + for (;;) { + uint32_t current_cycles = _sys_clock_cycle_get(); + + /* this handles the rollover on an unsigned 32-bit value */ + if ((current_cycles - start_cycles) >= cycles_to_wait) { + break; + } + } +} + +#endif /* CONFIG_ARM */ + #ifdef CONFIG_THREAD_CUSTOM_DATA /**