mirror of
https://github.com/apache/nuttx.git
synced 2026-06-04 14:53:47 +08:00
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:
committed by
Gregory Nutt
parent
7715ee71d2
commit
cef90a3865
@@ -138,18 +138,28 @@ void up_sigdeliver(void)
|
|||||||
* alter errno), then disable interrupts again and restore the original
|
* alter errno), then disable interrupts again and restore the original
|
||||||
* errno that is needed by the user logic (it is probably EINTR).
|
* 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
|
* I would prefer that all interrupts are disabled when
|
||||||
* up_fullcontextrestore() is called, but that may not be necessary.
|
* up_fullcontextrestore() is called, but that may not be necessary.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sinfo("Resuming\n");
|
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();
|
(void)up_irq_save();
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Restore the saved errno value */
|
/* Restore the saved errno value */
|
||||||
|
|
||||||
@@ -182,7 +192,7 @@ void up_sigdeliver(void)
|
|||||||
* spinlocks.
|
* spinlocks.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DEBUGASSERT(rtcb->irqcount == 0);
|
DEBUGASSERT(rtcb->irqcount == 1);
|
||||||
while (rtcb->irqcount < saved_irqcount)
|
while (rtcb->irqcount < saved_irqcount)
|
||||||
{
|
{
|
||||||
(void)enter_critical_section();
|
(void)enter_critical_section();
|
||||||
|
|||||||
Reference in New Issue
Block a user