Skip to content

Commit 94898a1

Browse files
authored
Merge pull request ARMmbed#10358 from kjbracey-arm/error_print_improvements
Error print improvements
2 parents c961a5d + b8e80dd commit 94898a1

File tree

8 files changed

+83
-24
lines changed

8 files changed

+83
-24
lines changed

drivers/UARTSerial.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ ssize_t UARTSerial::write_unbuffered(const char *buf_ptr, size_t length)
147147

148148
for (size_t data_written = 0; data_written < length; data_written++) {
149149
SerialBase::_base_putc(*buf_ptr++);
150-
data_written++;
151150
}
152151

153152
return length;

platform/mbed_assert.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
MBED_NORETURN void mbed_assert_internal(const char *expr, const char *file, int line)
2525
{
26-
core_util_critical_section_enter();
2726
mbed_error(MBED_ERROR_ASSERTION_FAILED, expr, 0, file, line);
2827
}
2928

platform/mbed_board.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,28 @@ void mbed_error_vprintf(const char *format, va_list arg)
7474

7575
void mbed_error_puts(const char *str)
7676
{
77+
// Writing the string to the console in a critical section is
78+
// potentially beneficial - for example in UARTSerial it
79+
// forces the "unbuffered" mode that makes sure all characters
80+
// go out now. If we made the call not in a critical section,
81+
// it would go to the software buffer and we would be reliant
82+
// on platform.stdio-flush-at-exit forcing a fsync before
83+
// entering mbed_die().
84+
//
85+
// But this may be the very first write to the console, and hence
86+
// require it to be initialized - doing this in a critical
87+
// section could be problematic. So we prime it outside the
88+
// critical section with a zero-length write - this forces
89+
// the initialization.
90+
//
91+
// It's still possible that we were in a critical section
92+
// or interrupt on entry anyway (eg if this is an error coming
93+
// from inside RTX), so in other areas of the system we suppress
94+
// things like mutex creation asserts and RTX traps while
95+
// an error is in progress, so that console initialization
96+
// may work.
97+
write(STDERR_FILENO, str, 0);
98+
7799
core_util_critical_section_enter();
78100
#if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES || MBED_CONF_PLATFORM_STDIO_CONVERT_TTY_NEWLINES
79101
char stdio_out_prev = '\0';

platform/mbed_error.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ static void print_error_report(const mbed_error_ctx *ctx, const char *, const ch
4545
#define ERROR_REPORT(ctx, error_msg, error_filename, error_line) ((void) 0)
4646
#endif
4747

48-
static core_util_atomic_flag error_in_progress = CORE_UTIL_ATOMIC_FLAG_INIT;
48+
static bool error_in_progress;
4949
static core_util_atomic_flag halt_in_progress = CORE_UTIL_ATOMIC_FLAG_INIT;
5050
static int error_count = 0;
5151
static mbed_error_ctx first_error_ctx = {0};
@@ -115,7 +115,7 @@ static MBED_NORETURN void mbed_halt_system(void)
115115
WEAK MBED_NORETURN void error(const char *format, ...)
116116
{
117117
// Prevent recursion if error is called again during store+print attempt
118-
if (!core_util_atomic_flag_test_and_set(&error_in_progress)) {
118+
if (!core_util_atomic_exchange_bool(&error_in_progress, true)) {
119119
handle_error(MBED_ERROR_UNKNOWN, 0, NULL, 0, MBED_CALLER_ADDR());
120120
ERROR_REPORT(&last_error_ctx, "Fatal Run-time error", NULL, 0);
121121

@@ -256,6 +256,12 @@ int mbed_get_error_count(void)
256256
return error_count;
257257
}
258258

259+
//Reads the fatal error occurred" flag
260+
bool mbed_get_error_in_progress(void)
261+
{
262+
return core_util_atomic_load_bool(&error_in_progress);
263+
}
264+
259265
//Sets a non-fatal error
260266
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)
261267
{
@@ -266,7 +272,7 @@ mbed_error_status_t mbed_warning(mbed_error_status_t error_status, const char *e
266272
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)
267273
{
268274
// Prevent recursion if error is called again during store+print attempt
269-
if (!core_util_atomic_flag_test_and_set(&error_in_progress)) {
275+
if (!core_util_atomic_exchange_bool(&error_in_progress, true)) {
270276
//set the error reported
271277
(void) handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR());
272278

platform/mbed_error.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#ifndef MBED_ERROR_H
2424
#define MBED_ERROR_H
2525

26+
#include <stdbool.h>
2627
#include "platform/mbed_retarget.h"
2728
#include "platform/mbed_toolchain.h"
2829

@@ -1039,6 +1040,13 @@ mbed_error_status_t mbed_get_last_error(void);
10391040
*/
10401041
int mbed_get_error_count(void);
10411042

1043+
/**
1044+
* Returns whether we are processing a fatal mbed error.
1045+
* @return bool Whether a fatal error has occurred.
1046+
*
1047+
*/
1048+
bool mbed_get_error_in_progress(void);
1049+
10421050
/**
10431051
* 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.
10441052
*

platform/mbed_interface.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,9 @@ MBED_NORETURN void mbed_die(void);
127127
/** Print out an error message. This is typically called when
128128
* handling a crash.
129129
*
130-
* @note Synchronization level: Interrupt safe
130+
* @note Synchronization level: Interrupt safe, as long as the
131+
* FileHandle::write of the stderr device is. See mbed_error_puts
132+
* for more information.
131133
* @note This uses an internal 128-byte buffer to format the string,
132134
* so the output may be truncated. If you need to write a potentially
133135
* long string, use mbed_error_puts.
@@ -145,7 +147,9 @@ void mbed_error_printf(const char *format, ...) MBED_PRINTF(1, 2);
145147
/** Print out an error message. Similar to mbed_error_printf
146148
* but uses a va_list.
147149
*
148-
* @note Synchronization level: Interrupt safe
150+
* @note Synchronization level: Interrupt safe, as long as the
151+
* FileHandle::write of the stderr device is. See mbed_error_puts
152+
* for more information.
149153
*
150154
* @param format C string that contains data stream to be printed.
151155
* @param arg Variable arguments list
@@ -160,7 +164,13 @@ void mbed_error_vprintf(const char *format, va_list arg) MBED_PRINTF(1, 0);
160164
* length. Unlike standard puts, but like standard fputs, this does not
161165
* append a '\n' character.
162166
*
163-
* @note Synchronization level: Interrupt safe
167+
* @note Synchronization level: Interrupt safe, as long as the
168+
* FileHandle::write of the stderr device is. The default
169+
* serial console is safe, either buffered or not. If the
170+
* console has not previously been initialized, an attempt
171+
* to use this from interrupt may during console initialization.
172+
* Special handling of `mbed_error` relaxes various system traps
173+
* to increase the chance of initialization working.
164174
*
165175
* @param str C string that contains data stream to be printed.
166176
*

rtos/Mutex.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ void Mutex::constructor(const char *name)
4747
attr.cb_size = sizeof(_obj_mem);
4848
attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
4949
_id = osMutexNew(&attr);
50-
MBED_ASSERT(_id);
50+
// To permit certain cases where a device may get constructed in
51+
// by the attempt to print an error in a fatal shutdown, let a
52+
// mutex construction error pass.
53+
MBED_ASSERT(_id || mbed_get_error_in_progress());
5154
}
5255

5356
osStatus Mutex::lock(void)
@@ -57,7 +60,7 @@ osStatus Mutex::lock(void)
5760
_count++;
5861
}
5962

60-
if (status != osOK) {
63+
if (status != osOK && !mbed_get_error_in_progress()) {
6164
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_MUTEX_LOCK_FAILED), "Mutex lock failed", status);
6265
}
6366

@@ -75,7 +78,7 @@ osStatus Mutex::lock(uint32_t millisec)
7578
(status == osErrorResource && millisec == 0) ||
7679
(status == osErrorTimeout && millisec != osWaitForever));
7780

78-
if (!success) {
81+
if (!success && !mbed_get_error_in_progress()) {
7982
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_MUTEX_LOCK_FAILED), "Mutex lock failed", status);
8083
}
8184

@@ -98,7 +101,7 @@ bool Mutex::trylock_for(uint32_t millisec)
98101
(status == osErrorResource && millisec == 0) ||
99102
(status == osErrorTimeout && millisec != osWaitForever));
100103

101-
if (!success) {
104+
if (!success && !mbed_get_error_in_progress()) {
102105
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_MUTEX_LOCK_FAILED), "Mutex lock failed", status);
103106
}
104107

@@ -121,15 +124,16 @@ bool Mutex::trylock_until(uint64_t millisec)
121124

122125
osStatus Mutex::unlock()
123126
{
124-
_count--;
125-
126127
osStatus status = osMutexRelease(_id);
128+
if (osOK == status) {
129+
_count--;
130+
}
127131

128-
if (status != osOK) {
132+
if (status != osOK && !mbed_get_error_in_progress()) {
129133
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_MUTEX_UNLOCK_FAILED), "Mutex unlock failed", status);
130134
}
131135

132-
return osOK;
136+
return status;
133137
}
134138

135139
osThreadId Mutex::get_owner()

rtos/TARGET_CORTEX/mbed_rtx_handlers.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -107,29 +107,40 @@ static const char *error_msg(int32_t status)
107107
}
108108
}
109109

110+
static void trap_rtx_error(unsigned int error_value, int32_t rtx_status, mbed_error_status_t error_status)
111+
{
112+
// Attempts to get the console for the first time while printing an error
113+
// may well cause a mutex error; in general let RTX calls fail during
114+
// an error condition.
115+
if (mbed_get_error_in_progress()) {
116+
return;
117+
}
118+
MBED_ERROR1(error_status, error_msg(rtx_status), error_value);
119+
}
120+
110121
void EvrRtxKernelError(int32_t status)
111122
{
112-
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_EVENT), error_msg(status), status);
123+
trap_rtx_error(status, status, MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_EVENT));
113124
}
114125

115126
void EvrRtxThreadError(osThreadId_t thread_id, int32_t status)
116127
{
117-
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_THREAD_EVENT), error_msg(status), thread_id);
128+
trap_rtx_error((unsigned int) thread_id, status, MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_THREAD_EVENT));
118129
}
119130

120131
void EvrRtxTimerError(osTimerId_t timer_id, int32_t status)
121132
{
122-
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_TIMER_EVENT), error_msg(status), timer_id);
133+
trap_rtx_error((unsigned int) timer_id, status, MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_TIMER_EVENT));
123134
}
124135

125136
void EvrRtxEventFlagsError(osEventFlagsId_t ef_id, int32_t status)
126137
{
127-
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_EVENT_FLAGS_EVENT), error_msg(status), ef_id);
138+
trap_rtx_error((unsigned int) ef_id, status, MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_EVENT_FLAGS_EVENT));
128139
}
129140

130141
void EvrRtxMutexError(osMutexId_t mutex_id, int32_t status)
131142
{
132-
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_MUTEX_EVENT), error_msg(status), mutex_id);
143+
trap_rtx_error((unsigned int) mutex_id, status, MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_MUTEX_EVENT));
133144
}
134145

135146
void EvrRtxSemaphoreError(osSemaphoreId_t semaphore_id, int32_t status)
@@ -139,17 +150,17 @@ void EvrRtxSemaphoreError(osSemaphoreId_t semaphore_id, int32_t status)
139150
return;
140151
}
141152

142-
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_SEMAPHORE_EVENT), error_msg(status), semaphore_id);
153+
trap_rtx_error((unsigned int) semaphore_id, status, MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_SEMAPHORE_EVENT));
143154
}
144155

145156
void EvrRtxMemoryPoolError(osMemoryPoolId_t mp_id, int32_t status)
146157
{
147-
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_MEMORY_POOL_EVENT), error_msg(status), mp_id);
158+
trap_rtx_error((unsigned int) mp_id, status, MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_MEMORY_POOL_EVENT));
148159
}
149160

150161
void EvrRtxMessageQueueError(osMessageQueueId_t mq_id, int32_t status)
151162
{
152-
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT), error_msg(status), mq_id);
163+
trap_rtx_error((unsigned int) mq_id, status, MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT));
153164
}
154165

155166
#endif

0 commit comments

Comments
 (0)