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++; val = rwlock->readers_wakeup; lll_unlock(rwlock->lock); futex_wait(&rwlock->readers_wakeup, val) lll_lock(rwlock->lock); rwlock->nr_readers_queued--; } 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++; val = rwlock->writer_wakeup; lll_unlock(rwlock->lock); futex_wait(&rwlock->writer_wakeup, val); lll_lock(rwlock->lock); rwlock->nr_writers_queued--; } 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; lll_unlock(rwlock->lock); futex_wake(&rwlock->writer_wakeup, 1); return; } else if (rwlock->nr_readers_queued) { ++rwlock->readers_wakeup; lll_unlock(rwlock->lock); futex_wake(&rwlock->readers_wakeup, MAX_INT); return; } } lll_unlock(rwlock->lock); }