diff --git a/arch/arm/src/armv7-m/up_assert.c b/arch/arm/src/armv7-m/up_assert.c index b34cfc7395..11f29cd653 100644 --- a/arch/arm/src/armv7-m/up_assert.c +++ b/arch/arm/src/armv7-m/up_assert.c @@ -53,6 +53,7 @@ #include "up_arch.h" #include "sched/sched.h" +#include "irq/irq.h" #include "up_internal.h" /**************************************************************************** @@ -319,6 +320,12 @@ static void up_dumpstate(void) #endif +#ifdef CONFIG_SMP + /* Show the CPU number */ + + _alert("CPU%d:\n", up_cpu_index()); +#endif + /* Then dump the registers (if available) */ up_registerdump(); @@ -351,6 +358,12 @@ static void _up_assert(int errorcode) (void)up_irq_save(); for (; ; ) { +#ifdef CONFIG_SMP + /* Try (again) to stop activity on other CPUs */ + + (void)spin_trylock(&g_cpu_irqlock); +#endif + #ifdef CONFIG_ARCH_LEDS board_autoled_on(LED_PANIC); up_mdelay(250); diff --git a/arch/arm/src/armv7-m/up_schedulesigaction.c b/arch/arm/src/armv7-m/up_schedulesigaction.c index cf70662510..fb6a4c167c 100644 --- a/arch/arm/src/armv7-m/up_schedulesigaction.c +++ b/arch/arm/src/armv7-m/up_schedulesigaction.c @@ -165,6 +165,19 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) #ifdef CONFIG_BUILD_PROTECTED CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR; #endif + +#ifdef CONFIG_SMP + /* In an SMP configuration, the interrupt disable logic also + * involves spinlocks that are configured per the TCB irqcount + * field. This is logically equivalent to enter_critical_section(). + * The matching call to leave_critical_section() will be + * performed in up_sigdeliver(). + */ + + DEBUGASSERT(tcb->irqcount < INT16_MAX); + tcb->irqcount++; +#endif + /* And make sure that the saved context in the TCB is the same * as the interrupt return context. */ @@ -211,6 +224,19 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) #ifdef CONFIG_BUILD_PROTECTED tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR; #endif + +#ifdef CONFIG_SMP + /* In an SMP configuration, the interrupt disable logic also + * involves spinlocks that are configured per the TCB irqcount + * field. This is logically equivalent to enter_critical_section(); + * The matching leave_critical_section will be performed in + * The matching call to leave_critical_section() will be performed + * in up_sigdeliver(). + */ + + DEBUGASSERT(tcb->irqcount < INT16_MAX); + tcb->irqcount++; +#endif } } diff --git a/arch/arm/src/armv7-m/up_sigdeliver.c b/arch/arm/src/armv7-m/up_sigdeliver.c index 6169b51279..086ed882fc 100644 --- a/arch/arm/src/armv7-m/up_sigdeliver.c +++ b/arch/arm/src/armv7-m/up_sigdeliver.c @@ -124,9 +124,9 @@ void up_sigdeliver(void) /* Then restore the task interrupt state */ #ifdef CONFIG_ARMV7M_USEBASEPRI - up_irq_restore((uint8_t)regs[REG_BASEPRI]); + leave_critical_section((uint8_t)regs[REG_BASEPRI]); #else - up_irq_restore((uint16_t)regs[REG_PRIMASK]); + leave_critical_section((uint16_t)regs[REG_PRIMASK]); #endif /* Deliver the signal */ @@ -136,9 +136,18 @@ void up_sigdeliver(void) /* Output any debug messages BEFORE restoring errno (because they may * 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"); + (void)up_irq_save(); rtcb->pterrno = saved_errno;