|  | // 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() } |