Merged in masayuki2009/nuttx.nuttx/fix_up_sigdeliver_for_smp (pull request #1043)

arch: armv7-m: Fix a deadlock in up_sigdeliver() in SMP mode.

In previous implementation, up_disable_irq() was called before
recovering local context. However, I noticed a deadlock happens
in the following situation. For example, if up_sigdevliver() is
in progress on CPU0 and CPU1 has called up_cpu_paused to CPU0,
hence g_cpu_irqlock has been locked by CPU1, in this case,
we would see a deadlock in later call of enter_critical_section()
to restore irqcount.

To avoid this situation, we need to call enter_critical_section()
to break the deadlock.

Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>

Approved-by: Gregory Nutt <gnutt@nuttx.org>
This commit is contained in:
Masayuki Ishikawa 2019-10-04 12:40:26 +00:00 committed by Gregory Nutt
parent 7715ee71d2
commit cef90a3865

View File

@ -138,18 +138,28 @@ void up_sigdeliver(void)
* alter errno), then disable interrupts again and restore the original
* errno that is needed by the user logic (it is probably EINTR).
*
* REVISIT: In SMP mode up_irq_save() probably only disables interrupts
* on the local CPU. We do not want to call enter_critical_section()
* here, however, because we don't want this state to stick after the
* call to up_fullcontextrestore().
*
* I would prefer that all interrupts are disabled when
* up_fullcontextrestore() is called, but that may not be necessary.
*/
sinfo("Resuming\n");
/* Call enter_critical_section() to disable local interrupts before
* restoring local context.
*
* Here, we should not use up_irq_save() in SMP mode.
* For example, if we call up_irq_save() here and another CPU might
* have called up_cpu_pause() to this cpu, hence g_cpu_irqlock has
* been locked by the cpu, in this case, we would see a deadlock in
* later call of enter_critical_section() to restore irqcount.
* To avoid this situation, we need to call enter_critical_section().
*/
#ifdef CONFIG_SMP
(void)enter_critical_section();
#else
(void)up_irq_save();
#endif
/* Restore the saved errno value */
@ -182,7 +192,7 @@ void up_sigdeliver(void)
* spinlocks.
*/
DEBUGASSERT(rtcb->irqcount == 0);
DEBUGASSERT(rtcb->irqcount == 1);
while (rtcb->irqcount < saved_irqcount)
{
(void)enter_critical_section();