...
Run Format

Source file src/sync/rwmutex.go

     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				throw("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			throw("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() }
   141	

View as plain text