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);
 }

Reply via email to