Skip to content

Commit

Permalink
spinlock: inline no trace implement to save the code size
Browse files Browse the repository at this point in the history
remove duplicate logic

nsh/smp:

before:
$ size nuttx
   text	   data	    bss	    dec	    hex	filename
 417211	   6528	  13216	 436955	  6aadb	nuttx

after:
$ size nuttx
   text	   data	    bss	    dec	    hex	filename
 417403	   6528	  13216	 437147	  6ab9b	nuttx

Signed-off-by: chao an <[email protected]>
  • Loading branch information
anchao committed Aug 4, 2024
1 parent 8f3e1e8 commit 3497911
Showing 1 changed file with 65 additions and 110 deletions.
175 changes: 65 additions & 110 deletions include/nuttx/spinlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,15 +223,14 @@ static inline spinlock_t up_testset(FAR volatile spinlock_t *lock)
#ifdef CONFIG_HAVE_INLINE_SPINLOCK

/****************************************************************************
* Name: spin_lock
* 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 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.
* 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.
Expand All @@ -245,44 +244,33 @@ static inline spinlock_t up_testset(FAR volatile spinlock_t *lock)
*
****************************************************************************/

static inline_function void spin_lock(FAR volatile spinlock_t *lock)
static inline_function void spin_lock_wo_note(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 */
#else /* CONFIG_TICKET_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
* Name: spin_lock
*
* 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.
* 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.
Expand All @@ -296,30 +284,31 @@ static inline_function void spin_lock(FAR volatile spinlock_t *lock)
*
****************************************************************************/

static inline_function void spin_lock_wo_note(FAR volatile spinlock_t *lock)
static inline_function void spin_lock(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();
}
/* Notify that we are waiting for a spinlock */

SP_DMB();
sched_note_spinlock_lock(lock);

/* Lock without trace note */

spin_lock_wo_note(lock);

/* Notify that we have the spinlock */

sched_note_spinlock_locked(lock);
}

/****************************************************************************
* Name: spin_trylock
* 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.
*
Expand All @@ -332,15 +321,9 @@ static inline_function void spin_lock_wo_note(FAR volatile spinlock_t *lock)
*
****************************************************************************/

static inline_function bool spin_trylock(FAR volatile spinlock_t *lock)
static inline_function bool
spin_trylock_wo_note(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);
Expand All @@ -365,34 +348,21 @@ static inline_function bool spin_trylock(FAR volatile spinlock_t *lock)
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
* Name: spin_trylock
*
* 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.
*
Expand All @@ -405,47 +375,42 @@ static inline_function bool spin_trylock(FAR volatile spinlock_t *lock)
*
****************************************************************************/

static inline_function bool
spin_trylock_wo_note(FAR volatile spinlock_t *lock)
static inline_function bool spin_trylock(FAR volatile spinlock_t *lock)
{
#ifdef CONFIG_TICKET_SPINLOCK
unsigned short ticket =
atomic_load((FAR atomic_ushort *)&lock->tickets.next);
bool locked;

spinlock_t oldval =
{
{
ticket, ticket
}
};
/* Notify that we are waiting for a spinlock */

spinlock_t newval =
sched_note_spinlock_lock(lock);

/* Try lock without trace note */

locked = spin_trylock_wo_note(lock);
if (locked)
{
{
ticket, ticket + 1
}
};
/* Notify that we have the spinlock */

if (!atomic_compare_exchange_strong((FAR atomic_uint *)&lock->value,
&oldval.value, newval.value))
#else /* CONFIG_TICKET_SPINLOCK */
if (up_testset(lock) == SP_LOCKED)
#endif /* CONFIG_TICKET_SPINLOCK */
sched_note_spinlock_locked(lock);
}
else
{
SP_DSB();
return false;
/* Notify that we abort for a spinlock */

sched_note_spinlock_abort(lock);
}

SP_DMB();
return true;
return locked;
}

/****************************************************************************
* Name: spin_unlock
* 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.
*
Expand All @@ -457,37 +422,25 @@ spin_trylock_wo_note(FAR volatile spinlock_t *lock)
*
****************************************************************************/

#ifdef __SP_UNLOCK_FUNCTION
static inline_function void spin_unlock(FAR volatile spinlock_t *lock)
static inline_function void
spin_unlock_wo_note(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
#ifdef CONFIG_TICKET_SPINLOCK
atomic_fetch_add((FAR atomic_ushort *)&lock->tickets.owner, 1);
# else
#else
*lock = SP_UNLOCKED;
# endif
#endif
SP_DSB();
SP_SEV();
}
#else
# define spin_unlock(l) do { *(l) = SP_UNLOCKED; } while (0)
#endif

/****************************************************************************
* Name: spin_unlock_wo_note
* Name: spin_unlock
*
* 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.
*
Expand All @@ -499,18 +452,20 @@ static inline_function void spin_unlock(FAR volatile spinlock_t *lock)
*
****************************************************************************/

static inline_function void
spin_unlock_wo_note(FAR volatile spinlock_t *lock)
#ifdef __SP_UNLOCK_FUNCTION
static inline_function void spin_unlock(FAR volatile spinlock_t *lock)
{
SP_DMB();
#ifdef CONFIG_TICKET_SPINLOCK
atomic_fetch_add((FAR atomic_ushort *)&lock->tickets.owner, 1);
/* Unlock without trace note */

spin_unlock_wo_note(lock);

/* Notify that we are unlocking the spinlock */

sched_note_spinlock_unlock(lock);
}
#else
*lock = SP_UNLOCKED;
# define spin_unlock(l) do { *(l) = SP_UNLOCKED; } while (0)
#endif
SP_DSB();
SP_SEV();
}

/****************************************************************************
* Name: spin_is_locked
Expand Down

0 comments on commit 3497911

Please sign in to comment.