diff options
Diffstat (limited to 'nptl/DESIGN-rwlock.txt')
-rw-r--r-- | nptl/DESIGN-rwlock.txt | 109 |
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); +} |