Added recursive read-write lock. It allows threads to
read lock or write lock the rwlock multiple times without
deadlocking. Mixing of read and write lock operations is
not supported.

ODP version of recursive rwlock enables porting legacy
applications, which use these kind of locks.

Signed-off-by: Petri Savolainen <petri.savolai...@nokia.com>
---
 include/odp.h                                      |  1 +
 include/odp/api/rwlock_recursive.h                 | 94 ++++++++++++++++++++++
 platform/linux-generic/Makefile.am                 |  4 +
 .../include/odp/plat/rwlock_recursive_types.h      | 49 +++++++++++
 .../linux-generic/include/odp/rwlock_recursive.h   | 28 +++++++
 platform/linux-generic/odp_rwlock_recursive.c      | 70 ++++++++++++++++
 6 files changed, 246 insertions(+)
 create mode 100644 include/odp/api/rwlock_recursive.h
 create mode 100644 
platform/linux-generic/include/odp/plat/rwlock_recursive_types.h
 create mode 100644 platform/linux-generic/include/odp/rwlock_recursive.h
 create mode 100644 platform/linux-generic/odp_rwlock_recursive.c

diff --git a/include/odp.h b/include/odp.h
index b47ab82..825c7e1 100644
--- a/include/odp.h
+++ b/include/odp.h
@@ -55,6 +55,7 @@ extern "C" {
 #include <odp/errno.h>
 #include <odp/thrmask.h>
 #include <odp/spinlock_recursive.h>
+#include <odp/rwlock_recursive.h>
 
 #ifdef __cplusplus
 }
