diff --git a/TESTS/mbed_hal/sleep_manager/main.cpp b/TESTS/mbed_hal/sleep_manager/main.cpp index e33172769a5..5f5afad9b40 100644 --- a/TESTS/mbed_hal/sleep_manager/main.cpp +++ b/TESTS/mbed_hal/sleep_manager/main.cpp @@ -34,21 +34,6 @@ using utest::v1::Case; using utest::v1::Specification; using utest::v1::Harness; -static uint32_t num_test_errors = 0UL; - -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) -{ - (void) error_status; - (void) error_msg; - (void) error_value; - (void) filename; - (void) line_number; - - num_test_errors++; - return MBED_SUCCESS; -} - void test_lock_unlock() { TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); @@ -60,16 +45,6 @@ void test_lock_unlock() TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); } -void test_lone_unlock() -{ - uint32_t expected_err_count = num_test_errors + 1; - sleep_manager_unlock_deep_sleep(); - TEST_ASSERT_EQUAL_UINT32(expected_err_count, num_test_errors); - - // Make sure upcoming tests won't be broken. - TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); -} - void test_lock_eq_ushrt_max() { uint32_t lock_count = 0; @@ -87,27 +62,6 @@ void test_lock_eq_ushrt_max() TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); } -void test_lock_gt_ushrt_max() -{ - uint32_t lock_count = 0; - while (lock_count < USHRT_MAX) { - sleep_manager_lock_deep_sleep(); - lock_count++; - TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep()); - } - - uint32_t expected_err_count = num_test_errors + 1; - sleep_manager_lock_deep_sleep(); - TEST_ASSERT_EQUAL_UINT32(expected_err_count, num_test_errors); - - // Make sure upcoming tests won't be broken. - while (lock_count > 0) { - sleep_manager_unlock_deep_sleep(); - lock_count--; - } - TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); -} - #if DEVICE_LPTICKER #if DEVICE_USTICKER utest::v1::status_t testcase_setup(const Case * const source, const size_t index_of_case) @@ -279,9 +233,7 @@ utest::v1::status_t testsuite_setup(const size_t number_of_cases) Case cases[] = { Case("deep sleep lock/unlock", test_lock_unlock), - Case("deep sleep unbalanced unlock", test_lone_unlock), Case("deep sleep locked USHRT_MAX times", test_lock_eq_ushrt_max), - Case("deep sleep locked more than USHRT_MAX times", test_lock_gt_ushrt_max), #if DEVICE_LPTICKER #if DEVICE_USTICKER Case("sleep_auto calls sleep/deep sleep based on lock", diff --git a/TESTS/mbed_hal/sleep_manager/sleep_manager_api_tests.h b/TESTS/mbed_hal/sleep_manager/sleep_manager_api_tests.h index 5a41780379e..6dce0efaddc 100644 --- a/TESTS/mbed_hal/sleep_manager/sleep_manager_api_tests.h +++ b/TESTS/mbed_hal/sleep_manager/sleep_manager_api_tests.h @@ -38,14 +38,6 @@ */ void test_lock_unlock(); -/** Test an unbalanced unlock call - * - * Given the deep sleep has not been locked - * When the deep sleep mode is unlocked - * Then an mbed_error is raised - */ -void test_lone_unlock(); - /** Test lock USHRT_MAX times * * Given a device with sleep mode support @@ -58,14 +50,6 @@ void test_lone_unlock(); */ void test_lock_eq_ushrt_max(); -/** Test lock more than USHRT_MAX times - * - * Given the deep sleep has already been locked USHRT_MAX times - * When the deep sleep mode is locked again - * Then an mbed_error is raised - */ -void test_lock_gt_ushrt_max(); - /** Test sleep_auto calls sleep and deep sleep based on lock * * Given a device with sleep mode support diff --git a/TESTS/mbedmicro-rtos-mbed/event_flags/main.cpp b/TESTS/mbedmicro-rtos-mbed/event_flags/main.cpp index 7d98c21a2e3..0cba8c5dde9 100644 --- a/TESTS/mbedmicro-rtos-mbed/event_flags/main.cpp +++ b/TESTS/mbedmicro-rtos-mbed/event_flags/main.cpp @@ -48,26 +48,6 @@ using utest::v1::Case; Semaphore sync_sem(0, 1); -/* In order to successfully run this test suite when compiled with --profile=debug - * error() has to be redefined as noop. - * - * EventFlags calls RTX API which uses Event Recorder functionality. When compiled - * with MBED_TRAP_ERRORS_ENABLED=1 (set in debug profile) EvrRtxEventFlagsError() calls error() - * which aborts test program. - */ -#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED -void error(const char *format, ...) -{ - (void) format; -} - -//Override the set_error function to trap the errors -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) -{ - return MBED_SUCCESS; -} -#endif - template void send_thread(EventFlags *ef) { @@ -167,14 +147,18 @@ void test_prohibited(void) ev.set(FLAG01 | FLAG02 | FLAG03); +#if !MBED_TRAP_ERRORS_ENABLED flags = ev.clear(PROHIBITED_FLAG); TEST_ASSERT_EQUAL(osFlagsErrorParameter, flags); +#endif flags = ev.get(); TEST_ASSERT_EQUAL(FLAG01 | FLAG02 | FLAG03, flags); +#if !MBED_TRAP_ERRORS_ENABLED flags = ev.set(PROHIBITED_FLAG); TEST_ASSERT_EQUAL(osFlagsErrorParameter, flags); +#endif flags = ev.get(); TEST_ASSERT_EQUAL(FLAG01 | FLAG02 | FLAG03, flags); diff --git a/TESTS/mbedmicro-rtos-mbed/rtostimer/main.cpp b/TESTS/mbedmicro-rtos-mbed/rtostimer/main.cpp index 74cfb51f543..a06561afc83 100644 --- a/TESTS/mbedmicro-rtos-mbed/rtostimer/main.cpp +++ b/TESTS/mbedmicro-rtos-mbed/rtostimer/main.cpp @@ -77,25 +77,6 @@ void sem_callback(Semaphore *sem) sem->release(); } -/* In order to successfully run this test suite when compiled with --profile=debug - * error() has to be redefined as noop. - * - * RtosTimer calls RTX API which uses Event Recorder functionality. When compiled - * with MBED_TRAP_ERRORS_ENABLED=1 (set in debug profile) EvrRtxTimerError() calls error() - * which aborts test program. - */ -#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED -void error(const char *format, ...) -{ - (void) format; -} - -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) -{ - return MBED_SUCCESS; -} -#endif - /** Test one-shot not restarted when elapsed * * Given a one-shot RtosTimer @@ -121,8 +102,11 @@ void test_oneshot_not_restarted() slots = stopwatch.wait_until_stopped(DELAY_MS + DELTA_MS); TEST_ASSERT_EQUAL(0, slots); + +#if !MBED_TRAP_ERRORS_ENABLED status = rtostimer.stop(); TEST_ASSERT_EQUAL(osErrorResource, status); +#endif } /** Test periodic repeats continuously @@ -160,8 +144,11 @@ void test_periodic_repeats() slots = stopwatch.wait_until_stopped(DELAY_MS + DELTA_MS); TEST_ASSERT_EQUAL(0, slots); + +#if !MBED_TRAP_ERRORS_ENABLED status = rtostimer.stop(); TEST_ASSERT_EQUAL(osErrorResource, status); +#endif } /** Test timer can be started again @@ -185,8 +172,10 @@ void test_start_again() int32_t slots = sem.wait(DELAY_MS + DELTA_MS); TEST_ASSERT_EQUAL(1, slots); +#if !MBED_TRAP_ERRORS_ENABLED status = rtostimer.stop(); TEST_ASSERT_EQUAL(osErrorResource, status); +#endif status = rtostimer.start(DELAY_MS); TEST_ASSERT_EQUAL(osOK, status); @@ -194,8 +183,10 @@ void test_start_again() slots = sem.wait(DELAY_MS + DELTA_MS); TEST_ASSERT_EQUAL(1, slots); +#if !MBED_TRAP_ERRORS_ENABLED status = rtostimer.stop(); TEST_ASSERT_EQUAL(osErrorResource, status); +#endif } /** Test timer restart updates delay @@ -228,8 +219,10 @@ void test_restart_updates_delay() TEST_ASSERT_EQUAL(1, slots); TEST_ASSERT_INT_WITHIN(DELTA_MS, DELAY2_MS, stopwatch.read_ms()); +#if !MBED_TRAP_ERRORS_ENABLED status = rtostimer.stop(); TEST_ASSERT_EQUAL(osErrorResource, status); +#endif } /** Test timer is created in stopped state @@ -241,8 +234,10 @@ void test_restart_updates_delay() void test_created_stopped() { RtosTimer rtostimer(mbed::callback(sem_callback, (Semaphore *) NULL), osTimerOnce); +#if !MBED_TRAP_ERRORS_ENABLED osStatus status = rtostimer.stop(); TEST_ASSERT_EQUAL(osErrorResource, status); +#endif } /** Test one-shot can be stopped @@ -269,8 +264,10 @@ void test_stop() slots = sem.wait(DELAY_MS + DELTA_MS); TEST_ASSERT_EQUAL(0, slots); +#if !MBED_TRAP_ERRORS_ENABLED status = rtostimer.stop(); TEST_ASSERT_EQUAL(osErrorResource, status); +#endif } /** Test timer started with infinite delay @@ -290,6 +287,7 @@ void test_wait_forever() TEST_ASSERT_EQUAL(osOK, status); } +#if !MBED_TRAP_ERRORS_ENABLED /** Test timer started with zero delay * * Given a one-shot RtosTimer @@ -331,6 +329,7 @@ void test_isr_calls_fail() wait_ms(DELAY_MS + DELTA_MS); } +#endif // !MBED_TRAP_ERRORS_ENABLED utest::v1::status_t test_setup(const size_t number_of_cases) { @@ -346,8 +345,10 @@ Case cases[] = { Case("Timer can be stopped", test_stop), Case("Timer is created in stopped state", test_created_stopped), Case("Timer started with infinite delay", test_wait_forever), +#if !MBED_TRAP_ERRORS_ENABLED Case("Timer started with zero delay", test_no_wait), Case("Calls from ISR fail", test_isr_calls_fail) +#endif }; Specification specification(test_setup, cases); diff --git a/TESTS/mbedmicro-rtos-mbed/signals/main.cpp b/TESTS/mbedmicro-rtos-mbed/signals/main.cpp index 07499a8a50e..4f340a646ee 100644 --- a/TESTS/mbedmicro-rtos-mbed/signals/main.cpp +++ b/TESTS/mbedmicro-rtos-mbed/signals/main.cpp @@ -46,27 +46,6 @@ struct Sync { Semaphore &sem_child; }; - -/* In order to successfully run this test suite when compiled with --profile=debug - * error() has to be redefined as noop. - * - * ThreadFlags calls RTX API which uses Event Recorder functionality. When compiled - * with MBED_TRAP_ERRORS_ENABLED=1 (set in debug profile) EvrRtxEventFlagsError() calls error() - * which aborts test program. - */ -#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED -void error(const char *format, ...) -{ - (void) format; -} - -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) -{ - return MBED_SUCCESS; -} -#endif - - template void run_signal_wait(void) { @@ -214,8 +193,10 @@ void test_set_prohibited(void) sem_parent.wait(); t.signal_set(ALL_SIGNALS); +#if !MBED_TRAP_ERRORS_ENABLED ret = t.signal_set(PROHIBITED_SIGNAL); TEST_ASSERT_EQUAL(osErrorParameter, ret); +#endif sem_child.release(); t.join(); diff --git a/features/lwipstack/lwip-sys/arch/cc.h b/features/lwipstack/lwip-sys/arch/cc.h index 90a0d7c868b..619e144efd9 100644 --- a/features/lwipstack/lwip-sys/arch/cc.h +++ b/features/lwipstack/lwip-sys/arch/cc.h @@ -97,7 +97,7 @@ void lwip_mbed_tracef_debug(const char *fmt, ...); void lwip_mbed_tracef_error(const char *fmt, ...); void lwip_mbed_tracef_warn(const char *fmt, ...); -void lwip_mbed_assert_fail(const char *msg, const char *func, const char *file, unsigned int line); +MBED_NORETURN void lwip_mbed_assert_fail(const char *msg, const char *func, const char *file, unsigned int line); #define LWIP_PLATFORM_DIAG(vars) lwip_mbed_tracef_debug vars #define LWIP_PLATFORM_DIAG_SEVERE(vars) lwip_mbed_tracef_error vars @@ -109,7 +109,7 @@ void lwip_mbed_assert_fail(const char *msg, const char *func, const char *file, #else // MBED_CONF_LWIP_USE_MBED_TRACE #include -void assert_printf(char *msg, int line, char *file); +MBED_NORETURN void assert_printf(char *msg, int line, char *file); /* Plaform specific diagnostic output */ #define LWIP_PLATFORM_DIAG(vars) printf vars diff --git a/features/lwipstack/lwip-sys/arch/lwip_sys_arch.c b/features/lwipstack/lwip-sys/arch/lwip_sys_arch.c index 20ad0b53804..e5afb99901c 100644 --- a/features/lwipstack/lwip-sys/arch/lwip_sys_arch.c +++ b/features/lwipstack/lwip-sys/arch/lwip_sys_arch.c @@ -589,7 +589,7 @@ void lwip_mbed_tracef_error(const char *fmt, ...) va_end(ap); } -void lwip_mbed_assert_fail(const char *msg, const char *func, const char *file, unsigned int line) +MBED_NORETURN void lwip_mbed_assert_fail(const char *msg, const char *func, const char *file, unsigned int line) { mbed_tracef(TRACE_LEVEL_ERROR, "lwIP", "Assertion failed: %s, function %s, file %s, line %u.", msg, func, file, line); exit(EXIT_FAILURE); // XXX how about abort? mbed_assert uses exit, so follow suit @@ -605,7 +605,7 @@ void lwip_mbed_assert_fail(const char *msg, const char *func, const char *file, \param[in] line Line number in file with error \param[in] file Filename with error */ -void assert_printf(char *msg, int line, char *file) { +MBED_NORETURN void assert_printf(char *msg, int line, char *file) { if (msg) error("%s:%d in file %s\n", msg, line, file); else diff --git a/hal/mbed_sleep_manager.c b/hal/mbed_sleep_manager.c index e0ce00c2163..03f678e826c 100644 --- a/hal/mbed_sleep_manager.c +++ b/hal/mbed_sleep_manager.c @@ -163,10 +163,6 @@ void sleep_manager_lock_deep_sleep_internal(void) if (deep_sleep_lock == USHRT_MAX) { core_util_critical_section_exit(); MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_OVERFLOW), "DeepSleepLock overflow (> USHRT_MAX)", deep_sleep_lock); - // When running sleep_manager tests, the mbed_error() is overridden - // and no longer calls mbed_halt_system(). Return to prevent - // execution of the following code. - return; } core_util_atomic_incr_u16(&deep_sleep_lock, 1); core_util_critical_section_exit(); @@ -178,10 +174,6 @@ void sleep_manager_unlock_deep_sleep_internal(void) if (deep_sleep_lock == 0) { core_util_critical_section_exit(); MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_UNDERFLOW), "DeepSleepLock underflow (< 0)", deep_sleep_lock); - // When running sleep_manager tests, the mbed_error() is overridden - // and no longer calls mbed_halt_system(). Return to prevent - // execution of the following code. - return; } core_util_atomic_decr_u16(&deep_sleep_lock, 1); core_util_critical_section_exit(); diff --git a/platform/mbed_assert.c b/platform/mbed_assert.c index 07a537f4ca6..bc1934461ad 100644 --- a/platform/mbed_assert.c +++ b/platform/mbed_assert.c @@ -20,7 +20,7 @@ #include "platform/mbed_critical.h" #include "platform/mbed_error.h" -void mbed_assert_internal(const char *expr, const char *file, int line) +MBED_NORETURN void mbed_assert_internal(const char *expr, const char *file, int line) { core_util_critical_section_enter(); mbed_error(MBED_ERROR_ASSERTION_FAILED, expr, 0, file, line); diff --git a/platform/mbed_assert.h b/platform/mbed_assert.h index f70159cc75a..4976c11b45f 100644 --- a/platform/mbed_assert.h +++ b/platform/mbed_assert.h @@ -24,6 +24,7 @@ #define MBED_ASSERT_H #include "mbed_preprocessor.h" +#include "mbed_toolchain.h" #ifdef __cplusplus extern "C" { @@ -37,7 +38,7 @@ extern "C" { * @param file File where assertation failed. * @param line Failing assertation line number. */ -void mbed_assert_internal(const char *expr, const char *file, int line); +MBED_NORETURN void mbed_assert_internal(const char *expr, const char *file, int line); #ifdef __cplusplus } diff --git a/platform/mbed_board.c b/platform/mbed_board.c index 91c50799471..59635d1d33c 100644 --- a/platform/mbed_board.c +++ b/platform/mbed_board.c @@ -21,7 +21,7 @@ #include "platform/mbed_retarget.h" #include "platform/mbed_critical.h" -WEAK void mbed_die(void) +WEAK MBED_NORETURN void mbed_die(void) { #if !defined (NRF51_H) && !defined(TARGET_EFM32) core_util_critical_section_enter(); diff --git a/platform/mbed_critical.c b/platform/mbed_critical.c index 59876db431c..320319ba637 100644 --- a/platform/mbed_critical.c +++ b/platform/mbed_critical.c @@ -100,6 +100,11 @@ void core_util_critical_section_exit(void) } } +void core_util_atomic_flag_clear(volatile core_util_atomic_flag *flagPtr) +{ + flagPtr->_flag = false; +} + #if MBED_EXCLUSIVE_ACCESS /* Supress __ldrex and __strex deprecated warnings - "#3731-D: intrinsic is deprecated" */ @@ -107,6 +112,15 @@ void core_util_critical_section_exit(void) #pragma diag_suppress 3731 #endif +bool core_util_atomic_flag_test_and_set(volatile core_util_atomic_flag *flagPtr) +{ + uint8_t currentValue; + do { + currentValue = __LDREXB(&flagPtr->_flag); + } while (__STREXB(true, &flagPtr->_flag)); + return currentValue; +} + bool core_util_atomic_cas_u8(volatile uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue) { do { @@ -204,6 +218,15 @@ uint32_t core_util_atomic_decr_u32(volatile uint32_t *valuePtr, uint32_t delta) #else +bool core_util_atomic_flag_test_and_set(volatile core_util_atomic_flag *flagPtr) +{ + core_util_critical_section_enter(); + uint8_t currentValue = flagPtr->_flag; + flagPtr->_flag = true; + core_util_critical_section_exit(); + return currentValue; +} + bool core_util_atomic_cas_u8(volatile uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue) { bool success; diff --git a/platform/mbed_critical.h b/platform/mbed_critical.h index 2c3a2d6099b..c4a510ca8ee 100644 --- a/platform/mbed_critical.h +++ b/platform/mbed_critical.h @@ -89,6 +89,43 @@ void core_util_critical_section_exit(void); */ bool core_util_in_critical_section(void); +/** + * A lock-free, primitive atomic flag. + * + * Emulate C11's atomic_flag. The flag is initially in an indeterminate state + * unless explicitly initialised with CORE_UTIL_ATOMIC_FLAG_INIT. + */ +typedef struct core_util_atomic_flag { + uint8_t _flag; +} core_util_atomic_flag; + +/** + * Initialiser for a core_util_atomic_flag. + * + * Example: + * ~~~ + * core_util_atomic_flag in_progress = CORE_UTIL_ATOMIC_FLAG_INIT; + * ~~~ + */ +#define CORE_UTIL_ATOMIC_FLAG_INIT { 0 } + +/** + * Atomic test and set. + * + * Atomically tests then sets the flag to true, returning the previous value. + * + * @param flagPtr Target flag being tested and set. + * @return The previous value. + */ +bool core_util_atomic_flag_test_and_set(volatile core_util_atomic_flag *flagPtr); + +/** + * Atomic clear. + * + * @param flagPtr Target flag being cleared. + */ +void core_util_atomic_flag_clear(volatile core_util_atomic_flag *flagPtr); + /** * Atomic compare and set. It compares the contents of a memory location to a * given value and, only if they are the same, modifies the contents of that diff --git a/platform/mbed_error.c b/platform/mbed_error.c index 578ac7d4653..21cf3fbe1b8 100644 --- a/platform/mbed_error.c +++ b/platform/mbed_error.c @@ -36,7 +36,8 @@ 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 uint8_t error_in_progress = 0; +static core_util_atomic_flag error_in_progress = CORE_UTIL_ATOMIC_FLAG_INIT; +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}; static mbed_error_ctx last_error_ctx = {0}; @@ -44,39 +45,43 @@ static mbed_error_hook_t error_hook = NULL; static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsigned int error_value, const char *filename, int line_number, void *caller); //Helper function to halt the system -static void mbed_halt_system(void) +static MBED_NORETURN void mbed_halt_system(void) { - //If not in ISR context exit, otherwise spin on WFI - if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) { + // Prevent recursion if halt is called again during halt attempt - try + // something simple instead. + if (core_util_atomic_flag_test_and_set(&halt_in_progress)) { + core_util_critical_section_enter(); + __DSB(); for (;;) { - __WFI(); + __WFE(); // Not WFI, as don't want to wake for pending interrupts } - } else { - //exit eventually calls mbed_die - exit(1); } -} - -WEAK void error(const char *format, ...) -{ - // Prevent recursion if error is called again - if (error_in_progress) { - return; + //If in ISR context, call mbed_die directly + if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) { + mbed_die(); } - //Call handle_error/print_error_report permanently setting error_in_progress flag - handle_error(MBED_ERROR_UNKNOWN, 0, NULL, 0, MBED_CALLER_ADDR()); - ERROR_REPORT(&last_error_ctx, "Fatal Run-time error", NULL, 0); - error_in_progress = 1; + // In normal context, try orderly exit(1), which eventually calls mbed_die + exit(1); +} + +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)) { + handle_error(MBED_ERROR_UNKNOWN, 0, NULL, 0, MBED_CALLER_ADDR()); + ERROR_REPORT(&last_error_ctx, "Fatal Run-time error", NULL, 0); #ifndef NDEBUG - va_list arg; - va_start(arg, format); - mbed_error_vprintf(format, arg); - va_end(arg); + va_list arg; + va_start(arg, format); + mbed_error_vprintf(format, arg); + va_end(arg); #endif - exit(1); + } + + mbed_halt_system(); } //Set an error status with the error handling system @@ -91,18 +96,6 @@ static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsign error_status = MBED_ERROR_INVALID_ARGUMENT; } - //Prevent corruption by holding out other callers - //and we also need this until we remove the "error" call completely - while (error_in_progress == 1); - - //Use critsect here, as we don't want inadvertant modification of this global variable - core_util_critical_section_enter(); - error_in_progress = 1; - core_util_critical_section_exit(); - - //Increment error count - error_count++; - //Clear the context capturing buffer memset(¤t_error_ctx, 0, sizeof(mbed_error_ctx)); //Capture error information @@ -126,6 +119,12 @@ static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsign current_error_ctx.error_line_number = line_number; #endif + //Prevent corruption by holding out other callers + core_util_critical_section_enter(); + + //Increment error count + error_count++; + //Capture the fist system error and store it if (error_count == 1) { //first error memcpy(&first_error_ctx, ¤t_error_ctx, sizeof(mbed_error_ctx)); @@ -144,7 +143,7 @@ static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsign error_hook(&last_error_ctx); } - error_in_progress = 0; + core_util_critical_section_exit(); return MBED_SUCCESS; } @@ -170,25 +169,25 @@ int mbed_get_error_count(void) return error_count; } -//Sets a fatal error +//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) { return handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR()); } //Sets a fatal error, this function is marked WEAK to be able to override this for some tests -WEAK 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) +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) { - //set the error reported and then halt the system - if (MBED_SUCCESS != handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR())) { - return MBED_ERROR_FAILED_OPERATION; + // Prevent recursion if error is called again during store+print attempt + if (!core_util_atomic_flag_test_and_set(&error_in_progress)) { + //set the error reported + (void) handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR()); + + //On fatal errors print the error context/report + ERROR_REPORT(&last_error_ctx, error_msg, filename, line_number); } - //On fatal errors print the error context/report - ERROR_REPORT(&last_error_ctx, error_msg, filename, line_number); mbed_halt_system(); - - return MBED_ERROR_FAILED_OPERATION; } //Register an application defined callback with error handling diff --git a/platform/mbed_error.h b/platform/mbed_error.h index 14adf03735c..71aa69c5c31 100644 --- a/platform/mbed_error.h +++ b/platform/mbed_error.h @@ -169,8 +169,7 @@ typedef int mbed_error_status_t; * @param error_status mbed_error_status_t status to be set(See mbed_error_status_t enum above for available error status values). * @param error_msg The error message to be printed out to STDIO/Serial. * @param error_value Value associated with the error status. This would depend on error code/error scenario. Only available with MBED_ERROR1 - * @return 0 or MBED_SUCCESS. - * MBED_ERROR_INVALID_ARGUMENT if called with invalid error status/codes + * @return Does not return * * @code * @@ -872,7 +871,7 @@ typedef struct _mbed_error_ctx { * */ -void error(const char *format, ...); +MBED_NORETURN void error(const char *format, ...); /** * Call this Macro to generate a mbed_error_status_t value for a System error @@ -979,8 +978,7 @@ int mbed_get_error_count(void); * @param error_value Value associated with the error status. This would depend on error code/error scenario. * @param filename Name of the source file originating the error( Most callers can pass __FILE__ here ). * @param line_number The line number of the source file originating the error( Most callers can pass __LINE__ here ) . - * @return 0 or MBED_SUCCESS. - * MBED_ERROR_INVALID_ARGUMENT if called with invalid error status/codes + * @return Does not return. * * @code * @@ -990,7 +988,7 @@ int mbed_get_error_count(void); * * @note See MBED_WARNING/MBED_ERROR macros which provides a wrapper on this API */ -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); +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); /** * Registers an application defined error callback with the error handling system. diff --git a/platform/mbed_interface.h b/platform/mbed_interface.h index b569d952bca..21bd4029334 100644 --- a/platform/mbed_interface.h +++ b/platform/mbed_interface.h @@ -121,7 +121,7 @@ void mbed_mac_address(char *mac); /** Cause the mbed to flash the BLOD (Blue LEDs Of Death) sequence */ -void mbed_die(void); +MBED_NORETURN void mbed_die(void); /** Print out an error message. This is typically called when * handling a crash. diff --git a/platform/mbed_power_mgmt.h b/platform/mbed_power_mgmt.h index fa7c63cfc55..80d3d8b0bda 100644 --- a/platform/mbed_power_mgmt.h +++ b/platform/mbed_power_mgmt.h @@ -46,8 +46,8 @@ extern "C" { * * # Defined behavior * * The lock is a counter - * * The lock can be locked up to USHRT_MAX - Verified by ::test_lock_eq_ushrt_max and ::test_lock_gt_ushrt_max - * * The lock has to be equally unlocked as locked - Verified by ::test_lone_unlock and ::test_lock_eq_ushrt_max + * * The lock can be locked up to USHRT_MAX - Verified by ::test_lock_eq_ushrt_max + * * The lock has to be equally unlocked as locked - Verified by ::test_lock_eq_ushrt_max * * The function sleep_manager_lock_deep_sleep_internal() locks the automatic deep mode selection - Verified by ::test_lock_unlock * * The function sleep_manager_unlock_deep_sleep_internal() unlocks the automatic deep mode selection - Verified by ::test_lock_unlock * * The function sleep_manager_sleep_auto() chooses the sleep or deep sleep modes based on the lock - Verified by ::test_sleep_auto diff --git a/rtos/TARGET_CORTEX/mbed_rtx_handlers.c b/rtos/TARGET_CORTEX/mbed_rtx_handlers.c index f0b2ad7402d..8bc395cba36 100644 --- a/rtos/TARGET_CORTEX/mbed_rtx_handlers.c +++ b/rtos/TARGET_CORTEX/mbed_rtx_handlers.c @@ -22,6 +22,7 @@ #include "mbed_interface.h" #include "RTX_Config.h" #include "rtos/rtos_handlers.h" +#include "rtos/rtos_idle.h" #ifdef RTE_Compiler_EventRecorder #include "EventRecorder.h" // Keil::Compiler:Event Recorder @@ -30,8 +31,6 @@ #define EvtRtxThreadTerminate EventID(EventLevelAPI, 0xF2U, 0x1AU) #endif -extern void rtos_idle_loop(void); - static void (*terminate_hook)(osThreadId_t id); static void thread_terminate_hook(osThreadId_t id) @@ -48,9 +47,7 @@ void rtos_attach_thread_terminate_hook(void (*fptr)(osThreadId_t id)) __NO_RETURN void osRtxIdleThread(void *argument) { - for (;;) { - rtos_idle_loop(); - } + rtos_idle_loop(); } __NO_RETURN uint32_t osRtxErrorNotify(uint32_t code, void *object_id) diff --git a/rtos/TARGET_CORTEX/mbed_rtx_idle.cpp b/rtos/TARGET_CORTEX/mbed_rtx_idle.cpp index f300e7e1e93..3fa9417f1f3 100644 --- a/rtos/TARGET_CORTEX/mbed_rtx_idle.cpp +++ b/rtos/TARGET_CORTEX/mbed_rtx_idle.cpp @@ -28,9 +28,10 @@ #include "mbed_assert.h" #include #include "rtx_os.h" + +/* Everything in rtx_lib.h, and provided by this file, has C linkage */ extern "C" { #include "rtx_lib.h" -} using namespace mbed; @@ -136,10 +137,12 @@ void rtos_attach_idle_hook(void (*fptr)(void)) } } -extern "C" void rtos_idle_loop(void) +MBED_NORETURN void rtos_idle_loop(void) { //Continuously call the idle hook function pointer while (1) { idle_hook_fptr(); } } + +} // extern "C" diff --git a/rtos/rtos_idle.h b/rtos/rtos_idle.h index c2894c23e30..965ba0f51d0 100644 --- a/rtos/rtos_idle.h +++ b/rtos/rtos_idle.h @@ -25,6 +25,7 @@ #ifndef RTOS_IDLE_H #define RTOS_IDLE_H +#include "mbed_toolchain.h" #include #ifdef __cplusplus @@ -41,6 +42,10 @@ extern "C" { @param fptr Hook function pointer. */ void rtos_attach_idle_hook(void (*fptr)(void)); + +/** @private */ +MBED_NORETURN void rtos_idle_loop(void); + /** @}*/ #ifdef __cplusplus