github.com/ActiveState/go@v0.0.0-20170614201249-0b81c023a722/src/sync/rwmutex.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package sync 6 7 import ( 8 "internal/race" 9 "sync/atomic" 10 "unsafe" 11 ) 12 13 // An RWMutex is a reader/writer mutual exclusion lock. 14 // The lock can be held by an arbitrary number of readers or a single writer. 15 // The zero value for a RWMutex is an unlocked mutex. 16 // 17 // An RWMutex must not be copied after first use. 18 // 19 // If a goroutine holds a RWMutex for reading and another goroutine might 20 // call Lock, no goroutine should expect to be able to acquire a read lock 21 // until the initial read lock is released. In particular, this prohibits 22 // recursive read locking. This is to ensure that the lock eventually becomes 23 // available; a blocked Lock call excludes new readers from acquiring the 24 // lock. 25 type RWMutex struct { 26 w Mutex // held if there are pending writers 27 writerSem uint32 // semaphore for writers to wait for completing readers 28 readerSem uint32 // semaphore for readers to wait for completing writers 29 readerCount int32 // number of pending readers 30 readerWait int32 // number of departing readers 31 } 32 33 const rwmutexMaxReaders = 1 << 30 34 35 // RLock locks rw for reading. 36 // 37 // It should not be used for recursive read locking; a blocked Lock 38 // call excludes new readers from acquiring the lock. See the 39 // documentation on the RWMutex type. 40 func (rw *RWMutex) RLock() { 41 if race.Enabled { 42 _ = rw.w.state 43 race.Disable() 44 } 45 if atomic.AddInt32(&rw.readerCount, 1) < 0 { 46 // A writer is pending, wait for it. 47 runtime_Semacquire(&rw.readerSem) 48 } 49 if race.Enabled { 50 race.Enable() 51 race.Acquire(unsafe.Pointer(&rw.readerSem)) 52 } 53 } 54 55 // RUnlock undoes a single RLock call; 56 // it does not affect other simultaneous readers. 57 // It is a run-time error if rw is not locked for reading 58 // on entry to RUnlock. 59 func (rw *RWMutex) RUnlock() { 60 if race.Enabled { 61 _ = rw.w.state 62 race.ReleaseMerge(unsafe.Pointer(&rw.writerSem)) 63 race.Disable() 64 } 65 if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 { 66 if r+1 == 0 || r+1 == -rwmutexMaxReaders { 67 race.Enable() 68 throw("sync: RUnlock of unlocked RWMutex") 69 } 70 // A writer is pending. 71 if atomic.AddInt32(&rw.readerWait, -1) == 0 { 72 // The last reader unblocks the writer. 73 runtime_Semrelease(&rw.writerSem, false) 74 } 75 } 76 if race.Enabled { 77 race.Enable() 78 } 79 } 80 81 // Lock locks rw for writing. 82 // If the lock is already locked for reading or writing, 83 // Lock blocks until the lock is available. 84 func (rw *RWMutex) Lock() { 85 if race.Enabled { 86 _ = rw.w.state 87 race.Disable() 88 } 89 // First, resolve competition with other writers. 90 rw.w.Lock() 91 // Announce to readers there is a pending writer. 92 r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders 93 // Wait for active readers. 94 if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 { 95 runtime_Semacquire(&rw.writerSem) 96 } 97 if race.Enabled { 98 race.Enable() 99 race.Acquire(unsafe.Pointer(&rw.readerSem)) 100 race.Acquire(unsafe.Pointer(&rw.writerSem)) 101 } 102 } 103 104 // Unlock unlocks rw for writing. It is a run-time error if rw is 105 // not locked for writing on entry to Unlock. 106 // 107 // As with Mutexes, a locked RWMutex is not associated with a particular 108 // goroutine. One goroutine may RLock (Lock) an RWMutex and then 109 // arrange for another goroutine to RUnlock (Unlock) it. 110 func (rw *RWMutex) Unlock() { 111 if race.Enabled { 112 _ = rw.w.state 113 race.Release(unsafe.Pointer(&rw.readerSem)) 114 race.Release(unsafe.Pointer(&rw.writerSem)) 115 race.Disable() 116 } 117 118 // Announce to readers there is no active writer. 119 r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders) 120 if r >= rwmutexMaxReaders { 121 race.Enable() 122 throw("sync: Unlock of unlocked RWMutex") 123 } 124 // Unblock blocked readers, if any. 125 for i := 0; i < int(r); i++ { 126 runtime_Semrelease(&rw.readerSem, false) 127 } 128 // Allow other writers to proceed. 129 rw.w.Unlock() 130 if race.Enabled { 131 race.Enable() 132 } 133 } 134 135 // RLocker returns a Locker interface that implements 136 // the Lock and Unlock methods by calling rw.RLock and rw.RUnlock. 137 func (rw *RWMutex) RLocker() Locker { 138 return (*rlocker)(rw) 139 } 140 141 type rlocker RWMutex 142 143 func (r *rlocker) Lock() { (*RWMutex)(r).RLock() } 144 func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }