...
Run Format

Source file src/sync/rwmutex.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()
  			throw("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()
  		throw("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() }
  

View as plain text