From ce42a9affc963a657fc0b7482f7e2d9a0b485d29 Mon Sep 17 00:00:00 2001 From: chao an Date: Mon, 14 Oct 2024 10:43:00 +0800 Subject: [PATCH] Revert "sched/spinlock: remove nesting spinlock support" This reverts commit 5aa13bc490ea2e5a0d7462dd0131f9218a35f56a. --- include/nuttx/spinlock.h | 35 +++++++++++++++++++++++++++++------ sched/irq/irq_spinlock.c | 4 ++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/include/nuttx/spinlock.h b/include/nuttx/spinlock.h index e484c233c0..8678dbef80 100644 --- a/include/nuttx/spinlock.h +++ b/include/nuttx/spinlock.h @@ -151,6 +151,10 @@ void sched_note_spinlock_unlock(FAR volatile spinlock_t *spinlock); extern volatile spinlock_t g_irq_spin; +/* Handles nested calls to spin_lock_irqsave and spin_unlock_irqrestore */ + +extern volatile uint8_t g_irq_spin_count[CONFIG_SMP_NCPUS]; + /**************************************************************************** * Name: up_testset * @@ -527,7 +531,14 @@ irqstate_t spin_lock_irqsave_wo_note(FAR volatile spinlock_t *lock) if (NULL == lock) { - spin_lock_wo_note(&g_irq_spin); + int me = this_cpu(); + if (0 == g_irq_spin_count[me]) + { + spin_lock_wo_note(&g_irq_spin); + } + + g_irq_spin_count[me]++; + DEBUGASSERT(0 != g_irq_spin_count[me]); } else { @@ -546,7 +557,10 @@ irqstate_t spin_lock_irqsave_wo_note(FAR volatile spinlock_t *lock) * Description: * If SMP is enabled: * If the argument lock is not specified (i.e. NULL), - * disable local interrupts and take the global spinlock (g_irq_spin). + * disable local interrupts and take the global spinlock (g_irq_spin) + * if the call counter (g_irq_spin_count[cpu]) equals to 0. Then the + * counter on the CPU is incremented to allow nested calls and return + * the interrupt state. * * If the argument lock is specified, * disable local interrupts and take the lock spinlock and return @@ -684,7 +698,14 @@ void spin_unlock_irqrestore_wo_note(FAR volatile spinlock_t *lock, { if (NULL == lock) { - spin_unlock_wo_note(&g_irq_spin); + int me = this_cpu(); + DEBUGASSERT(0 < g_irq_spin_count[me]); + g_irq_spin_count[me]--; + + if (0 == g_irq_spin_count[me]) + { + spin_unlock_wo_note(&g_irq_spin); + } } else { @@ -702,9 +723,11 @@ void spin_unlock_irqrestore_wo_note(FAR volatile spinlock_t *lock, * * Description: * If SMP is enabled: - * If the argument lock is not specified (i.e. NULL), release the - * spinlock (g_irq_spin) and restore the interrupt state as it was - * prior to the previous call to spin_lock_irqsave(NULL). + * If the argument lock is not specified (i.e. NULL), + * decrement the call counter (g_irq_spin_count[cpu]) and if it + * decrements to zero then release the spinlock (g_irq_spin) and + * restore the interrupt state as it was prior to the previous call to + * spin_lock_irqsave(NULL). * * If the argument lock is specified, release the lock and * restore the interrupt state as it was prior to the previous call to diff --git a/sched/irq/irq_spinlock.c b/sched/irq/irq_spinlock.c index 6204461a4c..5b20e77a5a 100644 --- a/sched/irq/irq_spinlock.c +++ b/sched/irq/irq_spinlock.c @@ -43,6 +43,10 @@ volatile spinlock_t g_irq_spin = SP_UNLOCKED; +/* Handles nested calls to spin_lock_irqsave and spin_unlock_irqrestore */ + +volatile uint8_t g_irq_spin_count[CONFIG_SMP_NCPUS]; + #ifdef CONFIG_RW_SPINLOCK /* Used for access control */