This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit a367657d2d8c548b66f4b8e667d6ee990c53c549 Author: dongjiuzhu1 <[email protected]> AuthorDate: Fri May 17 17:52:58 2024 +0800 sched/semaphore: support recursive write for same process in sem_rw lock Signed-off-by: dongjiuzhu1 <[email protected]> --- include/nuttx/rwsem.h | 22 +++++++++++++++++----- sched/semaphore/sem_rw.c | 20 +++++++++++++++----- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/include/nuttx/rwsem.h b/include/nuttx/rwsem.h index 2999bfcd52..af5fb82edf 100644 --- a/include/nuttx/rwsem.h +++ b/include/nuttx/rwsem.h @@ -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 {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; + 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 */ + spinlock_t protected; /* Protecting Locks for Read/Write Locked Tables */ } rw_semaphore_t; /**************************************************************************** diff --git a/sched/semaphore/sem_rw.c b/sched/semaphore/sem_rw.c index 52aaf03ae7..c22f92e26d 100644 --- a/sched/semaphore/sem_rw.c +++ b/sched/semaphore/sem_rw.c @@ -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> /**************************************************************************** @@ -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; @@ -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); @@ -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); @@ -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); } @@ -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); @@ -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; } @@ -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); }
