-
Notifications
You must be signed in to change notification settings - Fork 3k
Error path tightening: use MBED_NORETURN; add+use core_util_atomic_flag #8328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@c1728p9 - you originally put the silent-exit recursion check in. Does this "insta-death" alternative suit as an alternative? (I also note that |
Measured ROM saving is 464 bytes in a GCC_ARM K64F develop build of mbed-os-mesh-minimal. 604 bytes with ARM compiler. (My first test saved 200 Kbytes, due to me having an |
@kjbracey-arm the recursion check in mbed_halt_system was because in some cases error() led to a call to exit() which triggerd another error() and caused a loop. I think this happened when error() was called in interrupt context, but it has been a while. It may be safer to leave leave the One alternative to keeping |
platform/mbed_error.c
Outdated
{ | ||
|
||
// Prevent recursion if error is called again | ||
if (error_in_progress) { | ||
return; | ||
mbed_die(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we do mbed_die, previous error in progress will not be captured.
The code here is inconsistent - there's no recursion-stopping check on
Good point - that might need a specialised wait function. I also note the
Any idea what that's talking about? Presumably no longer relevant. Really don't want
The previous error presumably has already been recorded. Note that |
afb68a7
to
2bc975d
Compare
Right, started digging a bit deeper into this - separated out the "in progress" flags, and put in a "simple halt" alternative. |
@deepikabhavnani @bulislaw @c1728p9 @SenRamakri When y'all are available for a re-review. @kjbracey-arm This'll need to be rebased. |
Rebased. Reviewers - note that the commit message for the 2nd commit lists the changes and reasoning for stuff done to mbed_error exit paths. |
@SenRamakri @deepikabhavnani Before another rebase, please review. I'll review shortly as well |
* unless explicitly initialised with CORE_UTIL_ATOMIC_FLAG_INIT. | ||
*/ | ||
typedef struct core_util_atomic_flag { | ||
uint8_t _flag; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Query - Should atomic operations be extended to 16-bit and 32-bit flags as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The flag is inherently an opaque 1-bit true/false boolean from an API point of view - the 8-bit storage is an implementation detail.
And I'm using uint8_t
because the LDREXB function/intrinsic takes uint8_t *
.
It would probably be okay to have a bool
there and cast the pointer for LDREXB, but I hate casts. This way makes the code look neater, and means I'm not accidentally invoking undefined behaviour.
Only downside is that the compiler will insist on adding an extra instruction when I assign the _flag
to the bool
output of test-and-set - it thinks it needs to ensure all values from 1-255 come out as 1, when we know the thing can only be holding 0 or 1 in the first place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes look good to me, but PR header and commits do not match. We have 3 commits here and header does not say anything about new atomic API's core_util_atomic_flag_test_and_set
and core_util_atomic_flag_clear
@AnotherButler - Handbook update needed as well
Will start CI since it's quite light at the moment, but this needs a rebase first. |
@bulislaw @SenRamakri Any thoughts? |
@ARMmbed/mbed-os-maintainers It looks like this PR could come into the next patch release, and would probably help the author(s) of #8496, but this refactor adding new functionality. Thoughts? |
Exporter Build : FAILUREBuild number : 3078 |
Test : FAILUREBuild number : 3248 |
Pipe closed error, restarting /morph export-build However tests - I see there 2-4 tests failing across all targets and toolchains (just one exception) |
Test failures consistently around |
Wow. There are tests that define stub versions of That... won't work... Might be able to do something with a |
Exporter Build : SUCCESSBuild number : 3083 |
It will be too hard to try to intercept and continue from a trapped error once error functions are marked [[noreturn]], so make the error return tests conditional on error trapping being disabled.
Tests adjusted to not deliberately provoke |
Travis docs fails : |
Intercepting mbed_error will be too hard after mbed_error becomes [[noreturn]], so remove tests that do this.
An atomic flag primitive is sometimes wanted, and it is cumbersome to create it from the compare-and-swap operation - cumbersome enough that people often don't bother. Put in a core_util_atomic_flag that follows the C11/C++11 atomic_flag API, such that it could be mapped to it with #define later.
Various fixes in preparation for making sure error calls do not return. * Clear out handle_error's use of error_in_progress as a sort of spin lock; this is most likely to deadlock if ever activated, and conflicts with error's use of error_in_progress. Use a normal critical section lock. * Make error use same mbed_halt_system helper as mbed_error. * Make error's recursion check avoid print and proceed to halt, rather than returning. * Make mbed_error use error_in_progress to avoid recursion in same way as error() does. * Give mbed_halt_system its own recursion check in case of error in mbed_die - give it a simple fallback. * Make the in_progress things properly atomic, just in case.
Save some ROM space by putting MBED_NORETURN attributes on error functions and failed asserts. mbed_error was documented as returning an error code. It never actually could return, so documentation updated, but return type kept.
Don't need loops at two layers. Also tighten up slightly-invalid extern "C" markings.
/morph build |
Build : SUCCESSBuild number : 3500 Triggering tests/morph test |
Exporter Build : SUCCESSBuild number : 3116 |
Test : SUCCESSBuild number : 3283 |
Hi @kjbracey-arm, Could/should I tried calling it from our definition of
This generates the warning:
but this doesn't:
|
Yes it should. |
PR created. The warning you're getting is harmless - you know |
Description
Save some ROM space by putting MBED_NORETURN attributes on error functions and failed asserts.
As part of this, adjust error paths to make sure they don't return.
core_util_atomic_flag
added to support the above.See commit messages for more detail.
Fixes #8496.
Pull request type