mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			141 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
// 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 (
 | 
						|
	"internal/race"
 | 
						|
	"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.
 | 
						|
//
 | 
						|
// An RWMutex must not be copied after first use.
 | 
						|
//
 | 
						|
// If a goroutine holds a RWMutex for reading, it must not expect this or any
 | 
						|
// other goroutine to be able to also take the read lock until the first read
 | 
						|
// lock is released. In particular, this prohibits recursive read locking.
 | 
						|
// This is to ensure that the lock eventually becomes available;
 | 
						|
// a blocked Lock call excludes new readers from acquiring the lock.
 | 
						|
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 race.Enabled {
 | 
						|
		_ = rw.w.state
 | 
						|
		race.Disable()
 | 
						|
	}
 | 
						|
	if atomic.AddInt32(&rw.readerCount, 1) < 0 {
 | 
						|
		// A writer is pending, wait for it.
 | 
						|
		runtime_Semacquire(&rw.readerSem)
 | 
						|
	}
 | 
						|
	if race.Enabled {
 | 
						|
		race.Enable()
 | 
						|
		race.Acquire(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 race.Enabled {
 | 
						|
		_ = rw.w.state
 | 
						|
		race.ReleaseMerge(unsafe.Pointer(&rw.writerSem))
 | 
						|
		race.Disable()
 | 
						|
	}
 | 
						|
	if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
 | 
						|
		if r+1 == 0 || r+1 == -rwmutexMaxReaders {
 | 
						|
			race.Enable()
 | 
						|
			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 race.Enabled {
 | 
						|
		race.Enable()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Lock locks rw for writing.
 | 
						|
// If the lock is already locked for reading or writing,
 | 
						|
// Lock blocks until the lock is available.
 | 
						|
func (rw *RWMutex) Lock() {
 | 
						|
	if race.Enabled {
 | 
						|
		_ = rw.w.state
 | 
						|
		race.Disable()
 | 
						|
	}
 | 
						|
	// 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 race.Enabled {
 | 
						|
		race.Enable()
 | 
						|
		race.Acquire(unsafe.Pointer(&rw.readerSem))
 | 
						|
		race.Acquire(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 race.Enabled {
 | 
						|
		_ = rw.w.state
 | 
						|
		race.Release(unsafe.Pointer(&rw.readerSem))
 | 
						|
		race.Release(unsafe.Pointer(&rw.writerSem))
 | 
						|
		race.Disable()
 | 
						|
	}
 | 
						|
 | 
						|
	// Announce to readers there is no active writer.
 | 
						|
	r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
 | 
						|
	if r >= rwmutexMaxReaders {
 | 
						|
		race.Enable()
 | 
						|
		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 race.Enabled {
 | 
						|
		race.Enable()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// 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() }
 |