Skip to content

Commit

Permalink
shced:sem: replace mutex with spinlock
Browse files Browse the repository at this point in the history
The overhead of spinlok is less than mutext (mutex need to call
enter_critical section.)
After this patch, `down_write_trylock` and `down_read_trylock` can be
use in interrupt context.

The instruction is protected with mutex only one instruction so using
spinlock is better.

Signed-off-by: TaiJu Wu <[email protected]>
  • Loading branch information
TaiJuWu committed Mar 15, 2024
1 parent e0c18c0 commit b4d37db
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 27 deletions.
7 changes: 5 additions & 2 deletions include/nuttx/rwsem.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,18 @@
* Included Files
****************************************************************************/

#include <nuttx/mutex.h>
#include <nuttx/semaphore.h>
#include <nuttx/spinlock.h>

/****************************************************************************
* Public Type Definitions
****************************************************************************/

typedef struct
{
mutex_t protected; /* Protecting Locks for Read/Write Locked Tables */
#ifdef CONFIG_SPINLOCK
spinlock_t protected; /* Protecting Locks for Read/Write Locked Tables */
#endif
sem_t waiting; /* Reader/writer Waiting queue */
int waiter; /* Waiter Count */
int writer; /* Writer Count */
Expand Down
60 changes: 35 additions & 25 deletions sched/semaphore/sem_rw.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@
****************************************************************************/

#include <nuttx/rwsem.h>
#include <nuttx/irq.h>
#include <assert.h>

/****************************************************************************
* Pre-processor Definitions
****************************************************************************/

#undef spin_lock_irqsave
#undef spin_unlock_irqrestore

#if !defined(CONFIG_SPINLOCK)
#define spin_lock_irqsave(lock) up_irq_save()
#define spin_unlock_irqrestore(lock, flags) up_irq_restore(flags)
#endif

/****************************************************************************
* Private Functions
Expand Down Expand Up @@ -61,11 +75,11 @@ static inline void up_wait(FAR rw_semaphore_t *rwsem)

int down_read_trylock(FAR rw_semaphore_t *rwsem)
{
nxmutex_lock(&rwsem->protected);
irqstate_t flags = spin_lock_irqsave(&rwsem->protected);

if (rwsem->writer > 0)
{
nxmutex_unlock(&rwsem->protected);
spin_unlock_irqrestore(&rwsem->protected, flags);
return 0;
}

Expand All @@ -75,7 +89,7 @@ int down_read_trylock(FAR rw_semaphore_t *rwsem)

rwsem->reader++;

nxmutex_unlock(&rwsem->protected);
spin_unlock_irqrestore(&rwsem->protected, flags);

return 1;
}
Expand All @@ -97,14 +111,14 @@ void down_read(FAR rw_semaphore_t *rwsem)
* block and wait for the write-lock to be unlocked.
*/

nxmutex_lock(&rwsem->protected);
irqstate_t flags = spin_lock_irqsave(&rwsem->protected);

while (rwsem->writer > 0)
{
rwsem->waiter++;
nxmutex_unlock(&rwsem->protected);
spin_unlock_irqrestore(&rwsem->protected, flags);
nxsem_wait(&rwsem->waiting);
nxmutex_lock(&rwsem->protected);
flags = spin_lock_irqsave(&rwsem->protected);
rwsem->waiter--;
}

Expand All @@ -114,7 +128,7 @@ void down_read(FAR rw_semaphore_t *rwsem)

rwsem->reader++;

nxmutex_unlock(&rwsem->protected);
spin_unlock_irqrestore(&rwsem->protected, flags);
}

/****************************************************************************
Expand All @@ -130,7 +144,7 @@ void down_read(FAR rw_semaphore_t *rwsem)

void up_read(FAR rw_semaphore_t *rwsem)
{
nxmutex_lock(&rwsem->protected);
irqstate_t flags = spin_lock_irqsave(&rwsem->protected);

DEBUGASSERT(rwsem->reader > 0);

Expand All @@ -141,7 +155,7 @@ void up_read(FAR rw_semaphore_t *rwsem)
up_wait(rwsem);
}

nxmutex_unlock(&rwsem->protected);
spin_unlock_irqrestore(&rwsem->protected, flags);
}

/****************************************************************************
Expand All @@ -160,19 +174,19 @@ void up_read(FAR rw_semaphore_t *rwsem)

int down_write_trylock(FAR rw_semaphore_t *rwsem)
{
nxmutex_lock(&rwsem->protected);
irqstate_t flags = spin_lock_irqsave(&rwsem->protected);

if (rwsem->writer > 0 || rwsem->reader > 0)
{
nxmutex_unlock(&rwsem->protected);
spin_unlock_irqrestore(&rwsem->protected, flags);
return 0;
}

/* The check passes, then we just need the writer reference + 1 */

rwsem->writer++;

nxmutex_unlock(&rwsem->protected);
spin_unlock_irqrestore(&rwsem->protected, flags);

return 1;
}
Expand All @@ -190,22 +204,22 @@ int down_write_trylock(FAR rw_semaphore_t *rwsem)

void down_write(FAR rw_semaphore_t *rwsem)
{
nxmutex_lock(&rwsem->protected);
irqstate_t flags = spin_lock_irqsave(&rwsem->protected);

while (rwsem->reader > 0 || rwsem->writer > 0)
{
rwsem->waiter++;
nxmutex_unlock(&rwsem->protected);
spin_unlock_irqrestore(&rwsem->protected, flags);
nxsem_wait(&rwsem->waiting);
nxmutex_lock(&rwsem->protected);
flags = spin_lock_irqsave(&rwsem->protected);
rwsem->waiter--;
}

/* The check passes, then we just need the writer reference + 1 */

rwsem->writer++;

nxmutex_unlock(&rwsem->protected);
spin_unlock_irqrestore(&rwsem->protected, flags);
}

/****************************************************************************
Expand All @@ -221,15 +235,15 @@ void down_write(FAR rw_semaphore_t *rwsem)

void up_write(FAR rw_semaphore_t *rwsem)
{
nxmutex_lock(&rwsem->protected);
irqstate_t flags = spin_lock_irqsave(&rwsem->protected);

DEBUGASSERT(rwsem->writer > 0);

rwsem->writer--;

up_wait(rwsem);

nxmutex_unlock(&rwsem->protected);
spin_unlock_irqrestore(&rwsem->protected, flags);
}

/****************************************************************************
Expand All @@ -253,16 +267,13 @@ int init_rwsem(FAR rw_semaphore_t *rwsem)

/* Initialize structure information */

ret = nxmutex_init(&rwsem->protected);
if (ret < 0)
{
return ret;
}
#ifdef CONFIG_SPINLOCK
spin_lock_init(&rwsem->protected);
#endif

ret = nxsem_init(&rwsem->waiting, 0, 0);
if (ret < 0)
{
nxmutex_destroy(&rwsem->protected);
return ret;
}

Expand Down Expand Up @@ -292,6 +303,5 @@ void destroy_rwsem(FAR rw_semaphore_t *rwsem)
DEBUGASSERT(rwsem->waiter == 0 && rwsem->reader == 0 &&
rwsem->writer == 0);

nxmutex_destroy(&rwsem->protected);
nxsem_destroy(&rwsem->waiting);
}

0 comments on commit b4d37db

Please sign in to comment.