Skip to content

Commit

Permalink
sched/semaphore: support recursive write for same process in sem_rw lock
Browse files Browse the repository at this point in the history
Signed-off-by: dongjiuzhu1 <[email protected]>
  • Loading branch information
Donny9 committed Sep 29, 2024
1 parent 7cf5e7c commit 2fc97d1
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 10 deletions.
22 changes: 17 additions & 5 deletions include/nuttx/rwsem.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,29 @@
#include <nuttx/semaphore.h>
#include <nuttx/spinlock.h>

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

#define RWSEM_NO_HOLDER ((pid_t)-1)
#define RWSEM_INITIALIZER {NXMUTEX_INITIALIZER, SEM_INITIALIZER(0), \
RWSEM_NO_HOLDER, 0, 0, 0}

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

typedef struct
{
spinlock_t protected;
sem_t waiting;
int waiter;
int writer;
int reader;
spinlock_t protected; /* Protecting Locks for Read/Write Locked Tables */
sem_t waiting; /* Reader/writer Waiting queue */
pid_t holder; /* The write lock holder, this lock still can be
* locked when the holder is same as the current
* task/thread.
*/
int waiter; /* Waiter Count */
int writer; /* Writer Count */
int reader; /* Reader Count */
} rw_semaphore_t;

/****************************************************************************
Expand Down
20 changes: 15 additions & 5 deletions sched/semaphore/sem_rw.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@
* Included Files
****************************************************************************/

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

/****************************************************************************
Expand Down Expand Up @@ -165,8 +166,9 @@ void up_read(FAR rw_semaphore_t *rwsem)
int down_write_trylock(FAR rw_semaphore_t *rwsem)
{
irqstate_t flags = spin_lock_irqsave(&rwsem->protected);
pid_t tid = _SCHED_GETTID();

if (rwsem->writer > 0 || rwsem->reader > 0)
if (rwsem->reader > 0 || (rwsem->writer > 0 && tid != rwsem->holder))
{
spin_unlock_irqrestore(&rwsem->protected, flags);
return 0;
Expand All @@ -175,6 +177,7 @@ int down_write_trylock(FAR rw_semaphore_t *rwsem)
/* The check passes, then we just need the writer reference + 1 */

rwsem->writer++;
rwsem->holder = tid;

spin_unlock_irqrestore(&rwsem->protected, flags);

Expand All @@ -195,8 +198,9 @@ int down_write_trylock(FAR rw_semaphore_t *rwsem)
void down_write(FAR rw_semaphore_t *rwsem)
{
irqstate_t flags = spin_lock_irqsave(&rwsem->protected);
pid_t tid = _SCHED_GETTID();

while (rwsem->reader > 0 || rwsem->writer > 0)
while (rwsem->reader > 0 || (rwsem->writer > 0 && rwsem->holder != tid))
{
rwsem->waiter++;
spin_unlock_irqrestore(&rwsem->protected, flags);
Expand All @@ -208,6 +212,7 @@ void down_write(FAR rw_semaphore_t *rwsem)
/* The check passes, then we just need the writer reference + 1 */

rwsem->writer++;
rwsem->holder = tid;

spin_unlock_irqrestore(&rwsem->protected, flags);
}
Expand All @@ -228,8 +233,12 @@ void up_write(FAR rw_semaphore_t *rwsem)
irqstate_t flags = spin_lock_irqsave(&rwsem->protected);

DEBUGASSERT(rwsem->writer > 0);
DEBUGASSERT(rwsem->holder == _SCHED_GETTID());

rwsem->writer--;
if (--rwsem->writer <= 0)
{
rwsem->holder = RWSEM_NO_HOLDER;
}

up_wait(rwsem);

Expand Down Expand Up @@ -268,6 +277,7 @@ int init_rwsem(FAR rw_semaphore_t *rwsem)
rwsem->reader = 0;
rwsem->writer = 0;
rwsem->waiter = 0;
rwsem->holder = RWSEM_NO_HOLDER;

return OK;
}
Expand All @@ -289,7 +299,7 @@ void destroy_rwsem(FAR rw_semaphore_t *rwsem)
/* Need to check if there is still an unlocked or waiting state */

DEBUGASSERT(rwsem->waiter == 0 && rwsem->reader == 0 &&
rwsem->writer == 0);
rwsem->writer == 0 && rwsem->holder == RWSEM_NO_HOLDER);

nxsem_destroy(&rwsem->waiting);
}

0 comments on commit 2fc97d1

Please sign in to comment.