...

Source file src/pkg/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	// 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	// 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.
    43	func (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_SemacquireMutex(&rw.readerSem, false, 0)
    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.
    62	func (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			// Outlined slow-path to allow the fast-path to be inlined
    70			rw.rUnlockSlow(r)
    71		}
    72		if race.Enabled {
    73			race.Enable()
    74		}
    75	}
    76	
    77	func (rw *RWMutex) rUnlockSlow(r int32) {
    78		if r+1 == 0 || r+1 == -rwmutexMaxReaders {
    79			race.Enable()
    80			throw("sync: RUnlock of unlocked RWMutex")
    81		}
    82		// A writer is pending.
    83		if atomic.AddInt32(&rw.readerWait, -1) == 0 {
    84			// The last reader unblocks the writer.
    85			runtime_Semrelease(&rw.writerSem, false, 1)
    86		}
    87	}
    88	
    89	// Lock locks rw for writing.
    90	// If the lock is already locked for reading or writing,
    91	// Lock blocks until the lock is available.
    92	func (rw *RWMutex) Lock() {
    93		if race.Enabled {
    94			_ = rw.w.state
    95			race.Disable()
    96		}
    97		// First, resolve competition with other writers.
    98		rw.w.Lock()
    99		// Announce to readers there is a pending writer.
   100		r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
   101		// Wait for active readers.
   102		if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
   103			runtime_SemacquireMutex(&rw.writerSem, false, 0)
   104		}
   105		if race.Enabled {
   106			race.Enable()
   107			race.Acquire(unsafe.Pointer(&rw.readerSem))
   108			race.Acquire(unsafe.Pointer(&rw.writerSem))
   109		}
   110	}
   111	
   112	// Unlock unlocks rw for writing. It is a run-time error if rw is
   113	// not locked for writing on entry to Unlock.
   114	//
   115	// As with Mutexes, a locked RWMutex is not associated with a particular
   116	// goroutine. One goroutine may RLock (Lock) a RWMutex and then
   117	// arrange for another goroutine to RUnlock (Unlock) it.
   118	func (rw *RWMutex) Unlock() {
   119		if race.Enabled {
   120			_ = rw.w.state
   121			race.Release(unsafe.Pointer(&rw.readerSem))
   122			race.Disable()
   123		}
   124	
   125		// Announce to readers there is no active writer.
   126		r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
   127		if r >= rwmutexMaxReaders {
   128			race.Enable()
   129			throw("sync: Unlock of unlocked RWMutex")
   130		}
   131		// Unblock blocked readers, if any.
   132		for i := 0; i < int(r); i++ {
   133			runtime_Semrelease(&rw.readerSem, false, 0)
   134		}
   135		// Allow other writers to proceed.
   136		rw.w.Unlock()
   137		if race.Enabled {
   138			race.Enable()
   139		}
   140	}
   141	
   142	// RLocker returns a Locker interface that implements
   143	// the Lock and Unlock methods by calling rw.RLock and rw.RUnlock.
   144	func (rw *RWMutex) RLocker() Locker {
   145		return (*rlocker)(rw)
   146	}
   147	
   148	type rlocker RWMutex
   149	
   150	func (r *rlocker) Lock()   { (*RWMutex)(r).RLock() }
   151	func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }
   152	

View as plain text