summary refs log tree commit diff
path: root/nptl/DESIGN-rwlock.txt
diff options
context:
space:
mode:
Diffstat (limited to 'nptl/DESIGN-rwlock.txt')
-rw-r--r--nptl/DESIGN-rwlock.txt109
1 files changed, 109 insertions, 0 deletions
diff --git a/nptl/DESIGN-rwlock.txt b/nptl/DESIGN-rwlock.txt
new file mode 100644
index 0000000000..6262a7a5b9
--- /dev/null
+++ b/nptl/DESIGN-rwlock.txt
@@ -0,0 +1,109 @@
+Reader Writer Locks pseudocode
+==============================
+
+	pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
+	pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
+	pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
+
+struct pthread_rwlock_t {
+
+   unsigned int lock:
+         - internal mutex
+
+   unsigned int writers_preferred;
+         - locking mode: 0 recursive, readers preferred
+                         1 nonrecursive, writers preferred
+
+   unsigned int readers;
+         - number of read-only references various threads have
+
+   pthread_t writer;
+         - descriptor of the writer or 0
+
+   unsigned int readers_wakeup;
+         - 'all readers should wake up' futex.
+
+   unsigned int writer_wakeup;
+         - 'one writer should wake up' futex.
+
+   unsigned int nr_readers_queued;
+         - number of readers queued up.
+
+   unsigned int nr_writers_queued;
+         - number of writers queued up.
+}
+
+pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
+{
+  lll_lock(rwlock->lock);
+  for (;;) {
+    if (!rwlock->writer && (!rwlock->nr_writers_queued ||
+					!rwlock->writers_preferred))
+        break;
+
+    rwlock->nr_readers_queued++;
+    lll_unlock(rwlock->lock);
+
+    futex_wait(&rwlock->readers_wakeup, 0)
+
+    lll_lock(rwlock->lock);
+    if (!--rwlock->nr_readers_queued)
+        rwlock->readers_wakeup = 0;
+  }
+  rwlock->readers++;
+  lll_unlock(rwlock->lock);
+}
+
+pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
+{
+  int result = EBUSY;
+  lll_lock(rwlock->lock);
+  if (!rwlock->writer && (!rwlock->nr_writers_queued ||
+					!rwlock->writers_preferred))
+    rwlock->readers++;
+  lll_unlock(rwlock->lock);
+  return result;
+}
+
+pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
+{
+  lll_lock(rwlock->lock);
+  for (;;) {
+    if (!rwlock->writer && !rwlock->readers)
+       break;
+
+    rwlock->nr_writers_queued++;
+    lll_unlock(rwlock->lock);
+
+    futex_wait(&rwlock->writer_wakeup, 0);
+
+    lll_lock(rwlock->lock);
+    rwlock->nr_writers_queued--;
+    rwlock->writer_wakeup = 0;
+  }
+  rwlock->writer = pthread_self();
+  lll_unlock(rwlock->lock);
+}
+
+pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
+{
+  lll_lock(rwlock->lock);
+
+  if (rwlock->writer)
+    rwlock->writer = 0;
+  else
+    rwlock->readers--;
+
+  if (!rwlock->readers) {
+    if (rwlock->nr_writers_queued) {
+      rwlock->writer_wakeup = 1;
+      futex_wake(&rwlock->writer_wakeup, 1);
+    } else
+      if (rwlock->nr_readers_queued) {
+        rwlock->readers_wakeup = 1;
+        futex_wake(&rwlock->readers_wakeup, MAX_INT);
+      }
+  }
+
+  lll_unlock(rwlock->lock);
+}