From 6477b762d156f0291f0ab333a1221fe58d2387b2 Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Mon, 27 Aug 2018 12:23:50 +0300 Subject: [PATCH 1/3] Style clean-up of Thread-related files --- rtos/Kernel.cpp | 5 +- rtos/TARGET_CORTEX/mbed_rtx_handlers.c | 106 ++++++++++++------------- rtos/Thread.cpp | 93 ++++++++++++++-------- rtos/Thread.h | 103 +++++++++++++----------- 4 files changed, 170 insertions(+), 137 deletions(-) diff --git a/rtos/Kernel.cpp b/rtos/Kernel.cpp index 2562556cff..c4b1534edf 100644 --- a/rtos/Kernel.cpp +++ b/rtos/Kernel.cpp @@ -26,7 +26,8 @@ namespace rtos { -uint64_t Kernel::get_ms_count() { +uint64_t Kernel::get_ms_count() +{ // CMSIS-RTOS 2.1.0 and 2.1.1 differ in the time type. We assume // our header at least matches the implementation, so we don't try looking // at the run-time version report. (There's no compile-time version report) @@ -36,7 +37,7 @@ uint64_t Kernel::get_ms_count() { // 2.1.x who knows? We assume could go back to uint64_t if (sizeof osKernelGetTickCount() == sizeof(uint64_t)) { return osKernelGetTickCount(); - } else /* assume 32-bit */ { + } else { /* assume 32-bit */ // Based on suggestion in CMSIS-RTOS 2.1.1 docs, but with reentrancy // protection for the tick memory. We use critical section rather than a // mutex, as hopefully this method can be callable from interrupt later - diff --git a/rtos/TARGET_CORTEX/mbed_rtx_handlers.c b/rtos/TARGET_CORTEX/mbed_rtx_handlers.c index 223874e4e5..682684d8fa 100644 --- a/rtos/TARGET_CORTEX/mbed_rtx_handlers.c +++ b/rtos/TARGET_CORTEX/mbed_rtx_handlers.c @@ -32,43 +32,43 @@ extern void rtos_idle_loop(void); extern void thread_terminate_hook(osThreadId_t id); -__NO_RETURN void osRtxIdleThread (void *argument) +__NO_RETURN void osRtxIdleThread(void *argument) { for (;;) { - rtos_idle_loop(); + rtos_idle_loop(); } } -__NO_RETURN uint32_t osRtxErrorNotify (uint32_t code, void *object_id) +__NO_RETURN uint32_t osRtxErrorNotify(uint32_t code, void *object_id) { osThreadId_t tid = osThreadGetId(); switch (code) { - case osRtxErrorStackUnderflow: - // Stack underflow detected for thread (thread_id=object_id) - // Note: "overflow" is printed instead of "underflow" due to end user familiarity with overflow errors - MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_STACK_OVERFLOW), "CMSIS-RTOS error: Stack overflow", code); - break; - case osRtxErrorISRQueueOverflow: - // ISR Queue overflow detected when inserting object (object_id) - MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_ISR_QUEUE_OVERFLOW), "CMSIS-RTOS error: ISR Queue overflow", code); - break; - case osRtxErrorTimerQueueOverflow: - // User Timer Callback Queue overflow detected for timer (timer_id=object_id) - MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_TIMER_QUEUE_OVERFLOW), "CMSIS-RTOS error: User Timer Callback Queue overflow", code); - break; - case osRtxErrorClibSpace: - // Standard C/C++ library libspace not available: increase OS_THREAD_LIBSPACE_NUM - MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_CLIB_SPACE_UNAVAILABLE), "CMSIS-RTOS error: STD C/C++ library libspace not available", code); - break; - case osRtxErrorClibMutex: - // Standard C/C++ library mutex initialization failed - MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_CLIB_MUTEX_INIT_FAILURE), "CMSIS-RTOS error: STD C/C++ library mutex initialization failed", code); - break; - default: - //Unknown error flagged from kernel - MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_UNKNOWN), "CMSIS-RTOS error: Unknown", code); - break; + case osRtxErrorStackUnderflow: + // Stack underflow detected for thread (thread_id=object_id) + // Note: "overflow" is printed instead of "underflow" due to end user familiarity with overflow errors + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_STACK_OVERFLOW), "CMSIS-RTOS error: Stack overflow", code); + break; + case osRtxErrorISRQueueOverflow: + // ISR Queue overflow detected when inserting object (object_id) + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_ISR_QUEUE_OVERFLOW), "CMSIS-RTOS error: ISR Queue overflow", code); + break; + case osRtxErrorTimerQueueOverflow: + // User Timer Callback Queue overflow detected for timer (timer_id=object_id) + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_TIMER_QUEUE_OVERFLOW), "CMSIS-RTOS error: User Timer Callback Queue overflow", code); + break; + case osRtxErrorClibSpace: + // Standard C/C++ library libspace not available: increase OS_THREAD_LIBSPACE_NUM + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_CLIB_SPACE_UNAVAILABLE), "CMSIS-RTOS error: STD C/C++ library libspace not available", code); + break; + case osRtxErrorClibMutex: + // Standard C/C++ library mutex initialization failed + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_CLIB_MUTEX_INIT_FAILURE), "CMSIS-RTOS error: STD C/C++ library mutex initialization failed", code); + break; + default: + //Unknown error flagged from kernel + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_UNKNOWN), "CMSIS-RTOS error: Unknown", code); + break; } /* That shouldn't be reached */ @@ -77,52 +77,52 @@ __NO_RETURN uint32_t osRtxErrorNotify (uint32_t code, void *object_id) #if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED -static const char* error_msg(int32_t status) +static const char *error_msg(int32_t status) { switch (status) { - case osError: - return "Unspecified RTOS error"; - case osErrorTimeout: - return "Operation not completed within the timeout period"; - case osErrorResource: - return "Resource not available"; - case osErrorParameter: - return "Parameter error"; - case osErrorNoMemory: - return "System is out of memory"; - case osErrorISR: - return "Not allowed in ISR context"; - default: - return "Unknown"; + case osError: + return "Unspecified RTOS error"; + case osErrorTimeout: + return "Operation not completed within the timeout period"; + case osErrorResource: + return "Resource not available"; + case osErrorParameter: + return "Parameter error"; + case osErrorNoMemory: + return "System is out of memory"; + case osErrorISR: + return "Not allowed in ISR context"; + default: + return "Unknown"; } } -void EvrRtxKernelError (int32_t status) +void EvrRtxKernelError(int32_t status) { MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_EVENT), error_msg(status), status); } -void EvrRtxThreadError (osThreadId_t thread_id, int32_t status) +void EvrRtxThreadError(osThreadId_t thread_id, int32_t status) { MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_THREAD_EVENT), error_msg(status), thread_id); } -void EvrRtxTimerError (osTimerId_t timer_id, int32_t status) +void EvrRtxTimerError(osTimerId_t timer_id, int32_t status) { MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_TIMER_EVENT), error_msg(status), timer_id); } -void EvrRtxEventFlagsError (osEventFlagsId_t ef_id, int32_t status) +void EvrRtxEventFlagsError(osEventFlagsId_t ef_id, int32_t status) { MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_EVENT_FLAGS_EVENT), error_msg(status), ef_id); } -void EvrRtxMutexError (osMutexId_t mutex_id, int32_t status) +void EvrRtxMutexError(osMutexId_t mutex_id, int32_t status) { MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_MUTEX_EVENT), error_msg(status), mutex_id); } -void EvrRtxSemaphoreError (osSemaphoreId_t semaphore_id, int32_t status) +void EvrRtxSemaphoreError(osSemaphoreId_t semaphore_id, int32_t status) { // Ignore semaphore overflow, the count will saturate with a returned error if (status == osRtxErrorSemaphoreCountLimit) { @@ -132,12 +132,12 @@ void EvrRtxSemaphoreError (osSemaphoreId_t semaphore_id, int32_t status) MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_SEMAPHORE_EVENT), error_msg(status), semaphore_id); } -void EvrRtxMemoryPoolError (osMemoryPoolId_t mp_id, int32_t status) +void EvrRtxMemoryPoolError(osMemoryPoolId_t mp_id, int32_t status) { MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_MEMORY_POOL_EVENT), error_msg(status), mp_id); } -void EvrRtxMessageQueueError (osMessageQueueId_t mq_id, int32_t status) +void EvrRtxMessageQueueError(osMessageQueueId_t mq_id, int32_t status) { MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT), error_msg(status), mq_id); } @@ -145,7 +145,7 @@ void EvrRtxMessageQueueError (osMessageQueueId_t mq_id, int32_t status) #endif // RTX hook which gets called when a thread terminates, using the event function to call hook -void EvrRtxThreadExit (void) +void EvrRtxThreadExit(void) { osThreadId_t thread_id = osThreadGetId(); thread_terminate_hook(thread_id); @@ -154,7 +154,7 @@ void EvrRtxThreadExit (void) #endif } -void EvrRtxThreadTerminate (osThreadId_t thread_id) +void EvrRtxThreadTerminate(osThreadId_t thread_id) { thread_terminate_hook(thread_id); #if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_TERMINATE_DISABLE) && defined(RTE_Compiler_EventRecorder)) diff --git a/rtos/Thread.cpp b/rtos/Thread.cpp index 3fa93043d6..172fe751d6 100644 --- a/rtos/Thread.cpp +++ b/rtos/Thread.cpp @@ -48,7 +48,8 @@ namespace rtos { #endif void Thread::constructor(uint32_t tz_module, osPriority priority, - uint32_t stack_size, unsigned char *stack_mem, const char *name) { + uint32_t stack_size, unsigned char *stack_mem, const char *name) +{ const uintptr_t unaligned_mem = reinterpret_cast(stack_mem); const uintptr_t aligned_mem = ALIGN_UP(unaligned_mem, 8); @@ -63,17 +64,19 @@ void Thread::constructor(uint32_t tz_module, osPriority priority, _attr.priority = priority; _attr.stack_size = aligned_size; _attr.name = name ? name : "application_unnamed_thread"; - _attr.stack_mem = reinterpret_cast(aligned_mem); + _attr.stack_mem = reinterpret_cast(aligned_mem); _attr.tz_module = tz_module; } void Thread::constructor(osPriority priority, - uint32_t stack_size, unsigned char *stack_mem, const char *name) { + uint32_t stack_size, unsigned char *stack_mem, const char *name) +{ constructor(MBED_TZ_DEFAULT_ACCESS, priority, stack_size, stack_mem, name); } void Thread::constructor(Callback task, - osPriority priority, uint32_t stack_size, unsigned char *stack_mem, const char *name) { + osPriority priority, uint32_t stack_size, unsigned char *stack_mem, const char *name) +{ constructor(MBED_TZ_DEFAULT_ACCESS, priority, stack_size, stack_mem, name); switch (start(task)) { @@ -90,7 +93,8 @@ void Thread::constructor(Callback task, } } -osStatus Thread::start(Callback task) { +osStatus Thread::start(Callback task) +{ _mutex.lock(); if ((_tid != 0) || _finished) { @@ -99,7 +103,7 @@ osStatus Thread::start(Callback task) { } if (_attr.stack_mem == NULL) { - _attr.stack_mem = new uint32_t[_attr.stack_size/sizeof(uint32_t)]; + _attr.stack_mem = new uint32_t[_attr.stack_size / sizeof(uint32_t)]; MBED_ASSERT(_attr.stack_mem != NULL); } @@ -115,8 +119,8 @@ osStatus Thread::start(Callback task) { _tid = osThreadNew(Thread::_thunk, this, &_attr); if (_tid == NULL) { if (_dynamic_stack) { - delete[] (uint32_t *)(_attr.stack_mem); - _attr.stack_mem = (uint32_t*)NULL; + delete[](uint32_t *)(_attr.stack_mem); + _attr.stack_mem = (uint32_t *)NULL; } _mutex.unlock(); _join_sem.release(); @@ -127,7 +131,8 @@ osStatus Thread::start(Callback task) { return osOK; } -osStatus Thread::terminate() { +osStatus Thread::terminate() +{ osStatus_t ret = osOK; _mutex.lock(); @@ -149,7 +154,8 @@ osStatus Thread::terminate() { return ret; } -osStatus Thread::join() { +osStatus Thread::join() +{ int32_t ret = _join_sem.wait(); if (ret < 0) { return osError; @@ -167,7 +173,8 @@ osStatus Thread::join() { return osOK; } -osStatus Thread::set_priority(osPriority priority) { +osStatus Thread::set_priority(osPriority priority) +{ osStatus_t ret; _mutex.lock(); @@ -177,7 +184,8 @@ osStatus Thread::set_priority(osPriority priority) { return ret; } -osPriority Thread::get_priority() { +osPriority Thread::get_priority() +{ osPriority_t ret; _mutex.lock(); @@ -187,11 +195,13 @@ osPriority Thread::get_priority() { return ret; } -int32_t Thread::signal_set(int32_t flags) { +int32_t Thread::signal_set(int32_t flags) +{ return osThreadFlagsSet(_tid, flags); } -Thread::State Thread::get_state() { +Thread::State Thread::get_state() +{ uint8_t state = osThreadTerminated; _mutex.lock(); @@ -208,7 +218,7 @@ Thread::State Thread::get_state() { State user_state; - switch(state) { + switch (state) { case osThreadInactive: user_state = Inactive; break; @@ -256,7 +266,8 @@ Thread::State Thread::get_state() { return user_state; } -uint32_t Thread::stack_size() { +uint32_t Thread::stack_size() +{ uint32_t size = 0; _mutex.lock(); @@ -268,7 +279,8 @@ uint32_t Thread::stack_size() { return size; } -uint32_t Thread::free_stack() { +uint32_t Thread::free_stack() +{ uint32_t size = 0; _mutex.lock(); @@ -283,7 +295,8 @@ uint32_t Thread::free_stack() { return size; } -uint32_t Thread::used_stack() { +uint32_t Thread::used_stack() +{ uint32_t size = 0; _mutex.lock(); @@ -298,7 +311,8 @@ uint32_t Thread::used_stack() { return size; } -uint32_t Thread::max_stack() { +uint32_t Thread::max_stack() +{ uint32_t size = 0; _mutex.lock(); @@ -306,8 +320,9 @@ uint32_t Thread::max_stack() { #if defined(MBED_OS_BACKEND_RTX5) mbed_rtos_storage_thread_t *thread = (mbed_rtos_storage_thread_t *)_tid; uint32_t high_mark = 0; - while ((((uint32_t *)(thread->stack_mem))[high_mark] == osRtxStackMagicWord) || (((uint32_t *)(thread->stack_mem))[high_mark] == osRtxStackFillPattern)) + while ((((uint32_t *)(thread->stack_mem))[high_mark] == osRtxStackMagicWord) || (((uint32_t *)(thread->stack_mem))[high_mark] == osRtxStackFillPattern)) { high_mark++; + } size = thread->stack_size - (high_mark * sizeof(uint32_t)); #else size = osThreadGetStackSize(_tid) - osThreadGetStackSpace(_tid); @@ -318,15 +333,18 @@ uint32_t Thread::max_stack() { return size; } -const char *Thread::get_name() { +const char *Thread::get_name() +{ return _attr.name; } -int32_t Thread::signal_clr(int32_t flags) { +int32_t Thread::signal_clr(int32_t flags) +{ return osThreadFlagsClear(flags); } -osEvent Thread::signal_wait(int32_t signals, uint32_t millisec) { +osEvent Thread::signal_wait(int32_t signals, uint32_t millisec) +{ uint32_t res; osEvent evt; uint32_t options = osFlagsWaitAll; @@ -359,11 +377,13 @@ osEvent Thread::signal_wait(int32_t signals, uint32_t millisec) { return evt; } -osStatus Thread::wait(uint32_t millisec) { +osStatus Thread::wait(uint32_t millisec) +{ return osDelay(millisec); } -osStatus Thread::wait_until(uint64_t millisec) { +osStatus Thread::wait_until(uint64_t millisec) +{ // CMSIS-RTOS 2.1.0 and 2.1.1 differ in the time type, which we determine // by looking at the return type of osKernelGetTickCount. We assume // our header at least matches the implementation, so we don't try looking @@ -392,34 +412,39 @@ osStatus Thread::wait_until(uint64_t millisec) { } } -osStatus Thread::yield() { +osStatus Thread::yield() +{ return osThreadYield(); } -osThreadId Thread::gettid() { +osThreadId Thread::gettid() +{ return osThreadGetId(); } -void Thread::attach_idle_hook(void (*fptr)(void)) { +void Thread::attach_idle_hook(void (*fptr)(void)) +{ rtos_attach_idle_hook(fptr); } -void Thread::attach_terminate_hook(void (*fptr)(osThreadId_t id)) { +void Thread::attach_terminate_hook(void (*fptr)(osThreadId_t id)) +{ terminate_hook = fptr; } -Thread::~Thread() { +Thread::~Thread() +{ // terminate is thread safe terminate(); if (_dynamic_stack) { - delete[] (uint32_t*)(_attr.stack_mem); - _attr.stack_mem = (uint32_t*)NULL; + delete[](uint32_t *)(_attr.stack_mem); + _attr.stack_mem = (uint32_t *)NULL; } } -void Thread::_thunk(void * thread_ptr) +void Thread::_thunk(void *thread_ptr) { - Thread *t = (Thread*)thread_ptr; + Thread *t = (Thread *)thread_ptr; t->_task(); t->_mutex.lock(); t->_tid = (osThreadId)NULL; diff --git a/rtos/Thread.h b/rtos/Thread.h index 43d9775c1d..fb67d4dfc7 100644 --- a/rtos/Thread.h +++ b/rtos/Thread.h @@ -94,9 +94,10 @@ public: @note You cannot call this function from ISR context. */ - Thread(osPriority priority=osPriorityNormal, - uint32_t stack_size=OS_STACK_SIZE, - unsigned char *stack_mem=NULL, const char *name=NULL) { + Thread(osPriority priority = osPriorityNormal, + uint32_t stack_size = OS_STACK_SIZE, + unsigned char *stack_mem = NULL, const char *name = NULL) + { constructor(priority, stack_size, stack_mem, name); } @@ -113,9 +114,10 @@ public: @note You cannot call this function from ISR context. */ - Thread(uint32_t tz_module, osPriority priority=osPriorityNormal, - uint32_t stack_size=OS_STACK_SIZE, - unsigned char *stack_mem=NULL, const char *name=NULL) { + Thread(uint32_t tz_module, osPriority priority = osPriorityNormal, + uint32_t stack_size = OS_STACK_SIZE, + unsigned char *stack_mem = NULL, const char *name = NULL) + { constructor(tz_module, priority, stack_size, stack_mem, name); } @@ -140,12 +142,13 @@ public: @note You cannot call this function from ISR context. */ MBED_DEPRECATED_SINCE("mbed-os-5.1", - "Thread-spawning constructors hide errors. " - "Replaced by thread.start(task).") + "Thread-spawning constructors hide errors. " + "Replaced by thread.start(task).") Thread(mbed::Callback task, - osPriority priority=osPriorityNormal, - uint32_t stack_size=OS_STACK_SIZE, - unsigned char *stack_mem=NULL) { + osPriority priority = osPriorityNormal, + uint32_t stack_size = OS_STACK_SIZE, + unsigned char *stack_mem = NULL) + { constructor(task, priority, stack_size, stack_mem); } @@ -171,12 +174,13 @@ public: */ template MBED_DEPRECATED_SINCE("mbed-os-5.1", - "Thread-spawning constructors hide errors. " - "Replaced by thread.start(callback(task, argument)).") + "Thread-spawning constructors hide errors. " + "Replaced by thread.start(callback(task, argument)).") Thread(T *argument, void (T::*task)(), - osPriority priority=osPriorityNormal, - uint32_t stack_size=OS_STACK_SIZE, - unsigned char *stack_mem=NULL) { + osPriority priority = osPriorityNormal, + uint32_t stack_size = OS_STACK_SIZE, + unsigned char *stack_mem = NULL) + { constructor(mbed::callback(task, argument), priority, stack_size, stack_mem); } @@ -203,12 +207,13 @@ public: */ template MBED_DEPRECATED_SINCE("mbed-os-5.1", - "Thread-spawning constructors hide errors. " - "Replaced by thread.start(callback(task, argument)).") + "Thread-spawning constructors hide errors. " + "Replaced by thread.start(callback(task, argument)).") Thread(T *argument, void (*task)(T *), - osPriority priority=osPriorityNormal, - uint32_t stack_size=OS_STACK_SIZE, - unsigned char *stack_mem=NULL) { + osPriority priority = osPriorityNormal, + uint32_t stack_size = OS_STACK_SIZE, + unsigned char *stack_mem = NULL) + { constructor(mbed::callback(task, argument), priority, stack_size, stack_mem); } @@ -235,12 +240,13 @@ public: @note You cannot call this function from ISR context. */ MBED_DEPRECATED_SINCE("mbed-os-5.1", - "Thread-spawning constructors hide errors. " - "Replaced by thread.start(callback(task, argument)).") - Thread(void (*task)(void const *argument), void *argument=NULL, - osPriority priority=osPriorityNormal, - uint32_t stack_size=OS_STACK_SIZE, - unsigned char *stack_mem=NULL) { + "Thread-spawning constructors hide errors. " + "Replaced by thread.start(callback(task, argument)).") + Thread(void (*task)(void const *argument), void *argument = NULL, + osPriority priority = osPriorityNormal, + uint32_t stack_size = OS_STACK_SIZE, + unsigned char *stack_mem = NULL) + { constructor(mbed::callback((void (*)(void *))task, argument), priority, stack_size, stack_mem); } @@ -265,9 +271,10 @@ public: */ template MBED_DEPRECATED_SINCE("mbed-os-5.1", - "The start function does not support cv-qualifiers. " - "Replaced by thread.start(callback(obj, method)).") - osStatus start(T *obj, M method) { + "The start function does not support cv-qualifiers. " + "Replaced by thread.start(callback(obj, method)).") + osStatus start(T *obj, M method) + { return start(mbed::callback(obj, method)); } @@ -338,28 +345,28 @@ public: @note You cannot call this function from ISR context. */ State get_state(); - + /** Get the total stack memory size for this Thread @return the total stack memory size in bytes @note You cannot call this function from ISR context. */ uint32_t stack_size(); - + /** Get the currently unused stack memory for this Thread @return the currently unused stack memory in bytes @note You cannot call this function from ISR context. */ uint32_t free_stack(); - + /** Get the currently used stack memory for this Thread @return the currently used stack memory in bytes @note You cannot call this function from ISR context. */ uint32_t used_stack(); - + /** Get the maximum stack memory usage to date for this Thread @return the maximum stack memory usage to date in bytes @@ -389,7 +396,7 @@ public: @note You cannot call this function from ISR context. */ - static osEvent signal_wait(int32_t signals, uint32_t millisec=osWaitForever); + static osEvent signal_wait(int32_t signals, uint32_t millisec = osWaitForever); /** Wait for a specified time period in milliseconds Being tick-based, the delay will be up to the specified time - eg for @@ -455,21 +462,21 @@ public: private: // Required to share definitions without // delegated constructors - void constructor(osPriority priority=osPriorityNormal, - uint32_t stack_size=OS_STACK_SIZE, - unsigned char *stack_mem=NULL, - const char *name=NULL); + void constructor(osPriority priority = osPriorityNormal, + uint32_t stack_size = OS_STACK_SIZE, + unsigned char *stack_mem = NULL, + const char *name = NULL); void constructor(mbed::Callback task, - osPriority priority=osPriorityNormal, - uint32_t stack_size=OS_STACK_SIZE, - unsigned char *stack_mem=NULL, - const char *name=NULL); + osPriority priority = osPriorityNormal, + uint32_t stack_size = OS_STACK_SIZE, + unsigned char *stack_mem = NULL, + const char *name = NULL); void constructor(uint32_t tz_module, - osPriority priority=osPriorityNormal, - uint32_t stack_size=OS_STACK_SIZE, - unsigned char *stack_mem=NULL, - const char *name=NULL); - static void _thunk(void * thread_ptr); + osPriority priority = osPriorityNormal, + uint32_t stack_size = OS_STACK_SIZE, + unsigned char *stack_mem = NULL, + const char *name = NULL); + static void _thunk(void *thread_ptr); mbed::Callback _task; osThreadId_t _tid; From 1330eeecd01ae40b33be05ee2f354897e98263ea Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Tue, 3 Apr 2018 10:38:53 +0300 Subject: [PATCH 2/3] Add ThisThread --- TESTS/mbedmicro-rtos-mbed/threads/main.cpp | 195 +++++++++++---------- rtos/Kernel.cpp | 12 ++ rtos/Kernel.h | 15 ++ rtos/TARGET_CORTEX/mbed_rtx_handlers.c | 16 +- rtos/ThisThread.cpp | 141 +++++++++++++++ rtos/ThisThread.h | 188 ++++++++++++++++++++ rtos/Thread.cpp | 55 ++---- rtos/Thread.h | 55 +++++- rtos/rtos.h | 1 + rtos/rtos_handlers.h | 53 ++++++ 10 files changed, 597 insertions(+), 134 deletions(-) create mode 100644 rtos/ThisThread.cpp create mode 100644 rtos/ThisThread.h create mode 100644 rtos/rtos_handlers.h diff --git a/TESTS/mbedmicro-rtos-mbed/threads/main.cpp b/TESTS/mbedmicro-rtos-mbed/threads/main.cpp index 22d7c6f830..c5effb0e54 100644 --- a/TESTS/mbedmicro-rtos-mbed/threads/main.cpp +++ b/TESTS/mbedmicro-rtos-mbed/threads/main.cpp @@ -59,13 +59,13 @@ void increment(counter_t *counter) void increment_with_yield(counter_t *counter) { - Thread::yield(); + ThisThread::yield(); (*counter)++; } void increment_with_wait(counter_t *counter) { - Thread::wait(100); + ThisThread::sleep_for(100); (*counter)++; } @@ -246,118 +246,128 @@ void test_self_terminate() delete thread; } -void signal_wait() +void flags_wait() { - osEvent evt = Thread::signal_wait(0x1); - TEST_ASSERT_EQUAL(osEventSignal, evt.status); - TEST_ASSERT_EQUAL(0x1, evt.value.signals); + uint32_t flags = ThisThread::flags_wait_all(0x1); + TEST_ASSERT_EQUAL(0x1, flags); } -void signal_wait_tout() +void flags_wait_tout() { - osEvent evt = Thread::signal_wait(0x2, 50); - TEST_ASSERT_EQUAL(osEventTimeout, evt.status); + uint32_t flags = ThisThread::flags_wait_all_for(0x2, 50); + TEST_ASSERT_EQUAL(0x1, flags); } -void signal_wait_multibit() +void flags_wait_multibit() { - osEvent evt = Thread::signal_wait(0x1 | 0x2, 50); - TEST_ASSERT_EQUAL(osEventSignal, evt.status); - TEST_ASSERT_EQUAL(0x3, evt.value.signals); + uint32_t flags = ThisThread::flags_wait_all(0x1 | 0x2); + TEST_ASSERT_EQUAL(0x3, flags); } -void signal_wait_multibit_tout() +void flags_wait_multibit_any() { - osEvent evt = Thread::signal_wait(0x1 | 0x2, 50); - TEST_ASSERT_EQUAL(osEventTimeout, evt.status); + uint32_t flags = ThisThread::flags_wait_any(0x1 | 0x2); + TEST_ASSERT_NOT_EQUAL(0x0, flags); +} + +void flags_wait_multibit_tout() +{ + uint32_t flags = ThisThread::flags_wait_all_for(0x1 | 0x2, 50); + TEST_ASSERT_NOT_EQUAL(0x3, flags); } /** - Testing thread signal: wait + Testing thread flags: wait Given two threads (A & B) are started - when thread A executes @a signal_wait(0x1) - and thread B execute @a signal_set(0x1) + when thread A executes @a flags_wait_all(0x1) + and thread B execute @a flags_set(0x1) then thread A exits the wait and continues execution - Testing thread signal: timeout + Testing thread flags: timeout Given two threads (A & B) are started - when thread A executes @a signal_wait(0x1 | 0x2, 50) with a timeout of 50ms - and thread B execute @a signal_set(0x2) - then thread A keeps waiting for correct signal until it timeouts + when thread A executes @a flags_wait_all_for(0x1 | 0x2, 50) with a timeout of 50ms + and thread B execute @a flags_set(0x2) + then thread A keeps waiting for correct flags until it timeouts - Testing thread signal: multi-bit + Testing thread flags: multi-bit Given two threads (A & B) are started - when thread A executes @a signal_wait(0x1 | 0x2) - and thread B execute @a signal_set(0x1 | 0x2) + when thread A executes @a flags_wait_all(0x1 | 0x2) + and thread B execute @a flags_set(0x1 | 0x2) then thread A exits the wait and continues execution - Testing thread signal: multi-bit timeout + Testing thread flags: multi-bit any Given two threads (A & B) are started - when thread A executes @a signal_wait(0x1, 50) with a timeout of 50ms - and thread B execute @a signal_set(0x2) - then thread A keeps waiting for correct signal until it timeouts + when thread A executes @a flags_wait_any(0x1 | 0x2) + and thread B execute @a flags_set(0x1) + then thread A exits the wait and continues execution + + Testing thread flags: multi-bit timeout + Given two threads (A & B) are started + when thread A executes @a flags_wait_all_for(0x1, 50) with a timeout of 50ms + and thread B execute @a flags_set(0x2) + then thread A keeps waiting for correct flags until it timeouts */ template -void test_thread_signal() +void test_thread_flags_set() { Thread t_wait(osPriorityNormal, THREAD_STACK_SIZE); t_wait.start(callback(F)); - Thread::yield(); + ThisThread::yield(); Thread::State state = t_wait.get_state(); TEST_ASSERT_EQUAL(Thread::WaitingThreadFlag, state); - int32_t res = t_wait.signal_set(S); + int32_t res = t_wait.flags_set(S); t_wait.join(); } -void signal_clr() +void flags_clear() { - Thread::yield(); + ThisThread::yield(); - int32_t sig = Thread::signal_clr(0x1); + int32_t sig = ThisThread::flags_clear(0x1); TEST_ASSERT_EQUAL(0x1, sig); - /* Signal cleared we should get timeout */ - osEvent evt = Thread::signal_wait(0x1, 0); - TEST_ASSERT_EQUAL(osOK, evt.status); + /* Flags cleared we should get timeout */ + uint32_t flags = ThisThread::flags_wait_all_for(0x1, 0); + TEST_ASSERT_EQUAL(0, flags); } -/** Testing thread signals: signal clear +/** Testing thread flags: flags clear Given two threads (A & B) are started - when thread A executes @a signal_set(0x1) - and thread B execute @a signal_clr(0x1) - and thread B execute @a signal_wait(0x1, 0) - then thread B @a signal_wait status should be osOK indicating a timeout + when thread A executes @a flags_set(0x1) + and thread B execute @a flags_clear(0x1) + and thread B execute @a flags_wait_all_for(0x1, 0) + then thread B @a flags_wait_all_for return should be 0 indicating no flags set */ -void test_thread_signal_clr() +void test_thread_flags_clear() { Thread t_wait(osPriorityNormal, THREAD_STACK_SIZE); - t_wait.start(callback(signal_clr)); + t_wait.start(callback(flags_clear)); - int32_t res = t_wait.signal_set(0x1); + int32_t res = t_wait.flags_set(0x1); TEST_ASSERT_EQUAL(0x1, res); t_wait.join(); } -void thread_wait_signal() +void thread_wait_flags() { - Thread::signal_wait(0x1); + ThisThread::flags_wait_all(0x1); } void stack_info() { - Thread::signal_wait(0x1); + ThisThread::flags_wait_all(0x1); - thread_wait_signal(); + thread_wait_flags(); - Thread::signal_wait(0x1); + ThisThread::flags_wait_all(0x1); } /** Testing thread stack info @@ -377,26 +387,26 @@ void test_thread_stack_info() Thread t(osPriorityNormal, THREAD_STACK_SIZE); t.start(callback(stack_info)); - Thread::yield(); + ThisThread::yield(); TEST_ASSERT_EQUAL(THREAD_STACK_SIZE, t.stack_size()); TEST_ASSERT_EQUAL(THREAD_STACK_SIZE, t.free_stack() + t.used_stack()); uint32_t last_stack = t.used_stack(); - t.signal_set(0x1); - Thread::yield(); + t.flags_set(0x1); + ThisThread::yield(); TEST_ASSERT_EQUAL(THREAD_STACK_SIZE, t.free_stack() + t.used_stack()); TEST_ASSERT(last_stack <= t.used_stack()); last_stack = t.used_stack(); - t.signal_set(0x1); - Thread::yield(); + t.flags_set(0x1); + ThisThread::yield(); TEST_ASSERT_EQUAL(THREAD_STACK_SIZE, t.free_stack() + t.used_stack()); TEST_ASSERT(last_stack >= t.used_stack()); - t.signal_set(0x1); + t.flags_set(0x1); t.join(); } @@ -427,9 +437,9 @@ void test_thread_name() { const char tname[] = "Amazing thread"; Thread t(osPriorityNormal, THREAD_STACK_SIZE, NULL, tname); - t.start(callback(thread_wait_signal)); + t.start(callback(thread_wait_flags)); TEST_ASSERT_EQUAL(strcmp(tname, t.get_name()), 0); - t.signal_set(0x1); + t.flags_set(0x1); t.join(); } @@ -473,7 +483,7 @@ void test_delay() t.start(callback(test_delay_thread)); - Thread::yield(); + ThisThread::yield(); TEST_ASSERT_EQUAL(Thread::WaitingDelay, t.get_state()); @@ -481,33 +491,33 @@ void test_delay() TEST_ASSERT_EQUAL(Thread::Deleted, t.get_state()); } -void test_signal_thread() +void test_thread_flags_thread() { - Thread::signal_wait(0x1); + ThisThread::flags_wait_all(0x1); } -/** Testing thread states: wait signal +/** Testing thread states: wait flags Given the thread is running - when thread waits for a signal - then its state, as reported by @a get_state, is @a WaitingSignal + when thread waits for flags + then its state, as reported by @a get_state, is @a WaitingThreadFlag */ -void test_signal() +void test_thread_flags() { Thread t(osPriorityNormal, THREAD_STACK_SIZE); - t.start(callback(test_signal_thread)); + t.start(callback(test_thread_flags_thread)); - Thread::yield(); + ThisThread::yield(); TEST_ASSERT_EQUAL(Thread::WaitingThreadFlag, t.get_state()); - t.signal_set(0x1); + t.flags_set(0x1); } -void test_evt_flag_thread(osEventFlagsId_t evtflg) +void test_evt_flag_thread(EventFlags *evtflg) { - osEventFlagsWait(evtflg, 0x1, osFlagsWaitAny, osWaitForever); + evtflg->wait_any(0x1); } /** Testing thread states: wait evt flag @@ -519,22 +529,15 @@ void test_evt_flag_thread(osEventFlagsId_t evtflg) void test_evt_flag() { Thread t(osPriorityNormal, THREAD_STACK_SIZE); - mbed_rtos_storage_event_flags_t evtflg_mem; - osEventFlagsAttr_t evtflg_attr; - osEventFlagsId_t evtflg; + EventFlags evtflg; - evtflg_attr.cb_mem = &evtflg_mem; - evtflg_attr.cb_size = sizeof(evtflg_mem); - evtflg = osEventFlagsNew(&evtflg_attr); - TEST_ASSERT_NOT_EQUAL(NULL, evtflg); + t.start(callback(test_evt_flag_thread, &evtflg)); - t.start(callback(test_evt_flag_thread, evtflg)); - - Thread::yield(); + ThisThread::yield(); TEST_ASSERT_EQUAL(Thread::WaitingEventFlag, t.get_state()); - osEventFlagsSet(evtflg, 0x1); + evtflg.set(0x1); } void test_mutex_thread(Mutex *mutex) @@ -557,7 +560,7 @@ void test_mutex() t.start(callback(test_mutex_thread, &mutex)); - Thread::yield(); + ThisThread::yield(); TEST_ASSERT_EQUAL(Thread::WaitingMutex, t.get_state()); @@ -582,7 +585,7 @@ void test_semaphore() t.start(callback(test_semaphore_thread, &sem)); - Thread::yield(); + ThisThread::yield(); TEST_ASSERT_EQUAL(Thread::WaitingSemaphore, t.get_state()); @@ -607,7 +610,7 @@ void test_msg_get() t.start(callback(test_msg_get_thread, &queue)); - Thread::yield(); + ThisThread::yield(); TEST_ASSERT_EQUAL(Thread::WaitingMessageGet, t.get_state()); @@ -635,7 +638,7 @@ void test_msg_put() t.start(callback(test_msg_put_thread, &queue)); - Thread::yield(); + ThisThread::yield(); TEST_ASSERT_EQUAL(Thread::WaitingMessagePut, t.get_state()); queue.get(); @@ -681,7 +684,7 @@ void test_thread_ext_stack() void test_thread_prio() { Thread t(osPriorityNormal, THREAD_STACK_SIZE); - t.start(callback(thread_wait_signal)); + t.start(callback(thread_wait_flags)); TEST_ASSERT_EQUAL(osPriorityNormal, t.get_priority()); @@ -689,7 +692,7 @@ void test_thread_prio() TEST_ASSERT_EQUAL(osPriorityHigh, t.get_priority()); - t.signal_set(0x1); + t.flags_set(0x1); t.join(); } @@ -726,12 +729,12 @@ static const case_t cases[] = { {"Testing thread self terminate", test_self_terminate, DEFAULT_HANDLERS}, - {"Testing thread signals: wait", test_thread_signal<0x1, signal_wait>, DEFAULT_HANDLERS}, - {"Testing thread signals: timeout", test_thread_signal<0x1, signal_wait_tout>, DEFAULT_HANDLERS}, - {"Testing thread signals: multi-bit", test_thread_signal<0x3, signal_wait_multibit>, DEFAULT_HANDLERS}, - {"Testing thread signals: multi-bit timeout", test_thread_signal<0x1, signal_wait_multibit_tout>, DEFAULT_HANDLERS}, - {"Testing thread signals: signal clear", test_thread_signal_clr, DEFAULT_HANDLERS}, - + {"Testing thread flags: wait", test_thread_flags_set<0x1, flags_wait>, DEFAULT_HANDLERS}, + {"Testing thread flags: timeout", test_thread_flags_set<0x1, flags_wait_tout>, DEFAULT_HANDLERS}, + {"Testing thread flags: multi-bit all", test_thread_flags_set<0x3, flags_wait_multibit>, DEFAULT_HANDLERS}, + {"Testing thread flags: multi-bit all timeout", test_thread_flags_set<0x1, flags_wait_multibit_tout>, DEFAULT_HANDLERS}, + {"Testing thread flags: multi-bit any", test_thread_flags_set<0x1, flags_wait_multibit_any>, DEFAULT_HANDLERS}, + {"Testing thread flags: flags clear", test_thread_flags_clear, DEFAULT_HANDLERS}, {"Testing thread stack info", test_thread_stack_info, DEFAULT_HANDLERS}, {"Testing thread wait", test_thread_wait, DEFAULT_HANDLERS}, @@ -739,7 +742,7 @@ static const case_t cases[] = { {"Testing thread states: deleted", test_deleted, DEFAULT_HANDLERS}, {"Testing thread states: wait delay", test_delay, DEFAULT_HANDLERS}, - {"Testing thread states: wait signal", test_signal, DEFAULT_HANDLERS}, + {"Testing thread states: wait thread flags", test_thread_flags, DEFAULT_HANDLERS}, {"Testing thread states: wait event flag", test_evt_flag, DEFAULT_HANDLERS}, {"Testing thread states: wait mutex", test_mutex, DEFAULT_HANDLERS}, {"Testing thread states: wait semaphore", test_semaphore, DEFAULT_HANDLERS}, diff --git a/rtos/Kernel.cpp b/rtos/Kernel.cpp index c4b1534edf..1e7e8bc794 100644 --- a/rtos/Kernel.cpp +++ b/rtos/Kernel.cpp @@ -23,6 +23,8 @@ #include "rtos/Kernel.h" #include "mbed.h" +#include "rtos/rtos_idle.h" +#include "rtos/rtos_handlers.h" namespace rtos { @@ -61,4 +63,14 @@ uint64_t Kernel::get_ms_count() } } +void Kernel::attach_idle_hook(void (*fptr)(void)) +{ + rtos_attach_idle_hook(fptr); +} + +void Kernel::attach_thread_terminate_hook(void (*fptr)(osThreadId_t id)) +{ + rtos_attach_thread_terminate_hook(fptr); +} + } diff --git a/rtos/Kernel.h b/rtos/Kernel.h index 8be9a2abe1..bd123def7f 100644 --- a/rtos/Kernel.h +++ b/rtos/Kernel.h @@ -23,6 +23,7 @@ #define KERNEL_H #include +#include "cmsis_os2.h" namespace rtos { /** \addtogroup rtos */ @@ -43,6 +44,20 @@ namespace Kernel { */ uint64_t get_ms_count(); +/** Attach a function to be called by the RTOS idle task + @param fptr pointer to the function to be called + + @note You may call this function from ISR context. +*/ +void attach_idle_hook(void (*fptr)(void)); + +/** Attach a function to be called when a task is killed + @param fptr pointer to the function to be called + + @note You may call this function from ISR context. +*/ +void attach_thread_terminate_hook(void (*fptr)(osThreadId_t id)); + } // namespace Kernel } // namespace rtos diff --git a/rtos/TARGET_CORTEX/mbed_rtx_handlers.c b/rtos/TARGET_CORTEX/mbed_rtx_handlers.c index 682684d8fa..8afa16c8fb 100644 --- a/rtos/TARGET_CORTEX/mbed_rtx_handlers.c +++ b/rtos/TARGET_CORTEX/mbed_rtx_handlers.c @@ -21,6 +21,7 @@ #include "mbed_error.h" #include "mbed_interface.h" #include "RTX_Config.h" +#include "rtos/rtos_handlers.h" #ifdef RTE_Compiler_EventRecorder #include "EventRecorder.h" // Keil::Compiler:Event Recorder @@ -30,7 +31,20 @@ #endif extern void rtos_idle_loop(void); -extern void thread_terminate_hook(osThreadId_t id); + +static void (*terminate_hook)(osThreadId_t id); + +static void thread_terminate_hook(osThreadId_t id) +{ + if (terminate_hook) { + terminate_hook(id); + } +} + +void rtos_attach_thread_terminate_hook(void (*fptr)(osThreadId_t id)) +{ + terminate_hook = fptr; +} __NO_RETURN void osRtxIdleThread(void *argument) { diff --git a/rtos/ThisThread.cpp b/rtos/ThisThread.cpp new file mode 100644 index 0000000000..8df8e04fe4 --- /dev/null +++ b/rtos/ThisThread.cpp @@ -0,0 +1,141 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2012 ARM Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define __STDC_LIMIT_MACROS +#include "rtos/ThisThread.h" + +#include "mbed.h" +#include "rtos/rtos_idle.h" +#include "mbed_assert.h" + +namespace rtos { + +uint32_t ThisThread::flags_clear(uint32_t flags) +{ + flags = osThreadFlagsClear(flags); + MBED_ASSERT(!(flags & osFlagsError)); + return flags; +} + +uint32_t ThisThread::flags_get() +{ + return osThreadFlagsGet(); +} + +static uint32_t flags_wait_for(uint32_t flags, uint32_t millisec, bool clear, uint32_t options) +{ + if (!clear) { + options |= osFlagsNoClear; + } + flags = osThreadFlagsWait(flags, options, millisec); + if (flags & osFlagsError) { + MBED_ASSERT((flags == osFlagsErrorTimeout && millisec != osWaitForever) || + (flags == osFlagsErrorResource && millisec == 0)); + flags = ThisThread::flags_get(); + } + + return flags; +} + +static uint32_t flags_wait_until(uint32_t flags, uint64_t millisec, bool clear, uint32_t options) +{ + uint64_t now = Kernel::get_ms_count(); + + uint32_t delay; + if (now >= millisec) { + delay = 0; + } else if (millisec - now >= osWaitForever) { + // Documentation permits early return for big offsets + delay = osWaitForever - 1; + } else { + delay = millisec - now; + } + return flags_wait_for(flags, delay, clear, options); +} + +uint32_t ThisThread::flags_wait_all(uint32_t flags, bool clear) +{ + return flags_wait_for(flags, osWaitForever, clear, osFlagsWaitAll); +} + +uint32_t ThisThread::flags_wait_all_for(uint32_t flags, uint32_t millisec, bool clear) +{ + return flags_wait_for(flags, millisec, clear, osFlagsWaitAll); +} + +uint32_t ThisThread::flags_wait_all_until(uint32_t flags, uint64_t millisec, bool clear) +{ + return flags_wait_until(flags, millisec, clear, osFlagsWaitAll); +} + +uint32_t ThisThread::flags_wait_any(uint32_t flags, bool clear) +{ + return flags_wait_for(flags, osWaitForever, clear, osFlagsWaitAny); +} + +uint32_t ThisThread::flags_wait_any_for(uint32_t flags, uint32_t millisec, bool clear) +{ + return flags_wait_for(flags, millisec, clear, osFlagsWaitAny); +} + +uint32_t ThisThread::flags_wait_any_until(uint32_t flags, uint64_t millisec, bool clear) +{ + return flags_wait_until(flags, millisec, clear, osFlagsWaitAny); +} + +void ThisThread::sleep_for(uint32_t millisec) +{ + osStatus_t status = osDelay(millisec); + MBED_ASSERT(status == osOK); +} + +void ThisThread::sleep_until(uint64_t millisec) +{ + // CMSIS-RTOS 2.1.0 had 64-bit time and osDelayUntil, but that's been revoked. + // Limit ourselves to manual implementation assuming a >=32-bit osDelay. + + // 64-bit time doesn't wrap (for half a billion years, at last) + // make the effort to loop for unlimited sleep, as it doesn't cost much + uint64_t now; + + while ((now = Kernel::get_ms_count()) < millisec) { + if (millisec - now > UINT32_MAX) { + sleep_for(UINT32_MAX); + continue; + } else { + sleep_for(millisec - now); + break; + } + } +} + +void ThisThread::yield() +{ + osThreadYield(); +} + +osThreadId_t ThisThread::get_id() +{ + return osThreadGetId(); +} + +} diff --git a/rtos/ThisThread.h b/rtos/ThisThread.h new file mode 100644 index 0000000000..c0104fc1e0 --- /dev/null +++ b/rtos/ThisThread.h @@ -0,0 +1,188 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2018 ARM Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef THIS_THREAD_H +#define THIS_THREAD_H + +#include +#include "cmsis_os2.h" +#include "mbed_rtos1_types.h" +#include "mbed_rtos_storage.h" +#include "platform/Callback.h" +#include "platform/mbed_toolchain.h" +#include "platform/NonCopyable.h" +#include "rtos/Semaphore.h" +#include "rtos/Mutex.h" + +namespace rtos { +/** \addtogroup rtos */ +/** @{*/ +/** + * \defgroup rtos_ThisThread ThisThread namespace + * @{ + */ + +/** The ThisThread namespace allows controlling the current thread. + * + * Example: + * @code + * #include "mbed.h" + * #include "rtos.h" + * + * Thread thread; + * DigitalOut led1(LED1); + * + * #define STOP_FLAG 1 + * + * // Blink function toggles the led in a long running loop + * void blink(DigitalOut *led) { + * while (!ThisThread::flags_wait_any_for(STOP_FLAG, 1000)) { + * *led = !*led; + * } + * } + * + * // Spawns a thread to run blink for 5 seconds + * int main() { + * thread.start(callback(blink, &led1)); + * ThisThread::sleep_for(5000); + * thread.signal_set(STOP_FLAG); + * thread.join(); + * } + * @endcode + * + */ +namespace ThisThread { +/** Clears the specified Thread Flags of the currently running thread. + @param flags specifies the flags of the thread that should be cleared. + @return thread flags before clearing. + @note You cannot call this function from ISR context. + @see Thread::flags_set +*/ +uint32_t flags_clear(uint32_t flags); + +/** Returns the Thread Flags currently set for the currently running thread. + @return current thread flags or 0 if not in a valid thread. + @note You cannot call this function from ISR context. + @see Thread::flags_set +*/ +uint32_t flags_get(); + +/** Wait for all of the specified Thread Flags to become signaled for the current thread. + @param flags specifies the flags to wait for + @param clear whether to clear the specified flags after waiting for them. (default: true) + @return actual thread flags before clearing, which will satisfy the wait + @note You cannot call this function from ISR context. + @see Thread::flags_set +*/ +uint32_t flags_wait_all(uint32_t flags, bool clear = true); + +/** Wait for any of the specified Thread Flags to become signaled for the current thread. + @param flags specifies the flags to wait for + @param clear whether to clear the specified flags after waiting for them. (default: true) + @return actual thread flags before clearing, which will satisfy the wait + @note You cannot call this function from ISR context. + @see Thread::flags_set +*/ +uint32_t flags_wait_any(uint32_t flags, bool clear = true); + +/** Wait for all of the specified Thread Flags to become signaled for the current thread. + @param flags specifies the flags to wait for + @param millisec timeout value or 0 in case of no time-out. + @param clear whether to clear the specified flags after waiting for them. (default: true) + @return actual thread flags before clearing, which may not satisfy the wait + @note You cannot call this function from ISR context. + @see Thread::flags_set +*/ +uint32_t flags_wait_all_for(uint32_t flags, uint32_t millisec, bool clear = true); + +/** Wait for all of the specified Thread Flags to become signaled for the current thread. + @param flags specifies the flags to wait for + @param millisec absolute timeout time, referenced to Kernel::get_ms_count() + @param clear whether to clear the specified flags after waiting for them. (default: true) + @return actual thread flags before clearing, which may not satisfy the wait + @note You cannot call this function from ISR context. + @note the underlying RTOS may have a limit to the maximum wait time + due to internal 32-bit computations, but this is guaranteed to work if the + wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded, + the wait will time out earlier than specified. + @see Thread::flags_set +*/ +uint32_t flags_wait_all_until(uint32_t flags, uint64_t millisec, bool clear = true); + +/** Wait for any of the specified Thread Flags to become signaled for the current thread. + @param flags specifies the flags to wait for + @param millisec timeout value or 0 in case of no time-out. + @param clear whether to clear the specified flags after waiting for them. (default: true) + @return actual thread flags before clearing, which may not satisfy the wait + @note You cannot call this function from ISR context. + @see Thread::flags_set +*/ +uint32_t flags_wait_any_for(uint32_t flags, uint32_t millisec, bool clear = true); + +/** Wait for any of the specified Thread Flags to become signaled for the current thread. + @param flags specifies the flags to wait for + @param millisec absolute timeout time, referenced to Kernel::get_ms_count() + @param clear whether to clear the specified flags after waiting for them. (default: true) + @return actual thread flags before clearing, which may not satisfy the wait + @note You cannot call this function from ISR context. + @note the underlying RTOS may have a limit to the maximum wait time + due to internal 32-bit computations, but this is guaranteed to work if the + wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded, + the wait will time out earlier than specified. + @see Thread::flags_set +*/ +uint32_t flags_wait_any_until(uint32_t flags, uint64_t millisec, bool clear = true); + +/** Sleep for a specified time period in millisec: + @param millisec time delay value + @note You cannot call this function from ISR context. +*/ +void sleep_for(uint32_t millisec); + +/** Sleep until a specified time in millisec + The specified time is according to Kernel::get_ms_count(). + @param millisec absolute time in millisec + @note You cannot call this function from ISR context. + @note if millisec is equal to or lower than the current tick count, this + returns immediately. +*/ +void sleep_until(uint64_t millisec); + +/** Pass control to next equal-priority thread that is in state READY. + (Higher-priority READY threads would prevent us from running; this + will not enable lower-priority threads to run, as we remain READY). + @note You cannot call this function from ISR context. +*/ +void yield(); + +/** Get the thread id of the current running thread. + @return thread ID for reference by other functions or NULL in case of error or in ISR context. + @note You may call this function from ISR context. +*/ +osThreadId_t get_id(); + +}; +/** @}*/ +/** @}*/ +} +#endif + + diff --git a/rtos/Thread.cpp b/rtos/Thread.cpp index 172fe751d6..f56053d305 100644 --- a/rtos/Thread.cpp +++ b/rtos/Thread.cpp @@ -20,9 +20,11 @@ * SOFTWARE. */ #include "rtos/Thread.h" +#include "rtos/ThisThread.h" #include "mbed.h" #include "rtos/rtos_idle.h" +#include "rtos/rtos_handlers.h" #include "mbed_assert.h" #define ALIGN_UP(pos, align) ((pos) % (align) ? (pos) + ((align) - (pos) % (align)) : (pos)) @@ -33,14 +35,6 @@ MBED_STATIC_ASSERT(ALIGN_UP(1, 8) == 8, "ALIGN_UP macro error"); MBED_STATIC_ASSERT(ALIGN_DOWN(7, 8) == 0, "ALIGN_DOWN macro error"); MBED_STATIC_ASSERT(ALIGN_DOWN(8, 8) == 8, "ALIGN_DOWN macro error"); -static void (*terminate_hook)(osThreadId_t id) = 0; -extern "C" void thread_terminate_hook(osThreadId_t id) -{ - if (terminate_hook != (void (*)(osThreadId_t))NULL) { - terminate_hook(id); - } -} - namespace rtos { #ifndef MBED_TZ_DEFAULT_ACCESS @@ -195,6 +189,13 @@ osPriority Thread::get_priority() return ret; } +uint32_t Thread::flags_set(uint32_t flags) +{ + flags = osThreadFlagsSet(_tid, flags); + MBED_ASSERT(!(flags & osFlagsError)); + return flags; +} + int32_t Thread::signal_set(int32_t flags) { return osThreadFlagsSet(_tid, flags); @@ -338,6 +339,11 @@ const char *Thread::get_name() return _attr.name; } +osThreadId_t Thread::get_id() const +{ + return _tid; +} + int32_t Thread::signal_clr(int32_t flags) { return osThreadFlagsClear(flags); @@ -379,37 +385,14 @@ osEvent Thread::signal_wait(int32_t signals, uint32_t millisec) osStatus Thread::wait(uint32_t millisec) { - return osDelay(millisec); + ThisThread::sleep_for(millisec); + return osOK; } osStatus Thread::wait_until(uint64_t millisec) { - // CMSIS-RTOS 2.1.0 and 2.1.1 differ in the time type, which we determine - // by looking at the return type of osKernelGetTickCount. We assume - // our header at least matches the implementation, so we don't try looking - // at the run-time version report. (There's no compile-time version report) - if (sizeof osKernelGetTickCount() == sizeof(uint64_t)) { - // CMSIS-RTOS 2.1.0 has a 64-bit API. The corresponding RTX 5.2.0 can't - // delay more than 0xfffffffe ticks, but there's no limit stated for - // the generic API. - return osDelayUntil(millisec); - } else { - // 64-bit time doesn't wrap (for half a billion years, at last) - uint64_t now = Kernel::get_ms_count(); - // Report being late on entry - if (now >= millisec) { - return osErrorParameter; - } - // We're about to make a 32-bit delay call, so have at least this limit - if (millisec - now > 0xFFFFFFFF) { - return osErrorParameter; - } - // And this may have its own internal limit - we'll find out. - // We hope/assume there's no problem with passing - // osWaitForever = 0xFFFFFFFF - that value is only specified to have - // special meaning for osSomethingWait calls. - return osDelay(millisec - now); - } + ThisThread::sleep_until(millisec); + return osOK; } osStatus Thread::yield() @@ -429,7 +412,7 @@ void Thread::attach_idle_hook(void (*fptr)(void)) void Thread::attach_terminate_hook(void (*fptr)(osThreadId_t id)) { - terminate_hook = fptr; + rtos_attach_thread_terminate_hook(fptr); } Thread::~Thread() diff --git a/rtos/Thread.h b/rtos/Thread.h index fb67d4dfc7..4d17e0e894 100644 --- a/rtos/Thread.h +++ b/rtos/Thread.h @@ -280,7 +280,6 @@ public: /** Wait for thread to terminate @return status code that indicates the execution status of the function. - @note not callable from interrupt @note You cannot call this function from ISR context. */ @@ -308,12 +307,25 @@ public: */ osPriority get_priority(); + /** Set the specified Thread Flags for the thread. + @param flags specifies the flags of the thread that should be set. + @return thread flags after setting or osFlagsError in case of incorrect parameters. + + @note You may call this function from ISR context. + */ + uint32_t flags_set(uint32_t flags); + /** Set the specified Thread Flags for the thread. @param signals specifies the signal flags of the thread that should be set. @return signal flags after setting or osFlagsError in case of incorrect parameters. @note You may call this function from ISR context. + @deprecated Other signal_xxx methods have been deprecated in favour of ThisThread::flags functions. + To match this naming scheme, derived from CMSIS-RTOS2, Thread::flags_set is now provided. */ + MBED_DEPRECATED_SINCE("mbed-os-5.10", + "Other signal_xxx methods have been deprecated in favour of ThisThread::flags functions. " + "To match this naming scheme, derived from CMSIS-RTOS2, Thread::flags_set is now provided.") int32_t signal_set(int32_t signals); /** State of the Thread */ @@ -381,12 +393,23 @@ public: */ const char *get_name(); + /** Get thread id + @return thread ID for reference by other functions. + + @note You may call this function from ISR context. + */ + osThreadId_t get_id() const; + /** Clears the specified Thread Flags of the currently running thread. @param signals specifies the signal flags of the thread that should be cleared. @return signal flags before clearing or osFlagsError in case of incorrect parameters. @note You cannot call this function from ISR context. + @deprecated Static methods only affecting current thread cause confusion. Replaced by ThisThread::flags_clear. */ + MBED_DEPRECATED_SINCE("mbed-os-5.10", + "Static methods only affecting current thread cause confusion. " + "Replaced by ThisThread::flags_clear.") static int32_t signal_clr(int32_t signals); /** Wait for one or more Thread Flags to become signaled for the current RUNNING thread. @@ -395,7 +418,12 @@ public: @return event flag information or error code. @note if @a millisec is set to 0 and flag is no set the event carries osOK value. @note You cannot call this function from ISR context. + @deprecated Static methods only affecting current thread cause confusion. + Replaced by ThisThread::flags_wait_all, ThisThread::flags_wait_all_for, ThisThread::flags_wait_any and ThisThread:wait_any_for. */ + MBED_DEPRECATED_SINCE("mbed-os-5.10", + "Static methods only affecting current thread cause confusion. " + "Replaced by ThisThread::flags_wait_all, ThisThread::flags_wait_all_for, ThisThread::flags_wait_any and ThisThread:wait_any_for.") static osEvent signal_wait(int32_t signals, uint32_t millisec = osWaitForever); /** Wait for a specified time period in milliseconds @@ -406,7 +434,11 @@ public: @return status code that indicates the execution status of the function. @note You cannot call this function from ISR context. + @deprecated Static methods only affecting current thread cause confusion. Replaced by ThisThread::sleep_for. */ + MBED_DEPRECATED_SINCE("mbed-os-5.10", + "Static methods only affecting current thread cause confusion. " + "Replaced by ThisThread::sleep_for.") static osStatus wait(uint32_t millisec); /** Wait until a specified time in millisec @@ -422,35 +454,56 @@ public: it may return with an immediate error, or wait for the maximum delay. @note You cannot call this function from ISR context. + @deprecated Static methods only affecting current thread cause confusion. Replaced by ThisThread::sleep_until. */ + MBED_DEPRECATED_SINCE("mbed-os-5.10", + "Static methods only affecting current thread cause confusion. " + "Replaced by ThisThread::sleep_until.") static osStatus wait_until(uint64_t millisec); /** Pass control to next thread that is in state READY. @return status code that indicates the execution status of the function. @note You cannot call this function from ISR context. + @deprecated Static methods only affecting current thread cause confusion. Replaced by ThisThread::sleep_until. */ + MBED_DEPRECATED_SINCE("mbed-os-5.10", + "Static methods only affecting current thread cause confusion. " + "Replaced by ThisThread::yield.") static osStatus yield(); /** Get the thread id of the current running thread. @return thread ID for reference by other functions or NULL in case of error. @note You may call this function from ISR context. + @deprecated Static methods only affecting current thread cause confusion. Replaced by ThisThread::get_id. + Use Thread::get_id for the ID of a specific Thread. */ + MBED_DEPRECATED_SINCE("mbed-os-5.10", + "Static methods only affecting current thread cause confusion. " + "Replaced by ThisThread::get_id. Use Thread::get_id for the ID of a specific Thread.") static osThreadId gettid(); /** Attach a function to be called by the RTOS idle task @param fptr pointer to the function to be called @note You may call this function from ISR context. + @deprecated Static methods affecting system cause confusion. Replaced by Kernel::attach_idle_hook. */ + MBED_DEPRECATED_SINCE("mbed-os-5.10", + "Static methods affecting system cause confusion. " + "Replaced by Kernel::attach_idle_hook.") static void attach_idle_hook(void (*fptr)(void)); /** Attach a function to be called when a task is killed @param fptr pointer to the function to be called @note You may call this function from ISR context. + @deprecated Static methods affecting system cause confusion. Replaced by Kernel::attach_thread_terminate_hook. */ + MBED_DEPRECATED_SINCE("mbed-os-5.10", + "Static methods affecting system cause confusion. " + "Replaced by Kernel::attach_thread_terminate_hook.") static void attach_terminate_hook(void (*fptr)(osThreadId id)); /** Thread destructor diff --git a/rtos/rtos.h b/rtos/rtos.h index 4b3802cd23..174e730275 100644 --- a/rtos/rtos.h +++ b/rtos/rtos.h @@ -28,6 +28,7 @@ #include "mbed_rtos_storage.h" #include "rtos/Kernel.h" #include "rtos/Thread.h" +#include "rtos/ThisThread.h" #include "rtos/Mutex.h" #include "rtos/RtosTimer.h" #include "rtos/Semaphore.h" diff --git a/rtos/rtos_handlers.h b/rtos/rtos_handlers.h new file mode 100644 index 0000000000..e3d474300f --- /dev/null +++ b/rtos/rtos_handlers.h @@ -0,0 +1,53 @@ + +/** \addtogroup rtos */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2006-2012 ARM Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef RTOS_HANDLERS_H +#define RTOS_HANDLERS_H + +#include "cmsis_os2.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup rtos_handlers RTOS hook functions + * @{ + */ +/** + @note + Sets the hook function called by thread termination + @param fptr Hook function pointer. + */ +void rtos_attach_thread_terminate_hook(void (*fptr)(osThreadId_t id)); +/** @}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +/** @}*/ + From 0ddd1d9af5c2ee26e22c4fbde1d2d8cfea42f2d6 Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Thu, 23 Aug 2018 15:14:20 +0300 Subject: [PATCH 3/3] Make Thread methods const --- rtos/Thread.cpp | 14 +++++++------- rtos/Thread.h | 16 ++++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/rtos/Thread.cpp b/rtos/Thread.cpp index f56053d305..4faf8058f4 100644 --- a/rtos/Thread.cpp +++ b/rtos/Thread.cpp @@ -178,7 +178,7 @@ osStatus Thread::set_priority(osPriority priority) return ret; } -osPriority Thread::get_priority() +osPriority Thread::get_priority() const { osPriority_t ret; _mutex.lock(); @@ -201,7 +201,7 @@ int32_t Thread::signal_set(int32_t flags) return osThreadFlagsSet(_tid, flags); } -Thread::State Thread::get_state() +Thread::State Thread::get_state() const { uint8_t state = osThreadTerminated; @@ -267,7 +267,7 @@ Thread::State Thread::get_state() return user_state; } -uint32_t Thread::stack_size() +uint32_t Thread::stack_size() const { uint32_t size = 0; _mutex.lock(); @@ -280,7 +280,7 @@ uint32_t Thread::stack_size() return size; } -uint32_t Thread::free_stack() +uint32_t Thread::free_stack() const { uint32_t size = 0; _mutex.lock(); @@ -296,7 +296,7 @@ uint32_t Thread::free_stack() return size; } -uint32_t Thread::used_stack() +uint32_t Thread::used_stack() const { uint32_t size = 0; _mutex.lock(); @@ -312,7 +312,7 @@ uint32_t Thread::used_stack() return size; } -uint32_t Thread::max_stack() +uint32_t Thread::max_stack() const { uint32_t size = 0; _mutex.lock(); @@ -334,7 +334,7 @@ uint32_t Thread::max_stack() return size; } -const char *Thread::get_name() +const char *Thread::get_name() const { return _attr.name; } diff --git a/rtos/Thread.h b/rtos/Thread.h index 4d17e0e894..34933e8bc2 100644 --- a/rtos/Thread.h +++ b/rtos/Thread.h @@ -305,7 +305,7 @@ public: @note You cannot call this function from ISR context. */ - osPriority get_priority(); + osPriority get_priority() const; /** Set the specified Thread Flags for the thread. @param flags specifies the flags of the thread that should be set. @@ -356,42 +356,42 @@ public: @note You cannot call this function from ISR context. */ - State get_state(); + State get_state() const; /** Get the total stack memory size for this Thread @return the total stack memory size in bytes @note You cannot call this function from ISR context. */ - uint32_t stack_size(); + uint32_t stack_size() const; /** Get the currently unused stack memory for this Thread @return the currently unused stack memory in bytes @note You cannot call this function from ISR context. */ - uint32_t free_stack(); + uint32_t free_stack() const; /** Get the currently used stack memory for this Thread @return the currently used stack memory in bytes @note You cannot call this function from ISR context. */ - uint32_t used_stack(); + uint32_t used_stack() const; /** Get the maximum stack memory usage to date for this Thread @return the maximum stack memory usage to date in bytes @note You cannot call this function from ISR context. */ - uint32_t max_stack(); + uint32_t max_stack() const; /** Get thread name @return thread name or NULL if the name was not set. @note You may call this function from ISR context. */ - const char *get_name(); + const char *get_name() const; /** Get thread id @return thread ID for reference by other functions. @@ -536,7 +536,7 @@ private: osThreadAttr_t _attr; bool _dynamic_stack; Semaphore _join_sem; - Mutex _mutex; + mutable Mutex _mutex; mbed_rtos_storage_thread_t _obj_mem; bool _finished; };