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
Steven Cartmell 2017-12-19 13:35:43 +00:00
parent a07c07fa63
commit e14bee5209
4 changed files with 42 additions and 10 deletions

View File

@ -28,11 +28,13 @@ static union {
} _state = {0};
static bool _use_softdevice_routine = false;
static bool _state_saved = false;
void hal_critical_section_enter(void)
{
// Fetch the current state of interrupts
uint32_t primask = __get_PRIMASK();
uint8_t temp_state = 0;
// If interrupts are enabled, try to use the soft device
uint8_t sd_enabled;
@ -40,8 +42,12 @@ void hal_critical_section_enter(void)
(sd_softdevice_is_enabled(&sd_enabled) == NRF_SUCCESS) &&
(sd_enabled == 1)) {
// 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;
if (_state_saved == false) {
_state._sd_state = temp_state;
}
} else {
// If interrupts are enabled, disable them.
if (primask == 0) {
@ -50,13 +56,20 @@ void hal_critical_section_enter(void)
// Store PRIMASK state, it will be restored when exiting critical
// section.
_state._PRIMASK_state = primask;
_use_softdevice_routine = false;
if (_state_saved == false) {
_state._PRIMASK_state = primask;
}
}
_state_saved = true;
}
void hal_critical_section_exit(void)
{
_state_saved = false;
// Restore the state as it was prior to entering the critical section.
if (_use_softdevice_routine) {
sd_nvic_critical_region_exit(_state._sd_state)

View File

@ -21,6 +21,7 @@
#include <stdbool.h>
static volatile bool critical_interrupts_enabled = false;
static volatile bool state_saved = false;
static bool are_interrupts_enabled(void)
{
@ -34,17 +35,25 @@ static bool are_interrupts_enabled(void)
MBED_WEAK void hal_critical_section_enter(void)
{
critical_interrupts_enabled = are_interrupts_enabled();
const bool interrupt_state = are_interrupts_enabled();
__disable_irq();
}
if (state_saved == true) {
return;
}
critical_interrupts_enabled = interrupt_state;
state_saved = true;
}
MBED_WEAK void hal_critical_section_exit()
{
// Interrupts must be disabled on invoking an exit from a critical section
MBED_ASSERT(!are_interrupts_enabled());
state_saved = false;
// Restore the IRQs to their state prior to entering the critical section
if (critical_interrupts_enabled == true) {
__enable_irq();

View File

@ -66,11 +66,9 @@ void core_util_critical_section_enter(void)
MBED_ASSERT(critical_section_reentrancy_counter < UINT32_MAX);
#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)
@ -85,7 +83,7 @@ void core_util_critical_section_exit(void)
return;
}
critical_section_reentrancy_counter--;
--critical_section_reentrancy_counter;
if (critical_section_reentrancy_counter == 0) {
hal_critical_section_exit();

View File

@ -16,16 +16,28 @@
*/
#include "nrf_nvic.h"
#include <stdbool.h>
#include <stdint.h> // uint32_t, UINT32_MAX
static uint8_t _sd_state = 0;
static volatile bool _state_saved = false;
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)
{
_state_saved = false;
sd_nvic_critical_region_exit(_sd_state);
}