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