Skip to content

Commit

Permalink
Fix race condition in sleep for high-priority interrupts.
Browse files Browse the repository at this point in the history
  • Loading branch information
AriZuu committed Jan 1, 2017
1 parent 6e4605b commit c1cd3e2
Showing 1 changed file with 30 additions and 4 deletions.
34 changes: 30 additions & 4 deletions ports/cortex-m/arch_c.c
Expand Up @@ -595,10 +595,6 @@ void p_pos_powerSleep()
#endif
#endif

// Ensure flag that __WFE waits for is not set yet
__SEV();
__WFE();

#if POSCFG_FEATURE_TICKLESS

UVAR_t nextWake = c_pos_nextWakeup();
Expand All @@ -618,9 +614,39 @@ void p_pos_powerSleep()

#endif

/*
* It is important that NO interrupt occurs during __WFE flag
* manipulation and after SLEEPONEXIT bit is set before *all*
* interrupts are enabled. Otherwise a high priority interrupt
* (one that higher priority than pico]OS interrupts might
* occur and put system to sleep before pico]OS -compatible
* interrupts are enabled.
*/
#if __CORTEX_M >= 3 || PORTCFG_NVIC_SCHED_LOCK

__disable_irq();

#endif

// Ensure flag that __WFE waits for is not set yet
__SEV();
__WFE();
SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk; // Sleep after interrupt

/*
* Now we can be sure that __WFE flag is set by next interrupt that
* clears SLEEPONEXIT before completing. It is safe to allow interrupts
* again. For Cortex-M0, portSchedUnlock will turn PRIMASK off. For
* M3/M4, it alters only BASEPRI so PRIMASK must be cleared separately.
*/
portSchedUnlock(0);

#if __CORTEX_M >= 3

__enable_irq();

#endif

__DSB();
__WFE();
portSchedLock();
Expand Down

0 comments on commit c1cd3e2

Please sign in to comment.