...
Run Format

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

View as plain text