mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #8328 from kjbracey-arm/noreturn
Error path tightening: use MBED_NORETURN; add+use core_util_atomic_flagpull/8580/head
commit
5ed07c2dd4
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<uint32_t flags, uint32_t wait_ms>
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 <int32_t signals, uint32_t timeout, int32_t test_val>
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -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 <stdio.h>
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
//If in ISR context, call mbed_die directly
|
||||
if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
|
||||
mbed_die();
|
||||
}
|
||||
|
||||
// In normal context, try orderly exit(1), which eventually calls mbed_die
|
||||
exit(1);
|
||||
}
|
||||
|
||||
WEAK void error(const char *format, ...)
|
||||
WEAK MBED_NORETURN void error(const char *format, ...)
|
||||
{
|
||||
|
||||
// Prevent recursion if error is called again
|
||||
if (error_in_progress) {
|
||||
return;
|
||||
}
|
||||
|
||||
//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;
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -28,9 +28,10 @@
|
|||
#include "mbed_assert.h"
|
||||
#include <new>
|
||||
#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;
|
||||
|
||||
|
|
@ -151,10 +152,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"
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#ifndef RTOS_IDLE_H
|
||||
#define RTOS_IDLE_H
|
||||
|
||||
#include "mbed_toolchain.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#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
|
||||
|
|
|
|||
Loading…
Reference in New Issue