mirror of https://github.com/ARMmbed/mbed-os.git
Fix potential race condition in critical section HAL API
Call underlying HAL implementation to enter critical section/disable interrupts before incrementing the global critical section counter. Modify HAL implementations to track first entrances to the critical section and only update the saved state on first enter.pull/5346/head
parent
a07c07fa63
commit
e14bee5209
|
@ -28,11 +28,13 @@ static union {
|
||||||
} _state = {0};
|
} _state = {0};
|
||||||
|
|
||||||
static bool _use_softdevice_routine = false;
|
static bool _use_softdevice_routine = false;
|
||||||
|
static bool _state_saved = false;
|
||||||
|
|
||||||
void hal_critical_section_enter(void)
|
void hal_critical_section_enter(void)
|
||||||
{
|
{
|
||||||
// Fetch the current state of interrupts
|
// Fetch the current state of interrupts
|
||||||
uint32_t primask = __get_PRIMASK();
|
uint32_t primask = __get_PRIMASK();
|
||||||
|
uint8_t temp_state = 0;
|
||||||
|
|
||||||
// If interrupts are enabled, try to use the soft device
|
// If interrupts are enabled, try to use the soft device
|
||||||
uint8_t sd_enabled;
|
uint8_t sd_enabled;
|
||||||
|
@ -40,8 +42,12 @@ void hal_critical_section_enter(void)
|
||||||
(sd_softdevice_is_enabled(&sd_enabled) == NRF_SUCCESS) &&
|
(sd_softdevice_is_enabled(&sd_enabled) == NRF_SUCCESS) &&
|
||||||
(sd_enabled == 1)) {
|
(sd_enabled == 1)) {
|
||||||
// If the softdevice can be used, use it.
|
// If the softdevice can be used, use it.
|
||||||
sd_nvic_critical_region_enter(&_state._sd_state);
|
sd_nvic_critical_region_enter(&temp_state);
|
||||||
_use_softdevice_routine = true;
|
_use_softdevice_routine = true;
|
||||||
|
|
||||||
|
if (_state_saved == false) {
|
||||||
|
_state._sd_state = temp_state;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// If interrupts are enabled, disable them.
|
// If interrupts are enabled, disable them.
|
||||||
if (primask == 0) {
|
if (primask == 0) {
|
||||||
|
@ -50,13 +56,20 @@ void hal_critical_section_enter(void)
|
||||||
|
|
||||||
// Store PRIMASK state, it will be restored when exiting critical
|
// Store PRIMASK state, it will be restored when exiting critical
|
||||||
// section.
|
// section.
|
||||||
_state._PRIMASK_state = primask;
|
|
||||||
_use_softdevice_routine = false;
|
_use_softdevice_routine = false;
|
||||||
|
|
||||||
|
if (_state_saved == false) {
|
||||||
|
_state._PRIMASK_state = primask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_state_saved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hal_critical_section_exit(void)
|
void hal_critical_section_exit(void)
|
||||||
{
|
{
|
||||||
|
_state_saved = false;
|
||||||
|
|
||||||
// Restore the state as it was prior to entering the critical section.
|
// Restore the state as it was prior to entering the critical section.
|
||||||
if (_use_softdevice_routine) {
|
if (_use_softdevice_routine) {
|
||||||
sd_nvic_critical_region_exit(_state._sd_state)
|
sd_nvic_critical_region_exit(_state._sd_state)
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
static volatile bool critical_interrupts_enabled = false;
|
static volatile bool critical_interrupts_enabled = false;
|
||||||
|
static volatile bool state_saved = false;
|
||||||
|
|
||||||
static bool are_interrupts_enabled(void)
|
static bool are_interrupts_enabled(void)
|
||||||
{
|
{
|
||||||
|
@ -34,17 +35,25 @@ static bool are_interrupts_enabled(void)
|
||||||
|
|
||||||
MBED_WEAK void hal_critical_section_enter(void)
|
MBED_WEAK void hal_critical_section_enter(void)
|
||||||
{
|
{
|
||||||
critical_interrupts_enabled = are_interrupts_enabled();
|
const bool interrupt_state = are_interrupts_enabled();
|
||||||
|
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
}
|
|
||||||
|
|
||||||
|
if (state_saved == true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
critical_interrupts_enabled = interrupt_state;
|
||||||
|
state_saved = true;
|
||||||
|
}
|
||||||
|
|
||||||
MBED_WEAK void hal_critical_section_exit()
|
MBED_WEAK void hal_critical_section_exit()
|
||||||
{
|
{
|
||||||
// Interrupts must be disabled on invoking an exit from a critical section
|
// Interrupts must be disabled on invoking an exit from a critical section
|
||||||
MBED_ASSERT(!are_interrupts_enabled());
|
MBED_ASSERT(!are_interrupts_enabled());
|
||||||
|
|
||||||
|
state_saved = false;
|
||||||
|
|
||||||
// Restore the IRQs to their state prior to entering the critical section
|
// Restore the IRQs to their state prior to entering the critical section
|
||||||
if (critical_interrupts_enabled == true) {
|
if (critical_interrupts_enabled == true) {
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
|
|
|
@ -66,11 +66,9 @@ void core_util_critical_section_enter(void)
|
||||||
MBED_ASSERT(critical_section_reentrancy_counter < UINT32_MAX);
|
MBED_ASSERT(critical_section_reentrancy_counter < UINT32_MAX);
|
||||||
#endif /* FEATURE_UVISOR */
|
#endif /* FEATURE_UVISOR */
|
||||||
|
|
||||||
if (critical_section_reentrancy_counter == 0) {
|
hal_critical_section_enter();
|
||||||
hal_critical_section_enter();
|
|
||||||
}
|
|
||||||
|
|
||||||
critical_section_reentrancy_counter++;
|
++critical_section_reentrancy_counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void core_util_critical_section_exit(void)
|
void core_util_critical_section_exit(void)
|
||||||
|
@ -85,7 +83,7 @@ void core_util_critical_section_exit(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
critical_section_reentrancy_counter--;
|
--critical_section_reentrancy_counter;
|
||||||
|
|
||||||
if (critical_section_reentrancy_counter == 0) {
|
if (critical_section_reentrancy_counter == 0) {
|
||||||
hal_critical_section_exit();
|
hal_critical_section_exit();
|
||||||
|
|
|
@ -16,16 +16,28 @@
|
||||||
*/
|
*/
|
||||||
#include "nrf_nvic.h"
|
#include "nrf_nvic.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h> // uint32_t, UINT32_MAX
|
#include <stdint.h> // uint32_t, UINT32_MAX
|
||||||
|
|
||||||
static uint8_t _sd_state = 0;
|
static uint8_t _sd_state = 0;
|
||||||
|
static volatile bool _state_saved = false;
|
||||||
|
|
||||||
void hal_critical_section_enter(void)
|
void hal_critical_section_enter(void)
|
||||||
{
|
{
|
||||||
sd_nvic_critical_region_enter(&_sd_state);
|
uint8_t temp_state = 0;
|
||||||
|
sd_nvic_critical_region_enter(&temp_state);
|
||||||
|
|
||||||
|
if (_state_saved == true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_sd_state = temp_state;
|
||||||
|
_state_saved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hal_critical_section_exit(void)
|
void hal_critical_section_exit(void)
|
||||||
{
|
{
|
||||||
|
_state_saved = false;
|
||||||
|
|
||||||
sd_nvic_critical_region_exit(_sd_state);
|
sd_nvic_critical_region_exit(_sd_state);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue