...

Source file src/sync/rwmutex.go

Documentation: sync

		 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  // 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.
		28  type 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  
		36  const rwmutexMaxReaders = 1 << 30
		37  
		38  // Happens-before relationships are indicated to the race detector via:
		39  // - Unlock	-> Lock:	readerSem
		40  // - Unlock	-> RLock: readerSem
		41  // - RUnlock -> Lock:	writerSem
		42  //
		43  // The methods below temporarily disable handling of race synchronization
		44  // events in order to provide the more precise model above to the race
		45  // detector.
		46  //
		47  // For example, atomic.AddInt32 in RLock should not appear to provide
		48  // acquire-release semantics, which would incorrectly synchronize racing
		49  // readers, thus potentially missing races.
		50  
		51  // RLock locks rw for reading.
		52  //
		53  // It should not be used for recursive read locking; a blocked Lock
		54  // call excludes new readers from acquiring the lock. See the
		55  // documentation on the RWMutex type.
		56  func (rw *RWMutex) RLock() {
		57  	if race.Enabled {
		58  		_ = rw.w.state
		59  		race.Disable()
		60  	}
		61  	if atomic.AddInt32(&rw.readerCount, 1) < 0 {
		62  		// A writer is pending, wait for it.
		63  		runtime_SemacquireMutex(&rw.readerSem, false, 0)
		64  	}
		65  	if race.Enabled {
		66  		race.Enable()
		67  		race.Acquire(unsafe.Pointer(&rw.readerSem))
		68  	}
		69  }
		70  
		71  // RUnlock undoes a single RLock call;
		72  // it does not affect other simultaneous readers.
		73  // It is a run-time error if rw is not locked for reading
		74  // on entry to RUnlock.
		75  func (rw *RWMutex) RUnlock() {
		76  	if race.Enabled {
		77  		_ = rw.w.state
		78  		race.ReleaseMerge(unsafe.Pointer(&rw.writerSem))
		79  		race.Disable()
		80  	}
		81  	if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
		82  		// Outlined slow-path to allow the fast-path to be inlined
		83  		rw.rUnlockSlow(r)
		84  	}
		85  	if race.Enabled {
		86  		race.Enable()
		87  	}
		88  }
		89  
		90  func (rw *RWMutex) rUnlockSlow(r int32) {
		91  	if r+1 == 0 || r+1 == -rwmutexMaxReaders {
		92  		race.Enable()
		93  		throw("sync: RUnlock of unlocked RWMutex")
		94  	}
		95  	// A writer is pending.
		96  	if atomic.AddInt32(&rw.readerWait, -1) == 0 {
		97  		// The last reader unblocks the writer.
		98  		runtime_Semrelease(&rw.writerSem, false, 1)
		99  	}
	 100  }
	 101  
	 102  // Lock locks rw for writing.
	 103  // If the lock is already locked for reading or writing,
	 104  // Lock blocks until the lock is available.
	 105  func (rw *RWMutex) Lock() {
	 106  	if race.Enabled {
	 107  		_ = rw.w.state
	 108  		race.Disable()
	 109  	}
	 110  	// First, resolve competition with other writers.
	 111  	rw.w.Lock()
	 112  	// Announce to readers there is a pending writer.
	 113  	r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
	 114  	// Wait for active readers.
	 115  	if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
	 116  		runtime_SemacquireMutex(&rw.writerSem, false, 0)
	 117  	}
	 118  	if race.Enabled {
	 119  		race.Enable()
	 120  		race.Acquire(unsafe.Pointer(&rw.readerSem))
	 121  		race.Acquire(unsafe.Pointer(&rw.writerSem))
	 122  	}
	 123  }
	 124  
	 125  // Unlock unlocks rw for writing. It is a run-time error if rw is
	 126  // not locked for writing on entry to Unlock.
	 127  //
	 128  // As with Mutexes, a locked RWMutex is not associated with a particular
	 129  // goroutine. One goroutine may RLock (Lock) a RWMutex and then
	 130  // arrange for another goroutine to RUnlock (Unlock) it.
	 131  func (rw *RWMutex) Unlock() {
	 132  	if race.Enabled {
	 133  		_ = rw.w.state
	 134  		race.Release(unsafe.Pointer(&rw.readerSem))
	 135  		race.Disable()
	 136  	}
	 137  
	 138  	// Announce to readers there is no active writer.
	 139  	r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
	 140  	if r >= rwmutexMaxReaders {
	 141  		race.Enable()
	 142  		throw("sync: Unlock of unlocked RWMutex")
	 143  	}
	 144  	// Unblock blocked readers, if any.
	 145  	for i := 0; i < int(r); i++ {
	 146  		runtime_Semrelease(&rw.readerSem, false, 0)
	 147  	}
	 148  	// Allow other writers to proceed.
	 149  	rw.w.Unlock()
	 150  	if race.Enabled {
	 151  		race.Enable()
	 152  	}
	 153  }
	 154  
	 155  // RLocker returns a Locker interface that implements
	 156  // the Lock and Unlock methods by calling rw.RLock and rw.RUnlock.
	 157  func (rw *RWMutex) RLocker() Locker {
	 158  	return (*rlocker)(rw)
	 159  }
	 160  
	 161  type rlocker RWMutex
	 162  
	 163  func (r *rlocker) Lock()	 { (*RWMutex)(r).RLock() }
	 164  func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }
	 165  

View as plain text