123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- // Copyright 2009 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package sync
- import (
- "sync/atomic"
- "unsafe"
- )
- // An RWMutex is a reader/writer mutual exclusion lock.
- // The lock can be held by an arbitrary number of readers
- // or a single writer.
- // RWMutexes can be created as part of other
- // structures; the zero value for a RWMutex is
- // an unlocked mutex.
- type RWMutex struct {
- w Mutex // held if there are pending writers
- writerSem uint32 // semaphore for writers to wait for completing readers
- readerSem uint32 // semaphore for readers to wait for completing writers
- readerCount int32 // number of pending readers
- readerWait int32 // number of departing readers
- }
- const rwmutexMaxReaders = 1 << 30
- // RLock locks rw for reading.
- func (rw *RWMutex) RLock() {
- if raceenabled {
- _ = rw.w.state
- raceDisable()
- }
- if atomic.AddInt32(&rw.readerCount, 1) < 0 {
- // A writer is pending, wait for it.
- runtime_Semacquire(&rw.readerSem)
- }
- if raceenabled {
- raceEnable()
- raceAcquire(unsafe.Pointer(&rw.readerSem))
- }
- }
- // RUnlock undoes a single RLock call;
- // it does not affect other simultaneous readers.
- // It is a run-time error if rw is not locked for reading
- // on entry to RUnlock.
- func (rw *RWMutex) RUnlock() {
- if raceenabled {
- _ = rw.w.state
- raceReleaseMerge(unsafe.Pointer(&rw.writerSem))
- raceDisable()
- }
- if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
- if r+1 == 0 || r+1 == -rwmutexMaxReaders {
- raceEnable()
- panic("sync: RUnlock of unlocked RWMutex")
- }
- // A writer is pending.
- if atomic.AddInt32(&rw.readerWait, -1) == 0 {
- // The last reader unblocks the writer.
- runtime_Semrelease(&rw.writerSem)
- }
- }
- if raceenabled {
- raceEnable()
- }
- }
- // Lock locks rw for writing.
- // If the lock is already locked for reading or writing,
- // Lock blocks until the lock is available.
- // To ensure that the lock eventually becomes available,
- // a blocked Lock call excludes new readers from acquiring
- // the lock.
- func (rw *RWMutex) Lock() {
- if raceenabled {
- _ = rw.w.state
- raceDisable()
- }
- // First, resolve competition with other writers.
- rw.w.Lock()
- // Announce to readers there is a pending writer.
- r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
- // Wait for active readers.
- if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
- runtime_Semacquire(&rw.writerSem)
- }
- if raceenabled {
- raceEnable()
- raceAcquire(unsafe.Pointer(&rw.readerSem))
- raceAcquire(unsafe.Pointer(&rw.writerSem))
- }
- }
- // Unlock unlocks rw for writing. It is a run-time error if rw is
- // not locked for writing on entry to Unlock.
- //
- // As with Mutexes, a locked RWMutex is not associated with a particular
- // goroutine. One goroutine may RLock (Lock) an RWMutex and then
- // arrange for another goroutine to RUnlock (Unlock) it.
- func (rw *RWMutex) Unlock() {
- if raceenabled {
- _ = rw.w.state
- raceRelease(unsafe.Pointer(&rw.readerSem))
- raceRelease(unsafe.Pointer(&rw.writerSem))
- raceDisable()
- }
- // Announce to readers there is no active writer.
- r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
- if r >= rwmutexMaxReaders {
- raceEnable()
- panic("sync: Unlock of unlocked RWMutex")
- }
- // Unblock blocked readers, if any.
- for i := 0; i < int(r); i++ {
- runtime_Semrelease(&rw.readerSem)
- }
- // Allow other writers to proceed.
- rw.w.Unlock()
- if raceenabled {
- raceEnable()
- }
- }
- // RLocker returns a Locker interface that implements
- // the Lock and Unlock methods by calling rw.RLock and rw.RUnlock.
- func (rw *RWMutex) RLocker() Locker {
- return (*rlocker)(rw)
- }
- type rlocker RWMutex
- func (r *rlocker) Lock() { (*RWMutex)(r).RLock() }
- func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }
|