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