github.com/sbinet/go@v0.0.0-20160827155028-54d7de7dd62b/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 // RWMutexes can be created as part of other structures; 16 // the zero value for a RWMutex is an unlocked mutex. 17 // 18 // An RWMutex must not be copied after first use. 19 // 20 // If a goroutine holds a RWMutex for reading, it must not expect this or any 21 // other goroutine to be able to also take the read lock until the first read 22 // lock is released. In particular, this prohibits recursive read locking. 23 // This is to ensure that the lock eventually becomes available; 24 // a blocked Lock call excludes new readers from acquiring the 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 func (rw *RWMutex) RLock() { 37 if race.Enabled { 38 _ = rw.w.state 39 race.Disable() 40 } 41 if atomic.AddInt32(&rw.readerCount, 1) < 0 { 42 // A writer is pending, wait for it. 43 runtime_Semacquire(&rw.readerSem) 44 } 45 if race.Enabled { 46 race.Enable() 47 race.Acquire(unsafe.Pointer(&rw.readerSem)) 48 } 49 } 50 51 // RUnlock undoes a single RLock call; 52 // it does not affect other simultaneous readers. 53 // It is a run-time error if rw is not locked for reading 54 // on entry to RUnlock. 55 func (rw *RWMutex) RUnlock() { 56 if race.Enabled { 57 _ = rw.w.state 58 race.ReleaseMerge(unsafe.Pointer(&rw.writerSem)) 59 race.Disable() 60 } 61 if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 { 62 if r+1 == 0 || r+1 == -rwmutexMaxReaders { 63 race.Enable() 64 panic("sync: RUnlock of unlocked RWMutex") 65 } 66 // A writer is pending. 67 if atomic.AddInt32(&rw.readerWait, -1) == 0 { 68 // The last reader unblocks the writer. 69 runtime_Semrelease(&rw.writerSem) 70 } 71 } 72 if race.Enabled { 73 race.Enable() 74 } 75 } 76 77 // Lock locks rw for writing. 78 // If the lock is already locked for reading or writing, 79 // Lock blocks until the lock is available. 80 func (rw *RWMutex) Lock() { 81 if race.Enabled { 82 _ = rw.w.state 83 race.Disable() 84 } 85 // First, resolve competition with other writers. 86 rw.w.Lock() 87 // Announce to readers there is a pending writer. 88 r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders 89 // Wait for active readers. 90 if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 { 91 runtime_Semacquire(&rw.writerSem) 92 } 93 if race.Enabled { 94 race.Enable() 95 race.Acquire(unsafe.Pointer(&rw.readerSem)) 96 race.Acquire(unsafe.Pointer(&rw.writerSem)) 97 } 98 } 99 100 // Unlock unlocks rw for writing. It is a run-time error if rw is 101 // not locked for writing on entry to Unlock. 102 // 103 // As with Mutexes, a locked RWMutex is not associated with a particular 104 // goroutine. One goroutine may RLock (Lock) an RWMutex and then 105 // arrange for another goroutine to RUnlock (Unlock) it. 106 func (rw *RWMutex) Unlock() { 107 if race.Enabled { 108 _ = rw.w.state 109 race.Release(unsafe.Pointer(&rw.readerSem)) 110 race.Release(unsafe.Pointer(&rw.writerSem)) 111 race.Disable() 112 } 113 114 // Announce to readers there is no active writer. 115 r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders) 116 if r >= rwmutexMaxReaders { 117 race.Enable() 118 panic("sync: Unlock of unlocked RWMutex") 119 } 120 // Unblock blocked readers, if any. 121 for i := 0; i < int(r); i++ { 122 runtime_Semrelease(&rw.readerSem) 123 } 124 // Allow other writers to proceed. 125 rw.w.Unlock() 126 if race.Enabled { 127 race.Enable() 128 } 129 } 130 131 // RLocker returns a Locker interface that implements 132 // the Lock and Unlock methods by calling rw.RLock and rw.RUnlock. 133 func (rw *RWMutex) RLocker() Locker { 134 return (*rlocker)(rw) 135 } 136 137 type rlocker RWMutex 138 139 func (r *rlocker) Lock() { (*RWMutex)(r).RLock() } 140 func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }