spin_lock: inline spin_lock

test:
We can use qemu for testing.
compiling
make distclean -j20; ./tools/configure.sh -l qemu-armv8a:nsh_smp ;make -j20
running
qemu-system-aarch64 -cpu cortex-a53 -smp 4 -nographic -machine virt,virtualization=on,gic-version=3 -net none -chardev stdio,id=con,mux=on -serial chardev:con -mon chardev=con,mode=readline -kernel ./nuttx
This commit is contained in:
hujun5 2024-07-03 15:10:49 +08:00 committed by Xiang Xiao
parent ae8ce535f3
commit a4fece3450
51 changed files with 358 additions and 596 deletions

View File

@ -37,6 +37,7 @@
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <nuttx/power/pm.h>
#ifdef CONFIG_SERIAL_TERMIOS

View File

@ -36,6 +36,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <arch/board/board.h>

View File

@ -37,6 +37,7 @@
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <nuttx/power/pm.h>
#ifdef CONFIG_SERIAL_TERMIOS

View File

@ -37,6 +37,7 @@
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#ifdef CONFIG_SERIAL_TERMIOS
# include <termios.h>

View File

@ -37,6 +37,7 @@
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#ifdef CONFIG_SERIAL_TERMIOS
# include <termios.h>

View File

@ -36,6 +36,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <arch/board/board.h>

View File

@ -64,6 +64,7 @@
#include <arch/board/board.h>
#include <nuttx/arch.h>
#include <nuttx/spinlock.h>
/****************************************************************************
* Pre-processor Definitions

View File

@ -36,6 +36,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <arch/board/board.h>

View File

@ -28,6 +28,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/spinlock.h>
#include "arm_internal.h"
#include "sam_gpio.h"

View File

@ -28,6 +28,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/spinlock.h>
#include "arm_internal.h"
#include "sam_pio.h"

View File

@ -37,6 +37,7 @@
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <arch/board/board.h>

View File

@ -37,6 +37,7 @@
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <arch/board/board.h>

View File

@ -28,6 +28,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/spinlock.h>
#include <arch/board/board.h>
#include "arm_internal.h"

View File

@ -38,6 +38,7 @@
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/power/pm.h>
#include <nuttx/spinlock.h>
#ifdef CONFIG_SERIAL_TERMIOS
# include <termios.h>

View File

@ -37,6 +37,7 @@
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <nuttx/power/pm.h>
#ifdef CONFIG_SERIAL_TERMIOS

View File

@ -37,6 +37,7 @@
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <nuttx/power/pm.h>
#ifdef CONFIG_SERIAL_TERMIOS

View File

@ -37,6 +37,7 @@
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <nuttx/power/pm.h>
#ifdef CONFIG_SERIAL_TERMIOS

View File

@ -37,6 +37,7 @@
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <nuttx/semaphore.h>
#include <nuttx/power/pm.h>

View File

@ -37,6 +37,7 @@
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <nuttx/power/pm.h>
#ifdef CONFIG_SERIAL_TERMIOS

View File

@ -38,6 +38,7 @@
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <nuttx/power/pm.h>
#ifdef CONFIG_SERIAL_TERMIOS

View File

@ -38,6 +38,7 @@
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <nuttx/power/pm.h>
#ifdef CONFIG_SERIAL_TERMIOS

View File

@ -36,6 +36,7 @@
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <nuttx/power/pm.h>
#include <arch/board/board.h>

View File

@ -38,6 +38,7 @@
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <nuttx/power/pm.h>
#ifdef CONFIG_SERIAL_TERMIOS

View File

@ -52,6 +52,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <arch/board/board.h>
#include <nuttx/spinlock.h>
#include "arm_internal.h"
#include "hardware/tms570_sci.h"

View File

@ -36,6 +36,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <arch/board/board.h>

View File

@ -40,6 +40,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <arch/board/board.h>

View File

@ -41,6 +41,7 @@
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <arch/board/board.h>

View File

@ -37,6 +37,7 @@
#include <nuttx/serial/serial.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/tioctl.h>
#include <nuttx/spinlock.h>
#include "bl602_lowputc.h"
#include "bl602_gpio.h"

View File

@ -36,6 +36,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <arch/board/board.h>

View File

@ -35,6 +35,7 @@
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include "chip.h"
#include "riscv_internal.h"

View File

@ -25,6 +25,7 @@
#include <nuttx/config.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include <sys/types.h>
#include <stdint.h>

View File

@ -36,6 +36,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <arch/board/board.h>

View File

@ -36,6 +36,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <arch/board/board.h>

View File

@ -36,6 +36,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <arch/board/board.h>

View File

@ -36,6 +36,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#ifdef CONFIG_SERIAL_TERMIOS
# include <termios.h>

View File

@ -41,6 +41,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/serial/serial.h>
#include <nuttx/spinlock.h>
#include <arch/board/board.h>

View File

@ -30,6 +30,7 @@
#include <arch/arch.h>
#include <arch/irq.h>
#include <nuttx/arch.h>
#include <nuttx/spinlock.h>
#include "init/init.h"

View File

@ -25,6 +25,7 @@
#include "xtensa.h"
#include <nuttx/config.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include <nuttx/analog/dac.h>
#include <debug.h>
#include "esp32_dac.h"

View File

@ -34,6 +34,7 @@
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include "xtensa.h"
#include "esp32s2_clockconfig.h"

View File

@ -29,6 +29,7 @@
#include <nuttx/arch.h>
#include <nuttx/board.h>
#include <nuttx/power/pm.h>
#include <nuttx/spinlock.h>
#include "xtensa.h"
#include "esp32s3_pm.h"

View File

@ -1170,6 +1170,27 @@ void sched_note_spinlock(FAR struct tcb_s *tcb,
note_add(*driver, &note, sizeof(struct note_spinlock_s));
}
}
void sched_note_spinlock_lock(FAR volatile spinlock_t *spinlock)
{
sched_note_spinlock(this_task(), spinlock, NOTE_SPINLOCK_LOCK);
}
void sched_note_spinlock_locked(FAR volatile spinlock_t *spinlock)
{
sched_note_spinlock(this_task(), spinlock, NOTE_SPINLOCK_LOCKED);
}
void sched_note_spinlock_abort(FAR volatile spinlock_t *spinlock)
{
sched_note_spinlock(this_task(), spinlock, NOTE_SPINLOCK_ABORT);
}
void sched_note_spinlock_unlock(FAR volatile spinlock_t *spinlock)
{
sched_note_spinlock(this_task(), spinlock, NOTE_SPINLOCK_UNLOCK);
}
#endif
#ifdef CONFIG_SCHED_INSTRUMENTATION_SYSCALL

View File

@ -42,6 +42,7 @@
#include <nuttx/serial/serial.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/uart_16550.h>
#include <nuttx/spinlock.h>
#include <arch/board/board.h>

View File

@ -41,6 +41,7 @@
#include <nuttx/mutex.h>
#include <nuttx/sched.h>
#include <nuttx/spawn.h>
#include <nuttx/spinlock.h>
#ifdef CONFIG_FDSAN
# include <android/fdsan.h>
@ -66,11 +67,11 @@ static FAR struct file *files_fget_by_index(FAR struct filelist *list,
FAR struct file *filep;
irqstate_t flags;
flags = spin_lock_irqsave(&list->fl_lock);
flags = spin_lock_irqsave(NULL);
filep = &list->fl_files[l1][l2];
spin_unlock_irqrestore(&list->fl_lock, flags);
spin_unlock_irqrestore(NULL, flags);
return filep;
}
@ -125,7 +126,7 @@ static int files_extend(FAR struct filelist *list, size_t row)
}
while (++i < row);
flags = spin_lock_irqsave(&list->fl_lock);
flags = spin_lock_irqsave(NULL);
/* To avoid race condition, if the file list is updated by other threads
* and list rows is greater or equal than temp list,
@ -134,7 +135,7 @@ static int files_extend(FAR struct filelist *list, size_t row)
if (orig_rows != list->fl_rows && list->fl_rows >= row)
{
spin_unlock_irqrestore(&list->fl_lock, flags);
spin_unlock_irqrestore(NULL, flags);
for (j = orig_rows; j < i; j++)
{
@ -156,7 +157,7 @@ static int files_extend(FAR struct filelist *list, size_t row)
list->fl_files = files;
list->fl_rows = row;
spin_unlock_irqrestore(&list->fl_lock, flags);
spin_unlock_irqrestore(NULL, flags);
if (tmp != NULL && tmp != &list->fl_prefile)
{
@ -484,13 +485,13 @@ int file_allocate_from_tcb(FAR struct tcb_s *tcb, FAR struct inode *inode,
/* Find free file */
flags = spin_lock_irqsave(&list->fl_lock);
flags = spin_lock_irqsave(NULL);
for (; ; i++, j = 0)
{
if (i >= list->fl_rows)
{
spin_unlock_irqrestore(&list->fl_lock, flags);
spin_unlock_irqrestore(NULL, flags);
ret = files_extend(list, i + 1);
if (ret < 0)
@ -498,7 +499,7 @@ int file_allocate_from_tcb(FAR struct tcb_s *tcb, FAR struct inode *inode,
return ret;
}
flags = spin_lock_irqsave(&list->fl_lock);
flags = spin_lock_irqsave(NULL);
}
do
@ -518,7 +519,7 @@ int file_allocate_from_tcb(FAR struct tcb_s *tcb, FAR struct inode *inode,
}
found:
spin_unlock_irqrestore(&list->fl_lock, flags);
spin_unlock_irqrestore(NULL, flags);
if (addref)
{

View File

@ -37,10 +37,10 @@
#include <nuttx/mutex.h>
#include <nuttx/semaphore.h>
#include <nuttx/spinlock.h>
#include <nuttx/mm/map.h>
#include <nuttx/spawn.h>
#include <nuttx/queue.h>
#include <nuttx/irq.h>
/****************************************************************************
* Pre-processor Definitions
@ -490,7 +490,6 @@ struct file
struct filelist
{
spinlock_t fl_lock; /* Manage access to the file list */
uint8_t fl_rows; /* The number of rows of fl_files array */
FAR struct file **fl_files; /* The pointer of two layer file descriptors array */

View File

@ -28,8 +28,30 @@
#include <nuttx/config.h>
#include <sys/types.h>
#include <assert.h>
#include <stdint.h>
#if defined(CONFIG_TICKET_SPINLOCK) || defined(CONFIG_RW_SPINLOCK)
# if !defined(__cplusplus)
# include <stdatomic.h>
# define CONFIG_HAVE_INLINE_SPINLOCK
# elif defined(__has_include) && __has_include(<atomic>)
extern "C++"
{
# include <atomic>
# define CONFIG_HAVE_INLINE_SPINLOCK
using std::atomic_int;
using std::atomic_load;
using std::atomic_fetch_add;
using std::atomic_fetch_sub;
using std::atomic_compare_exchange_strong;
}
# endif
#else
# define CONFIG_HAVE_INLINE_SPINLOCK
#endif
#include <nuttx/compiler.h>
#include <nuttx/irq.h>
#undef EXTERN
@ -123,6 +145,18 @@ typedef union spinlock_u spinlock_t;
* Public Function Prototypes
****************************************************************************/
#ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
void sched_note_spinlock_lock(FAR volatile spinlock_t *spinlock);
void sched_note_spinlock_locked(FAR volatile spinlock_t *spinlock);
void sched_note_spinlock_abort(FAR volatile spinlock_t *spinlock);
void sched_note_spinlock_unlock(FAR volatile spinlock_t *spinlock);
#else
# define sched_note_spinlock_lock(spinlock)
# define sched_note_spinlock_locked(spinlock)
# define sched_note_spinlock_abort(spinlock)
# define sched_note_spinlock_unlocked(spinlock)
#endif
/****************************************************************************
* Name: up_testset
*
@ -184,6 +218,8 @@ static inline spinlock_t up_testset(FAR volatile spinlock_t *lock)
/* void spin_lock_init(FAR spinlock_t *lock); */
#define spin_lock_init(l) do { *(l) = SP_UNLOCKED; } while (0)
#ifdef CONFIG_HAVE_INLINE_SPINLOCK
/****************************************************************************
* Name: spin_lock
*
@ -207,7 +243,34 @@ static inline spinlock_t up_testset(FAR volatile spinlock_t *lock)
*
****************************************************************************/
void spin_lock(FAR volatile spinlock_t *lock);
static inline_function void spin_lock(FAR volatile spinlock_t *lock)
{
#ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
/* Notify that we are waiting for a spinlock */
sched_note_spinlock_lock(lock);
#endif
#ifdef CONFIG_TICKET_SPINLOCK
unsigned short ticket =
atomic_fetch_add((FAR atomic_ushort *)&lock->tickets.next, 1);
while (atomic_load((FAR atomic_ushort *)&lock->tickets.owner) != ticket)
#else /* CONFIG_SPINLOCK */
while (up_testset(lock) == SP_LOCKED)
#endif
{
SP_DSB();
SP_WFE();
}
#ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
/* Notify that we have the spinlock */
sched_note_spinlock_locked(lock);
#endif
SP_DMB();
}
/****************************************************************************
* Name: spin_lock_wo_note
@ -231,7 +294,22 @@ void spin_lock(FAR volatile spinlock_t *lock);
*
****************************************************************************/
void spin_lock_wo_note(FAR volatile spinlock_t *lock);
static inline_function void spin_lock_wo_note(FAR volatile spinlock_t *lock)
{
#ifdef CONFIG_TICKET_SPINLOCK
unsigned short ticket =
atomic_fetch_add((FAR atomic_ushort *)&lock->tickets.next, 1);
while (atomic_load((FAR atomic_ushort *)&lock->tickets.owner) != ticket)
#else /* CONFIG_TICKET_SPINLOCK */
while (up_testset(lock) == SP_LOCKED)
#endif
{
SP_DSB();
SP_WFE();
}
SP_DMB();
}
/****************************************************************************
* Name: spin_trylock
@ -252,7 +330,56 @@ void spin_lock_wo_note(FAR volatile spinlock_t *lock);
*
****************************************************************************/
bool spin_trylock(FAR volatile spinlock_t *lock);
static inline_function bool spin_trylock(FAR volatile spinlock_t *lock)
{
#ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
/* Notify that we are waiting for a spinlock */
sched_note_spinlock_lock(lock);
#endif
#ifdef CONFIG_TICKET_SPINLOCK
unsigned short ticket =
atomic_load((FAR atomic_ushort *)&lock->tickets.next);
spinlock_t old =
{
{
ticket, ticket
}
};
spinlock_t new =
{
{
ticket, ticket + 1
}
};
if (!atomic_compare_exchange_strong((FAR atomic_uint *)&lock->value,
&old.value, new.value))
#else /* CONFIG_TICKET_SPINLOCK */
if (up_testset(lock) == SP_LOCKED)
#endif /* CONFIG_TICKET_SPINLOCK */
{
#ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
/* Notify that we abort for a spinlock */
sched_note_spinlock_abort(lock);
#endif
SP_DSB();
return false;
}
#ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
/* Notify that we have the spinlock */
sched_note_spinlock_locked(lock);
#endif
SP_DMB();
return true;
}
/****************************************************************************
* Name: spin_trylock_wo_note
@ -276,7 +403,40 @@ bool spin_trylock(FAR volatile spinlock_t *lock);
*
****************************************************************************/
bool spin_trylock_wo_note(FAR volatile spinlock_t *lock);
static inline_function bool
spin_trylock_wo_note(FAR volatile spinlock_t *lock)
{
#ifdef CONFIG_TICKET_SPINLOCK
unsigned short ticket =
atomic_load((FAR atomic_ushort *)&lock->tickets.next);
spinlock_t old =
{
{
ticket, ticket
}
};
spinlock_t new =
{
{
ticket, ticket + 1
}
};
if (!atomic_compare_exchange_strong((FAR atomic_uint *)&lock->value,
&old.value, new.value))
#else /* CONFIG_TICKET_SPINLOCK */
if (up_testset(lock) == SP_LOCKED)
#endif /* CONFIG_TICKET_SPINLOCK */
{
SP_DSB();
return false;
}
SP_DMB();
return true;
}
/****************************************************************************
* Name: spin_unlock
@ -296,7 +456,23 @@ bool spin_trylock_wo_note(FAR volatile spinlock_t *lock);
****************************************************************************/
#ifdef __SP_UNLOCK_FUNCTION
void spin_unlock(FAR volatile spinlock_t *lock);
static inline_function void spin_unlock(FAR volatile spinlock_t *lock)
{
# ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
/* Notify that we are unlocking the spinlock */
sched_note_spinlock_unlock(lock);
# endif
SP_DMB();
# ifdef CONFIG_TICKET_SPINLOCK
atomic_fetch_add((FAR atomic_ushort *)&lock->tickets.owner, 1);
# else
*lock = SP_UNLOCKED;
# endif
SP_DSB();
SP_SEV();
}
#else
# define spin_unlock(l) do { *(l) = SP_UNLOCKED; } while (0)
#endif
@ -321,7 +497,18 @@ void spin_unlock(FAR volatile spinlock_t *lock);
*
****************************************************************************/
void spin_unlock_wo_note(FAR volatile spinlock_t *lock);
static inline_function void
spin_unlock_wo_note(FAR volatile spinlock_t *lock)
{
SP_DMB();
#ifdef CONFIG_TICKET_SPINLOCK
atomic_fetch_add((FAR atomic_ushort *)&lock->tickets.owner, 1);
#else
*lock = SP_UNLOCKED;
#endif
SP_DSB();
SP_SEV();
}
/****************************************************************************
* Name: spin_is_locked
@ -502,7 +689,26 @@ void spin_unlock_irqrestore_wo_note(FAR spinlock_t *lock, irqstate_t flags);
*
****************************************************************************/
void read_lock(FAR volatile rwlock_t *lock);
static inline_function void read_lock(FAR volatile rwlock_t *lock)
{
while (true)
{
int old = atomic_load((FAR atomic_int *)lock);
if (old <= RW_SP_WRITE_LOCKED)
{
DEBUGASSERT(old == RW_SP_WRITE_LOCKED);
SP_DSB();
SP_WFE();
}
else if(atomic_compare_exchange_strong((FAR atomic_int *)lock,
&old, old + 1))
{
break;
}
}
SP_DMB();
}
/****************************************************************************
* Name: read_trylock
@ -528,7 +734,26 @@ void read_lock(FAR volatile rwlock_t *lock);
*
****************************************************************************/
bool read_trylock(FAR volatile rwlock_t *lock);
static inline_function bool read_trylock(FAR volatile rwlock_t *lock)
{
while (true)
{
int old = atomic_load((FAR atomic_int *)lock);
if (old <= RW_SP_WRITE_LOCKED)
{
DEBUGASSERT(old == RW_SP_WRITE_LOCKED);
return false;
}
else if (atomic_compare_exchange_strong((FAR atomic_int *)lock,
&old, old + 1))
{
break;
}
}
SP_DMB();
return true;
}
/****************************************************************************
* Name: read_unlock
@ -547,7 +772,15 @@ bool read_trylock(FAR volatile rwlock_t *lock);
*
****************************************************************************/
void read_unlock(FAR volatile rwlock_t *lock);
static inline_function void read_unlock(FAR volatile rwlock_t *lock)
{
DEBUGASSERT(atomic_load((FAR atomic_int *)lock) >= RW_SP_READ_LOCKED);
SP_DMB();
atomic_fetch_sub((FAR atomic_int *)lock, 1);
SP_DSB();
SP_SEV();
}
/****************************************************************************
* Name: write_lock
@ -574,7 +807,19 @@ void read_unlock(FAR volatile rwlock_t *lock);
*
****************************************************************************/
void write_lock(FAR volatile rwlock_t *lock);
static inline_function void write_lock(FAR volatile rwlock_t *lock)
{
int zero = RW_SP_UNLOCKED;
while (!atomic_compare_exchange_strong((FAR atomic_int *)lock,
&zero, RW_SP_WRITE_LOCKED))
{
SP_DSB();
SP_WFE();
}
SP_DMB();
}
/****************************************************************************
* Name: write_trylock
@ -601,7 +846,20 @@ void write_lock(FAR volatile rwlock_t *lock);
*
****************************************************************************/
bool write_trylock(FAR volatile rwlock_t *lock);
static inline_function bool write_trylock(FAR volatile rwlock_t *lock)
{
int zero = RW_SP_UNLOCKED;
if (atomic_compare_exchange_strong((FAR atomic_int *)lock,
&zero, RW_SP_WRITE_LOCKED))
{
SP_DMB();
return true;
}
SP_DSB();
return false;
}
/****************************************************************************
* Name: write_unlock
@ -620,7 +878,17 @@ bool write_trylock(FAR volatile rwlock_t *lock);
*
****************************************************************************/
void write_unlock(FAR volatile rwlock_t *lock);
static inline_function void write_unlock(FAR volatile rwlock_t *lock)
{
/* Ensure this cpu already get write lock */
DEBUGASSERT(atomic_load((FAR atomic_int *)lock) == RW_SP_WRITE_LOCKED);
SP_DMB();
atomic_store((FAR atomic_int *)lock, RW_SP_UNLOCKED);
SP_DSB();
SP_SEV();
}
/****************************************************************************
* Name: read_lock_irqsave
@ -767,6 +1035,7 @@ void write_unlock_irqrestore(FAR rwlock_t *lock, irqstate_t flags);
#endif
#endif /* CONFIG_RW_SPINLOCK */
#endif /* CONFIG_HAVE_INLINE_SPINLOCK */
#undef EXTERN
#if defined(__cplusplus)

View File

@ -34,6 +34,7 @@
#include <nuttx/fs/fs.h>
#include <nuttx/net/net.h>
#include <nuttx/sched.h>
#include <nuttx/spinlock.h>
#ifdef CONFIG_BINFMT_LOADABLE
# include <nuttx/binfmt/binfmt.h>

View File

@ -117,7 +117,7 @@ volatile uint8_t g_cpu_nestcount[CONFIG_SMP_NCPUS];
****************************************************************************/
#ifdef CONFIG_SMP
static bool irq_waitlock(int cpu)
static inline_function bool irq_waitlock(int cpu)
{
#ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
FAR struct tcb_s *tcb = current_task(cpu);

View File

@ -36,12 +36,4 @@ if(CONFIG_PRIORITY_INHERITANCE)
list(APPEND CSRCS sem_initialize.c sem_holder.c sem_setprotocol.c)
endif()
if(CONFIG_SPINLOCK)
list(APPEND CSRCS spinlock.c)
endif()
if(CONFIG_TICKET_SPINLOCK)
list(APPEND CSRCS spinlock.c)
endif()
target_sources(sched PRIVATE ${CSRCS})

View File

@ -28,10 +28,6 @@ ifeq ($(CONFIG_PRIORITY_INHERITANCE),y)
CSRCS += sem_initialize.c sem_holder.c sem_setprotocol.c
endif
ifeq ($(CONFIG_SPINLOCK),y)
CSRCS += spinlock.c
endif
# Include semaphore build support
DEPPATH += --dep-path semaphore

View File

@ -1,560 +0,0 @@
/****************************************************************************
* sched/semaphore/spinlock.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdatomic.h>
#include <sched.h>
#include <assert.h>
#include <nuttx/spinlock.h>
#include <nuttx/sched_note.h>
#include <arch/irq.h>
#if defined(CONFIG_TICKET_SPINLOCK) || defined(CONFIG_RW_SPINLOCK)
# include <stdatomic.h>
#endif
#include "sched/sched.h"
#if defined(CONFIG_SPINLOCK) || defined(CONFIG_TICKET_SPINLOCK)
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: spin_lock
*
* Description:
* If this CPU does not already hold the spinlock, then loop until the
* spinlock is successfully locked.
*
* This implementation is non-reentrant and is prone to deadlocks in
* the case that any logic on the same CPU attempts to take the lock
* more than once.
*
* Input Parameters:
* lock - A reference to the spinlock object to lock.
*
* Returned Value:
* None. When the function returns, the spinlock was successfully locked
* by this CPU.
*
* Assumptions:
* Not running at the interrupt level.
*
****************************************************************************/
void spin_lock(FAR volatile spinlock_t *lock)
{
#ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
/* Notify that we are waiting for a spinlock */
sched_note_spinlock(this_task(), lock, NOTE_SPINLOCK_LOCK);
#endif
#ifdef CONFIG_TICKET_SPINLOCK
unsigned short ticket =
atomic_fetch_add((FAR atomic_ushort *)&lock->tickets.next, 1);
while (atomic_load((FAR atomic_ushort *)&lock->tickets.owner) != ticket)
#else /* CONFIG_SPINLOCK */
while (up_testset(lock) == SP_LOCKED)
#endif
{
SP_DSB();
SP_WFE();
}
#ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
/* Notify that we have the spinlock */
sched_note_spinlock(this_task(), lock, NOTE_SPINLOCK_LOCKED);
#endif
SP_DMB();
}
/****************************************************************************
* Name: spin_lock_wo_note
*
* Description:
* If this CPU does not already hold the spinlock, then loop until the
* spinlock is successfully locked.
*
* This implementation is the same as the above spin_lock() except that
* it does not perform instrumentation logic.
*
* Input Parameters:
* lock - A reference to the spinlock object to lock.
*
* Returned Value:
* None. When the function returns, the spinlock was successfully locked
* by this CPU.
*
* Assumptions:
* Not running at the interrupt level.
*
****************************************************************************/
void spin_lock_wo_note(FAR volatile spinlock_t *lock)
{
#ifdef CONFIG_TICKET_SPINLOCK
unsigned short ticket =
atomic_fetch_add((FAR atomic_ushort *)&lock->tickets.next, 1);
while (atomic_load((FAR atomic_ushort *)&lock->tickets.owner) != ticket)
#else /* CONFIG_TICKET_SPINLOCK */
while (up_testset(lock) == SP_LOCKED)
#endif
{
SP_DSB();
SP_WFE();
}
SP_DMB();
}
/****************************************************************************
* Name: spin_trylock
*
* Description:
* Try once to lock the spinlock. Do not wait if the spinlock is already
* locked.
*
* Input Parameters:
* lock - A reference to the spinlock object to lock.
*
* Returned Value:
* false - Failure, the spinlock was already locked
* true - Success, the spinlock was successfully locked
*
* Assumptions:
* Not running at the interrupt level.
*
****************************************************************************/
bool spin_trylock(FAR volatile spinlock_t *lock)
{
#ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
/* Notify that we are waiting for a spinlock */
sched_note_spinlock(this_task(), lock, NOTE_SPINLOCK_LOCK);
#endif
#ifdef CONFIG_TICKET_SPINLOCK
unsigned short ticket =
atomic_load((FAR atomic_ushort *)&lock->tickets.next);
spinlock_t old =
{
{
ticket, ticket
}
};
spinlock_t new =
{
{
ticket, ticket + 1
}
};
if (!atomic_compare_exchange_strong((FAR atomic_uint *)&lock->value,
&old.value, new.value))
#else /* CONFIG_TICKET_SPINLOCK */
if (up_testset(lock) == SP_LOCKED)
#endif /* CONFIG_TICKET_SPINLOCK */
{
#ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
/* Notify that we abort for a spinlock */
sched_note_spinlock(this_task(), lock, NOTE_SPINLOCK_ABORT);
#endif
SP_DSB();
return false;
}
#ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
/* Notify that we have the spinlock */
sched_note_spinlock(this_task(), lock, NOTE_SPINLOCK_LOCKED);
#endif
SP_DMB();
return true;
}
/****************************************************************************
* Name: spin_trylock_wo_note
*
* Description:
* Try once to lock the spinlock. Do not wait if the spinlock is already
* locked.
*
* This implementation is the same as the above spin_trylock() except that
* it does not perform instrumentation logic.
*
* Input Parameters:
* lock - A reference to the spinlock object to lock.
*
* Returned Value:
* false - Failure, the spinlock was already locked
* true - Success, the spinlock was successfully locked
*
* Assumptions:
* Not running at the interrupt level.
*
****************************************************************************/
bool spin_trylock_wo_note(FAR volatile spinlock_t *lock)
{
#ifdef CONFIG_TICKET_SPINLOCK
unsigned short ticket =
atomic_load((FAR atomic_ushort *)&lock->tickets.next);
spinlock_t old =
{
{
ticket, ticket
}
};
spinlock_t new =
{
{
ticket, ticket + 1
}
};
if (!atomic_compare_exchange_strong((FAR atomic_uint *)&lock->value,
&old.value, new.value))
#else /* CONFIG_TICKET_SPINLOCK */
if (up_testset(lock) == SP_LOCKED)
#endif /* CONFIG_TICKET_SPINLOCK */
{
SP_DSB();
return false;
}
SP_DMB();
return true;
}
/****************************************************************************
* Name: spin_unlock
*
* Description:
* Release one count on a non-reentrant spinlock.
*
* Input Parameters:
* lock - A reference to the spinlock object to unlock.
*
* Returned Value:
* None.
*
* Assumptions:
* Not running at the interrupt level.
*
****************************************************************************/
#ifdef __SP_UNLOCK_FUNCTION
void spin_unlock(FAR volatile spinlock_t *lock)
{
#ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
/* Notify that we are unlocking the spinlock */
sched_note_spinlock(this_task(), lock, NOTE_SPINLOCK_UNLOCK);
#endif
SP_DMB();
#ifdef CONFIG_TICKET_SPINLOCK
atomic_fetch_add((FAR atomic_ushort *)&lock->tickets.owner, 1);
#else
*lock = SP_UNLOCKED;
#endif
SP_DSB();
SP_SEV();
}
#endif
/****************************************************************************
* Name: spin_unlock_wo_note
*
* Description:
* Release one count on a non-reentrant spinlock.
*
* This implementation is the same as the above spin_unlock() except that
* it does not perform instrumentation logic.
*
* Input Parameters:
* lock - A reference to the spinlock object to unlock.
*
* Returned Value:
* None.
*
* Assumptions:
* Not running at the interrupt level.
*
****************************************************************************/
void spin_unlock_wo_note(FAR volatile spinlock_t *lock)
{
SP_DMB();
#ifdef CONFIG_TICKET_SPINLOCK
atomic_fetch_add((FAR atomic_ushort *)&lock->tickets.owner, 1);
#else
*lock = SP_UNLOCKED;
#endif
SP_DSB();
SP_SEV();
}
#ifdef CONFIG_RW_SPINLOCK
/****************************************************************************
* Name: read_lock
*
* Description:
* If this task does not already hold the spinlock, then loop until the
* spinlock is successfully locked.
*
* This implementation is non-reentrant and set a bit of lock.
*
* The priority of reader is higher than writter if a reader hold the
* lock, a new reader can get its lock but writer can't get this lock.
*
* Input Parameters:
* lock - A reference to the spinlock object to lock.
*
* Returned Value:
* None. When the function returns, the spinlock was successfully locked
* by this CPU.
*
* Assumptions:
* Not running at the interrupt level.
*
****************************************************************************/
void read_lock(FAR volatile rwlock_t *lock)
{
while (true)
{
int old = atomic_load((FAR atomic_int *)lock);
if (old <= RW_SP_WRITE_LOCKED)
{
DEBUGASSERT(old == RW_SP_WRITE_LOCKED);
SP_DSB();
SP_WFE();
}
else if(atomic_compare_exchange_strong((FAR atomic_int *)lock,
&old, old + 1))
{
break;
}
}
SP_DMB();
}
/****************************************************************************
* Name: read_trylock
*
* Description:
* If this task does not already hold the spinlock, then try to get the
* lock.
*
* This implementation is non-reentrant and set a bit of lock.
*
* The priority of reader is higher than writter if a reader hold the
* lock, a new reader can get its lock but writer can't get this lock.
*
* Input Parameters:
* lock - A reference to the spinlock object to lock.
*
* Returned Value:
* false - Failure, the spinlock was already locked
* true - Success, the spinlock was successfully locked
*
* Assumptions:
* Not running at the interrupt level.
*
****************************************************************************/
bool read_trylock(FAR volatile rwlock_t *lock)
{
while (true)
{
int old = atomic_load((FAR atomic_int *)lock);
if (old <= RW_SP_WRITE_LOCKED)
{
DEBUGASSERT(old == RW_SP_WRITE_LOCKED);
return false;
}
else if (atomic_compare_exchange_strong((FAR atomic_int *)lock,
&old, old + 1))
{
break;
}
}
SP_DMB();
return true;
}
/****************************************************************************
* Name: read_unlock
*
* Description:
* Release a bit on a non-reentrant spinlock.
*
* Input Parameters:
* lock - A reference to the spinlock object to unlock.
*
* Returned Value:
* None.
*
* Assumptions:
* Not running at the interrupt level.
*
****************************************************************************/
void read_unlock(FAR volatile rwlock_t *lock)
{
DEBUGASSERT(atomic_load((FAR atomic_int *)lock) >= RW_SP_READ_LOCKED);
SP_DMB();
atomic_fetch_sub((FAR atomic_int *)lock, 1);
SP_DSB();
SP_SEV();
}
/****************************************************************************
* Name: write_lock
*
* Description:
* If this task does not already hold the spinlock, then loop until the
* spinlock is successfully locked.
*
* This implementation is non-reentrant and set all bit on lock to avoid
* readers and writers.
*
* The priority of reader is higher than writter if a reader hold the
* lock, a new reader can get its lock but writer can't get this lock.
*
* Input Parameters:
* lock - A reference to the spinlock object to lock.
*
* Returned Value:
* None. When the function returns, the spinlock was successfully locked
* by this CPU.
*
* Assumptions:
* Not running at the interrupt level.
*
****************************************************************************/
void write_lock(FAR volatile rwlock_t *lock)
{
int zero = RW_SP_UNLOCKED;
while (!atomic_compare_exchange_strong((FAR atomic_int *)lock,
&zero, RW_SP_WRITE_LOCKED))
{
SP_DSB();
SP_WFE();
}
SP_DMB();
}
/****************************************************************************
* Name: write_trylock
*
* Description:
* If this task does not already hold the spinlock, then loop until the
* spinlock is successfully locked.
*
* This implementation is non-reentrant and set all bit on lock to avoid
* readers and writers.
*
* The priority of reader is higher than writter if a reader hold the
* lock, a new reader can get its lock but writer can't get this lock.
*
* Input Parameters:
* lock - A reference to the spinlock object to lock.
*
* Returned Value:
* false - Failure, the spinlock was already locked
* true - Success, the spinlock was successfully locked
*
* Assumptions:
* Not running at the interrupt level.
*
****************************************************************************/
bool write_trylock(FAR volatile rwlock_t *lock)
{
int zero = RW_SP_UNLOCKED;
if (atomic_compare_exchange_strong((FAR atomic_int *)lock,
&zero, RW_SP_WRITE_LOCKED))
{
SP_DMB();
return true;
}
SP_DSB();
return false;
}
/****************************************************************************
* Name: write_unlock
*
* Description:
* Release write lock on a non-reentrant spinlock.
*
* Input Parameters:
* lock - A reference to the spinlock object to unlock.
*
* Returned Value:
* None.
*
* Assumptions:
* Not running at the interrupt level.
*
****************************************************************************/
void write_unlock(FAR volatile rwlock_t *lock)
{
/* Ensure this cpu already get write lock */
DEBUGASSERT(atomic_load((FAR atomic_int *)lock) == RW_SP_WRITE_LOCKED);
SP_DMB();
atomic_store((FAR atomic_int *)lock, RW_SP_UNLOCKED);
SP_DSB();
SP_SEV();
}
#endif /* CONFIG_RW_SPINLOCK */
#endif /* CONFIG_SPINLOCK */

View File

@ -23,6 +23,8 @@
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/spinlock.h>
#include "signal/signal.h"
/****************************************************************************