diff --git a/include/odp/api/rwlock_recursive.h 
b/include/odp/api/rwlock_recursive.h
new file mode 100644
index 0000000..4c7556a
--- /dev/null
+++ b/include/odp/api/rwlock_recursive.h
@@ -0,0 +1,94 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * ODP recursive read/write lock
+ */
+
+#ifndef ODP_API_RWLOCK_RECURSIVE_H_
+#define ODP_API_RWLOCK_RECURSIVE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @addtogroup odp_synchronizers
+ *  Operations on recursive rwlocks.
+ *  @{
+ */
+
+/**
+ * @typedef odp_rwlock_recursive_t
+ * Recursive rwlock
+ *
+ * A thread can read- or write-acquire a recursive read-write lock multiple
+ * times without a deadlock. To release the lock, the thread must unlock it
+ * the same number of times. Recursion is supported only for a pure series of
+ * read or write lock calls. Read and write lock calls must not be mixed when
+ * recursing.
+ *
+ * For example, these are supported...
+ *   * read_lock(); read_lock(); read_unlock(); read_unlock();
+ *   * write_lock(); write_lock(); write_unlock(); write_unlock();
+ *
+ * ... but this is not supported.
+ *   * read_lock(); write_lock(); write_unlock(); read_unlock();
+ */
+
+/**
+ * Initialize recursive rwlock
+ *
+ * @param lock    Pointer to a lock
+ */
+void odp_rwlock_recursive_init(odp_rwlock_recursive_t *lock);
+
+/**
+ * Acquire recursive rwlock for reading
+ *
+ * This call allows the thread to acquire the same lock multiple times for
+ * reading. The lock cannot be acquired for writing while holding it
+ * for reading.
+ *
+ * @param lock    Pointer to a lock
+ */
+void odp_rwlock_recursive_read_lock(odp_rwlock_recursive_t *lock);
+
+/**
+ * Release recursive rwlock after reading
+ *
+ * @param lock    Pointer to a lock
+ */
+void odp_rwlock_recursive_read_unlock(odp_rwlock_recursive_t *lock);
+
+/**
+ * Acquire recursive rwlock for writing
+ *
+ * This call allows the thread to acquire the same lock multiple times for
+ * writing. The lock cannot be acquired for reading while holding it
+ * for writing.
+ *
+ * @param lock    Pointer to a lock
+ */
+void odp_rwlock_recursive_write_lock(odp_rwlock_recursive_t *lock);
+
+/**
+ * Release recursive rwlock after writing
+ *
+ * @param lock    Pointer to a lock
+ */
+void odp_rwlock_recursive_write_unlock(odp_rwlock_recursive_t *lock);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/platform/linux-generic/Makefile.am 
b/platform/linux-generic/Makefile.am
index 96e4f9e..0e10848 100644
--- a/platform/linux-generic/Makefile.am
+++ b/platform/linux-generic/Makefile.am
@@ -35,6 +35,7 @@ odpinclude_HEADERS = \
                  $(srcdir)/include/odp/queue.h \
                  $(srcdir)/include/odp/random.h \
                  $(srcdir)/include/odp/rwlock.h \
+                 $(srcdir)/include/odp/rwlock_recursive.h \
                  $(srcdir)/include/odp/schedule.h \
                  $(srcdir)/include/odp/schedule_types.h \
                  $(srcdir)/include/odp/shared_memory.h \
@@ -65,6 +66,7 @@ odpplatinclude_HEADERS = \
                  $(srcdir)/include/odp/plat/pool_types.h \
                  $(srcdir)/include/odp/plat/queue_types.h \
                  $(srcdir)/include/odp/plat/rwlock_types.h \
+                 $(srcdir)/include/odp/plat/rwlock_recursive_types.h \
                  $(srcdir)/include/odp/plat/schedule_types.h \
                  $(srcdir)/include/odp/plat/shared_memory_types.h \
                  $(srcdir)/include/odp/plat/spinlock_types.h \
@@ -100,6 +102,7 @@ odpapiinclude_HEADERS = \
                  $(top_srcdir)/include/odp/api/queue.h \
                  $(top_srcdir)/include/odp/api/random.h \
                  $(top_srcdir)/include/odp/api/rwlock.h \
+                 $(top_srcdir)/include/odp/api/rwlock_recursive.h \
                  $(top_srcdir)/include/odp/api/schedule.h \
                  $(top_srcdir)/include/odp/api/schedule_types.h \
                  $(top_srcdir)/include/odp/api/shared_memory.h \
@@ -159,6 +162,7 @@ __LIB__libodp_la_SOURCES = \
                           odp_pool.c \
                           odp_queue.c \
                           odp_rwlock.c \
+                          odp_rwlock_recursive.c \
                           odp_schedule.c \
                           odp_shared_memory.c \
                           odp_spinlock.c \
diff --git a/platform/linux-generic/include/odp/plat/rwlock_recursive_types.h 
b/platform/linux-generic/include/odp/plat/rwlock_recursive_types.h
new file mode 100644
index 0000000..9e220f5
--- /dev/null
+++ b/platform/linux-generic/include/odp/plat/rwlock_recursive_types.h
@@ -0,0 +1,49 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * ODP recursive read/write lock
+ */
+
+#ifndef ODP_RWLOCK_RECURSIVE_TYPES_H_
+#define ODP_RWLOCK_RECURSIVE_TYPES_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp/rwlock.h>
+#include <odp/std_types.h>
+#include <odp/config.h>
+
+/**
+ * @internal
+ * ODP recursive rwlock
+ */
+struct odp_rwlock_recursive_s {
+       odp_rwlock_t lock;                       /**< the lock */
+       int wr_owner;                            /**< write owner thread */
+       uint32_t wr_cnt;                         /**< write recursion count */
+       uint8_t  rd_cnt[ODP_CONFIG_MAX_THREADS]; /**< read recursion count */
+};
+
+/** @addtogroup odp_synchronizers
+ *  @{
+ */
+
+typedef struct odp_rwlock_recursive_s odp_rwlock_recursive_t;
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/platform/linux-generic/include/odp/rwlock_recursive.h 
b/platform/linux-generic/include/odp/rwlock_recursive.h
new file mode 100644
index 0000000..e9dadc8
--- /dev/null
+++ b/platform/linux-generic/include/odp/rwlock_recursive.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * ODP resursive read/write lock
+ */
+
+#ifndef ODP_PLAT_RWLOCK_RECURSIVE_H_
+#define ODP_PLAT_RWLOCK_RECURSIVE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp/plat/rwlock_recursive_types.h>
+
+#include <odp/api/rwlock_recursive.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/platform/linux-generic/odp_rwlock_recursive.c 
b/platform/linux-generic/odp_rwlock_recursive.c
new file mode 100644
index 0000000..e3a383c
--- /dev/null
+++ b/platform/linux-generic/odp_rwlock_recursive.c
@@ -0,0 +1,70 @@
+/* Copyright (c) 2013, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include <odp/rwlock_recursive.h>
+#include <odp/thread.h>
+#include <string.h>
+
+#define NO_OWNER (-1)
+
+void odp_rwlock_recursive_init(odp_rwlock_recursive_t *rlock)
+{
+       memset(rlock, 0, sizeof(odp_rwlock_recursive_t));
+       odp_rwlock_init(&rlock->lock);
+       rlock->wr_owner = NO_OWNER;
+}
+
+/* Multiple readers can recurse the lock concurrently */
+void odp_rwlock_recursive_read_lock(odp_rwlock_recursive_t *rlock)
+{
+       int thr = odp_thread_id();
+
+       if (rlock->rd_cnt[thr]) {
+               rlock->rd_cnt[thr]++;
+               return;
+       }
+
+       odp_rwlock_read_lock(&rlock->lock);
+       rlock->rd_cnt[thr] = 1;
+}
+
+void odp_rwlock_recursive_read_unlock(odp_rwlock_recursive_t *rlock)
+{
+       int thr = odp_thread_id();
+
+       rlock->rd_cnt[thr]--;
+
+       if (rlock->rd_cnt[thr] > 0)
+               return;
+
+       odp_rwlock_read_unlock(&rlock->lock);
+}
+
+/* Only one writer can recurse the lock */
+void odp_rwlock_recursive_write_lock(odp_rwlock_recursive_t *rlock)
+{
+       int thr = odp_thread_id();
+
+       if (rlock->wr_owner == thr) {
+               rlock->wr_cnt++;
+               return;
+       }
+
+       odp_rwlock_write_lock(&rlock->lock);
+       rlock->wr_owner = thr;
+       rlock->wr_cnt   = 1;
+}
+
+void odp_rwlock_recursive_write_unlock(odp_rwlock_recursive_t *rlock)
+{
+       rlock->wr_cnt--;
+
+       if (rlock->wr_cnt > 0)
+               return;
+
+       rlock->wr_owner = NO_OWNER;
+       odp_rwlock_write_unlock(&rlock->lock);
+}
-- 
2.5.1

_______________________________________________
lng-odp mailing list
lng-odp@lists.linaro.org
https://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to