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.
pull/10358/head
Kevin Bracey 2019-04-09 16:09:24 +03:00
parent aa0e86475c
commit b8e80dd2fb
4 changed files with 48 additions and 19 deletions

View File

@ -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());

View File

@ -23,6 +23,7 @@
#ifndef MBED_ERROR_H
#define MBED_ERROR_H
#include <stdbool.h>
#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.
*

View File

@ -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()

View File

@ -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