From b8e80dd2fb3fac8d8e0e2ada930e95eec03c5b63 Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Tue, 9 Apr 2019 16:09:24 +0300 Subject: [PATCH] Don't trap RTX errors or mutex errors during errors Once a fatal error is in progress, it's not useful to trap RTX errors or mutex problems, so short-circuit the checks. This makes it more likely that we may be able to get the console initialised if it is being written to for the first time by `mbed_error` in a difficult context - such as an RTX error callback from inside an SVCall. For example, the one-line program osMutexAcquire(NULL, 0); will generate an RTX error trap, then `mbed_error` will try to call `write(STDERR_FILENO)` to print the error, which will prompt mbed_retarget to construct a singleton `UARTSerial`. This would trap in the mutex for the singleton or the construction of the UARTSerial itself, if we didn't allow this leniency. If we clear the mutex checks, then `UARTSerial::write_unbuffered` will work. --- platform/mbed_error.c | 12 +++++++++--- platform/mbed_error.h | 8 ++++++++ rtos/Mutex.cpp | 20 +++++++++++-------- rtos/TARGET_CORTEX/mbed_rtx_handlers.c | 27 ++++++++++++++++++-------- 4 files changed, 48 insertions(+), 19 deletions(-) diff --git a/platform/mbed_error.c b/platform/mbed_error.c index f65d05ff65..ee5e93e6cc 100644 --- a/platform/mbed_error.c +++ b/platform/mbed_error.c @@ -45,7 +45,7 @@ static void print_error_report(const mbed_error_ctx *ctx, const char *, const ch #define ERROR_REPORT(ctx, error_msg, error_filename, error_line) ((void) 0) #endif -static core_util_atomic_flag error_in_progress = CORE_UTIL_ATOMIC_FLAG_INIT; +static bool error_in_progress; static core_util_atomic_flag halt_in_progress = CORE_UTIL_ATOMIC_FLAG_INIT; static int error_count = 0; static mbed_error_ctx first_error_ctx = {0}; @@ -115,7 +115,7 @@ static MBED_NORETURN void mbed_halt_system(void) WEAK MBED_NORETURN void error(const char *format, ...) { // Prevent recursion if error is called again during store+print attempt - if (!core_util_atomic_flag_test_and_set(&error_in_progress)) { + if (!core_util_atomic_exchange_bool(&error_in_progress, true)) { handle_error(MBED_ERROR_UNKNOWN, 0, NULL, 0, MBED_CALLER_ADDR()); ERROR_REPORT(&last_error_ctx, "Fatal Run-time error", NULL, 0); @@ -256,6 +256,12 @@ int mbed_get_error_count(void) return error_count; } +//Reads the fatal error occurred" flag +bool mbed_get_error_in_progress(void) +{ + return core_util_atomic_load_bool(&error_in_progress); +} + //Sets a non-fatal error mbed_error_status_t mbed_warning(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number) { @@ -266,7 +272,7 @@ mbed_error_status_t mbed_warning(mbed_error_status_t error_status, const char *e WEAK MBED_NORETURN mbed_error_status_t mbed_error(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number) { // Prevent recursion if error is called again during store+print attempt - if (!core_util_atomic_flag_test_and_set(&error_in_progress)) { + if (!core_util_atomic_exchange_bool(&error_in_progress, true)) { //set the error reported (void) handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR()); diff --git a/platform/mbed_error.h b/platform/mbed_error.h index 4301f2ff67..d1982f42f1 100644 --- a/platform/mbed_error.h +++ b/platform/mbed_error.h @@ -23,6 +23,7 @@ #ifndef MBED_ERROR_H #define MBED_ERROR_H +#include #include "platform/mbed_retarget.h" #include "platform/mbed_toolchain.h" @@ -1036,6 +1037,13 @@ mbed_error_status_t mbed_get_last_error(void); */ int mbed_get_error_count(void); +/** + * Returns whether we are processing a fatal mbed error. + * @return bool Whether a fatal error has occurred. + * + */ +bool mbed_get_error_in_progress(void); + /** * Call this function to set a fatal system error and halt the system. This function will log the fatal error with the context info and prints the error report and halts the system. * diff --git a/rtos/Mutex.cpp b/rtos/Mutex.cpp index 24596156ee..d6841159a3 100644 --- a/rtos/Mutex.cpp +++ b/rtos/Mutex.cpp @@ -47,7 +47,10 @@ void Mutex::constructor(const char *name) attr.cb_size = sizeof(_obj_mem); attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust; _id = osMutexNew(&attr); - MBED_ASSERT(_id); + // To permit certain cases where a device may get constructed in + // by the attempt to print an error in a fatal shutdown, let a + // mutex construction error pass. + MBED_ASSERT(_id || mbed_get_error_in_progress()); } osStatus Mutex::lock(void) @@ -57,7 +60,7 @@ osStatus Mutex::lock(void) _count++; } - if (status != osOK) { + if (status != osOK && !mbed_get_error_in_progress()) { MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_MUTEX_LOCK_FAILED), "Mutex lock failed", status); } @@ -75,7 +78,7 @@ osStatus Mutex::lock(uint32_t millisec) (status == osErrorResource && millisec == 0) || (status == osErrorTimeout && millisec != osWaitForever)); - if (!success) { + if (!success && !mbed_get_error_in_progress()) { MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_MUTEX_LOCK_FAILED), "Mutex lock failed", status); } @@ -98,7 +101,7 @@ bool Mutex::trylock_for(uint32_t millisec) (status == osErrorResource && millisec == 0) || (status == osErrorTimeout && millisec != osWaitForever)); - if (!success) { + if (!success && !mbed_get_error_in_progress()) { MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_MUTEX_LOCK_FAILED), "Mutex lock failed", status); } @@ -121,15 +124,16 @@ bool Mutex::trylock_until(uint64_t millisec) osStatus Mutex::unlock() { - _count--; - osStatus status = osMutexRelease(_id); + if (osOK == status) { + _count--; + } - if (status != osOK) { + if (status != osOK && !mbed_get_error_in_progress()) { MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_MUTEX_UNLOCK_FAILED), "Mutex unlock failed", status); } - return osOK; + return status; } osThreadId Mutex::get_owner() diff --git a/rtos/TARGET_CORTEX/mbed_rtx_handlers.c b/rtos/TARGET_CORTEX/mbed_rtx_handlers.c index 845990c7c1..31ce7f81d7 100644 --- a/rtos/TARGET_CORTEX/mbed_rtx_handlers.c +++ b/rtos/TARGET_CORTEX/mbed_rtx_handlers.c @@ -107,29 +107,40 @@ static const char *error_msg(int32_t status) } } +static void trap_rtx_error(unsigned int error_value, int32_t rtx_status, mbed_error_status_t error_status) +{ + // Attempts to get the console for the first time while printing an error + // may well cause a mutex error; in general let RTX calls fail during + // an error condition. + if (mbed_get_error_in_progress()) { + return; + } + MBED_ERROR1(error_status, error_msg(rtx_status), error_value); +} + void EvrRtxKernelError(int32_t status) { - MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_EVENT), error_msg(status), status); + trap_rtx_error(status, status, MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_EVENT)); } 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); + trap_rtx_error((unsigned int) thread_id, status, MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_THREAD_EVENT)); } 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); + trap_rtx_error((unsigned int) timer_id, status, MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_TIMER_EVENT)); } 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); + trap_rtx_error((unsigned int) ef_id, status, MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_EVENT_FLAGS_EVENT)); } 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); + trap_rtx_error((unsigned int) mutex_id, status, MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_MUTEX_EVENT)); } void EvrRtxSemaphoreError(osSemaphoreId_t semaphore_id, int32_t status) @@ -139,17 +150,17 @@ void EvrRtxSemaphoreError(osSemaphoreId_t semaphore_id, int32_t status) return; } - MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_SEMAPHORE_EVENT), error_msg(status), semaphore_id); + trap_rtx_error((unsigned int) semaphore_id, status, MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_SEMAPHORE_EVENT)); } 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); + trap_rtx_error((unsigned int) mp_id, status, MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_MEMORY_POOL_EVENT)); } 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); + trap_rtx_error((unsigned int) mq_id, status, MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT)); } #endif