mirror of
https://github.com/apache/nuttx.git
synced 2026-05-29 20:56:47 +08:00
spinlock: add sched_lock to spin_lock_irqsave
reason: We aim to replace big locks with smaller ones. So we will use spin_lock_irqsave extensively to replace enter_critical_section in the subsequent process. We imitate the implementation of Linux by adding sched_lock to spin_lock_irqsave in order to address scenarios where sem_post occurs within spin_lock_irqsave, which can lead to spinlock failures and deadlocks. Signed-off-by: hujun5 <hujun5@xiaomi.com>
This commit is contained in:
+63
-15
@@ -233,6 +233,8 @@ static inline_function void raw_spin_lock(FAR volatile spinlock_t *lock)
|
|||||||
#ifdef CONFIG_SPINLOCK
|
#ifdef CONFIG_SPINLOCK
|
||||||
static inline_function void spin_lock(FAR volatile spinlock_t *lock)
|
static inline_function void spin_lock(FAR volatile spinlock_t *lock)
|
||||||
{
|
{
|
||||||
|
sched_lock();
|
||||||
|
|
||||||
/* Notify that we are waiting for a spinlock */
|
/* Notify that we are waiting for a spinlock */
|
||||||
|
|
||||||
sched_note_spinlock_lock(lock);
|
sched_note_spinlock_lock(lock);
|
||||||
@@ -245,6 +247,8 @@ static inline_function void spin_lock(FAR volatile spinlock_t *lock)
|
|||||||
|
|
||||||
sched_note_spinlock_locked(lock);
|
sched_note_spinlock_locked(lock);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
# define spin_lock(l) sched_lock()
|
||||||
#endif /* CONFIG_SPINLOCK */
|
#endif /* CONFIG_SPINLOCK */
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -313,6 +317,8 @@ static inline_function bool spin_trylock(FAR volatile spinlock_t *lock)
|
|||||||
{
|
{
|
||||||
bool locked;
|
bool locked;
|
||||||
|
|
||||||
|
sched_lock();
|
||||||
|
|
||||||
/* Notify that we are waiting for a spinlock */
|
/* Notify that we are waiting for a spinlock */
|
||||||
|
|
||||||
sched_note_spinlock_lock(lock);
|
sched_note_spinlock_lock(lock);
|
||||||
@@ -331,10 +337,13 @@ static inline_function bool spin_trylock(FAR volatile spinlock_t *lock)
|
|||||||
/* Notify that we abort for a spinlock */
|
/* Notify that we abort for a spinlock */
|
||||||
|
|
||||||
sched_note_spinlock_abort(lock);
|
sched_note_spinlock_abort(lock);
|
||||||
|
sched_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return locked;
|
return locked;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
# define spin_trylock(l) (sched_lock(), true)
|
||||||
#endif /* CONFIG_SPINLOCK */
|
#endif /* CONFIG_SPINLOCK */
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -400,10 +409,14 @@ static inline_function void spin_unlock(FAR volatile spinlock_t *lock)
|
|||||||
/* Notify that we are unlocking the spinlock */
|
/* Notify that we are unlocking the spinlock */
|
||||||
|
|
||||||
sched_note_spinlock_unlock(lock);
|
sched_note_spinlock_unlock(lock);
|
||||||
|
|
||||||
|
sched_unlock();
|
||||||
}
|
}
|
||||||
# else
|
# else
|
||||||
# define spin_unlock(l) do { *(l) = SP_UNLOCKED; } while (0)
|
# define spin_unlock(l) do { *(l) = SP_UNLOCKED; sched_unlock();} while (0)
|
||||||
# endif
|
# endif
|
||||||
|
#else
|
||||||
|
# define spin_unlock(l) sched_unlock()
|
||||||
#endif /* CONFIG_SPINLOCK */
|
#endif /* CONFIG_SPINLOCK */
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -456,15 +469,15 @@ irqstate_t raw_spin_lock_irqsave(FAR volatile spinlock_t *lock)
|
|||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* If SMP is enabled:
|
* If SMP is enabled:
|
||||||
* Disable local interrupts and take the lock spinlock and return
|
* Disable local interrupts, sched_lock and take the lock spinlock and
|
||||||
* the interrupt state.
|
* return the interrupt state.
|
||||||
*
|
*
|
||||||
* NOTE: This API is very simple to protect data (e.g. H/W register
|
* NOTE: This API is very simple to protect data (e.g. H/W register
|
||||||
* or internal data structure) in SMP mode. But do not use this API
|
* or internal data structure) in SMP mode. But do not use this API
|
||||||
* with kernel APIs which suspend a caller thread. (e.g. nxsem_wait)
|
* with kernel APIs which suspend a caller thread. (e.g. nxsem_wait)
|
||||||
*
|
*
|
||||||
* If SMP is not enabled:
|
* If SMP is not enabled:
|
||||||
* This function is equivalent to up_irq_save().
|
* This function is equivalent to up_irq_save() + sched_lock().
|
||||||
*
|
*
|
||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
* lock - Caller specific spinlock. not NULL.
|
* lock - Caller specific spinlock. not NULL.
|
||||||
@@ -485,9 +498,8 @@ irqstate_t spin_lock_irqsave(FAR volatile spinlock_t *lock)
|
|||||||
|
|
||||||
sched_note_spinlock_lock(lock);
|
sched_note_spinlock_lock(lock);
|
||||||
|
|
||||||
/* Lock without trace note */
|
|
||||||
|
|
||||||
flags = raw_spin_lock_irqsave(lock);
|
flags = raw_spin_lock_irqsave(lock);
|
||||||
|
sched_lock();
|
||||||
|
|
||||||
/* Notify that we have the spinlock */
|
/* Notify that we have the spinlock */
|
||||||
|
|
||||||
@@ -496,7 +508,13 @@ irqstate_t spin_lock_irqsave(FAR volatile spinlock_t *lock)
|
|||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define spin_lock_irqsave(l) ((void)(l), up_irq_save())
|
static inline_function
|
||||||
|
irqstate_t spin_lock_irqsave(FAR volatile spinlock_t *lock)
|
||||||
|
{
|
||||||
|
irqstate_t flags = up_irq_save();
|
||||||
|
sched_lock();
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -570,6 +588,7 @@ irqstate_t spin_lock_irqsave(FAR volatile spinlock_t *lock)
|
|||||||
({ \
|
({ \
|
||||||
(void)(l); \
|
(void)(l); \
|
||||||
f = up_irq_save(); \
|
f = up_irq_save(); \
|
||||||
|
sched_lock(); \
|
||||||
true; \
|
true; \
|
||||||
})
|
})
|
||||||
#endif /* CONFIG_SPINLOCK */
|
#endif /* CONFIG_SPINLOCK */
|
||||||
@@ -600,11 +619,11 @@ void raw_spin_unlock_irqrestore(FAR volatile spinlock_t *lock,
|
|||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* If SMP is enabled:
|
* If SMP is enabled:
|
||||||
* Release the lock and restore the interrupt state as it was prior
|
* Release the lock and restore the interrupt state, sched_unlock
|
||||||
* to the previous call to spin_lock_irqsave(lock).
|
* as it was prior to the previous call to spin_lock_irqsave(lock).
|
||||||
*
|
*
|
||||||
* If SMP is not enabled:
|
* If SMP is not enabled:
|
||||||
* This function is equivalent to up_irq_restore().
|
* This function is equivalent to up_irq_restore() + sched_unlock().
|
||||||
*
|
*
|
||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
* lock - Caller specific spinlock. not NULL
|
* lock - Caller specific spinlock. not NULL
|
||||||
@@ -625,12 +644,14 @@ void spin_unlock_irqrestore(FAR volatile spinlock_t *lock, irqstate_t flags)
|
|||||||
|
|
||||||
raw_spin_unlock_irqrestore(lock, flags);
|
raw_spin_unlock_irqrestore(lock, flags);
|
||||||
|
|
||||||
|
sched_unlock();
|
||||||
|
|
||||||
/* Notify that we are unlocking the spinlock */
|
/* Notify that we are unlocking the spinlock */
|
||||||
|
|
||||||
sched_note_spinlock_unlock(lock);
|
sched_note_spinlock_unlock(lock);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define spin_unlock_irqrestore(l, f) ((void)(l), up_irq_restore(f))
|
# define spin_unlock_irqrestore(l, f) ((void)(l), up_irq_restore(f), sched_unlock())
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_RW_SPINLOCK)
|
#if defined(CONFIG_RW_SPINLOCK)
|
||||||
@@ -679,6 +700,8 @@ void spin_unlock_irqrestore(FAR volatile spinlock_t *lock, irqstate_t flags)
|
|||||||
|
|
||||||
static inline_function void read_lock(FAR volatile rwlock_t *lock)
|
static inline_function void read_lock(FAR volatile rwlock_t *lock)
|
||||||
{
|
{
|
||||||
|
sched_lock();
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int old = atomic_read(lock);
|
int old = atomic_read(lock);
|
||||||
@@ -723,12 +746,15 @@ static inline_function void read_lock(FAR volatile rwlock_t *lock)
|
|||||||
|
|
||||||
static inline_function bool read_trylock(FAR volatile rwlock_t *lock)
|
static inline_function bool read_trylock(FAR volatile rwlock_t *lock)
|
||||||
{
|
{
|
||||||
|
sched_lock();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int old = atomic_read(lock);
|
int old = atomic_read(lock);
|
||||||
if (old <= RW_SP_WRITE_LOCKED)
|
if (old <= RW_SP_WRITE_LOCKED)
|
||||||
{
|
{
|
||||||
DEBUGASSERT(old == RW_SP_WRITE_LOCKED);
|
DEBUGASSERT(old == RW_SP_WRITE_LOCKED);
|
||||||
|
sched_unlock();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (atomic_cmpxchg(lock, &old, old + 1))
|
else if (atomic_cmpxchg(lock, &old, old + 1))
|
||||||
@@ -766,6 +792,8 @@ static inline_function void read_unlock(FAR volatile rwlock_t *lock)
|
|||||||
atomic_fetch_sub(lock, 1);
|
atomic_fetch_sub(lock, 1);
|
||||||
UP_DSB();
|
UP_DSB();
|
||||||
UP_SEV();
|
UP_SEV();
|
||||||
|
|
||||||
|
sched_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -797,6 +825,7 @@ static inline_function void write_lock(FAR volatile rwlock_t *lock)
|
|||||||
{
|
{
|
||||||
int zero = RW_SP_UNLOCKED;
|
int zero = RW_SP_UNLOCKED;
|
||||||
|
|
||||||
|
sched_lock();
|
||||||
while (!atomic_cmpxchg(lock, &zero, RW_SP_WRITE_LOCKED))
|
while (!atomic_cmpxchg(lock, &zero, RW_SP_WRITE_LOCKED))
|
||||||
{
|
{
|
||||||
UP_DSB();
|
UP_DSB();
|
||||||
@@ -835,9 +864,11 @@ static inline_function bool write_trylock(FAR volatile rwlock_t *lock)
|
|||||||
{
|
{
|
||||||
int zero = RW_SP_UNLOCKED;
|
int zero = RW_SP_UNLOCKED;
|
||||||
|
|
||||||
|
sched_lock();
|
||||||
if (atomic_cmpxchg(lock, &zero, RW_SP_WRITE_LOCKED))
|
if (atomic_cmpxchg(lock, &zero, RW_SP_WRITE_LOCKED))
|
||||||
{
|
{
|
||||||
UP_DMB();
|
UP_DMB();
|
||||||
|
sched_unlock();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -872,6 +903,7 @@ static inline_function void write_unlock(FAR volatile rwlock_t *lock)
|
|||||||
atomic_set(lock, RW_SP_UNLOCKED);
|
atomic_set(lock, RW_SP_UNLOCKED);
|
||||||
UP_DSB();
|
UP_DSB();
|
||||||
UP_SEV();
|
UP_SEV();
|
||||||
|
sched_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -902,7 +934,15 @@ static inline_function void write_unlock(FAR volatile rwlock_t *lock)
|
|||||||
#ifdef CONFIG_SPINLOCK
|
#ifdef CONFIG_SPINLOCK
|
||||||
irqstate_t read_lock_irqsave(FAR rwlock_t *lock);
|
irqstate_t read_lock_irqsave(FAR rwlock_t *lock);
|
||||||
#else
|
#else
|
||||||
# define read_lock_irqsave(l) ((void)(l), up_irq_save())
|
irqstate_t inline_function read_lock_irqsave(FAR rwlock_t *lock)
|
||||||
|
{
|
||||||
|
irqstate_t ret;
|
||||||
|
|
||||||
|
ret = up_irq_save();
|
||||||
|
sched_lock();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -931,7 +971,7 @@ irqstate_t read_lock_irqsave(FAR rwlock_t *lock);
|
|||||||
#ifdef CONFIG_SPINLOCK
|
#ifdef CONFIG_SPINLOCK
|
||||||
void read_unlock_irqrestore(FAR rwlock_t *lock, irqstate_t flags);
|
void read_unlock_irqrestore(FAR rwlock_t *lock, irqstate_t flags);
|
||||||
#else
|
#else
|
||||||
# define read_unlock_irqrestore(l, f) ((void)(l), up_irq_restore(f))
|
# define read_unlock_irqrestore(l, f) ((void)(l), up_irq_restore(f), sched_unlock())
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -962,7 +1002,15 @@ void read_unlock_irqrestore(FAR rwlock_t *lock, irqstate_t flags);
|
|||||||
#ifdef CONFIG_SPINLOCK
|
#ifdef CONFIG_SPINLOCK
|
||||||
irqstate_t write_lock_irqsave(FAR rwlock_t *lock);
|
irqstate_t write_lock_irqsave(FAR rwlock_t *lock);
|
||||||
#else
|
#else
|
||||||
# define write_lock_irqsave(l) ((void)(l), up_irq_save())
|
static inline_function write_lock_irqsave(FAR rwlock_t *lock)
|
||||||
|
{
|
||||||
|
irqstate_t ret;
|
||||||
|
|
||||||
|
ret = up_irq_save();
|
||||||
|
sched_lock();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -991,7 +1039,7 @@ irqstate_t write_lock_irqsave(FAR rwlock_t *lock);
|
|||||||
#ifdef CONFIG_SPINLOCK
|
#ifdef CONFIG_SPINLOCK
|
||||||
void write_unlock_irqrestore(FAR rwlock_t *lock, irqstate_t flags);
|
void write_unlock_irqrestore(FAR rwlock_t *lock, irqstate_t flags);
|
||||||
#else
|
#else
|
||||||
# define write_unlock_irqrestore(l, f) ((void)(l), up_irq_restore(f))
|
# define write_unlock_irqrestore(l, f) ((void)(l), up_irq_restore(f), sched_unlock())
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* CONFIG_RW_SPINLOCK */
|
#endif /* CONFIG_RW_SPINLOCK */
|
||||||
|
|||||||
Reference in New Issue
Block a user