github.com/spotify/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/pkg/sync/rwmutex.go (about)

     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  	"sync/atomic"
     9  	"unsafe"
    10  )
    11  
    12  // An RWMutex is a reader/writer mutual exclusion lock.
    13  // The lock can be held by an arbitrary number of readers
    14  // or a single writer.
    15  // RWMutexes can be created as part of other
    16  // structures; the zero value for a RWMutex is
    17  // an unlocked mutex.
    18  type RWMutex struct {
    19  	w           Mutex  // held if there are pending writers
    20  	writerSem   uint32 // semaphore for writers to wait for completing readers
    21  	readerSem   uint32 // semaphore for readers to wait for completing writers
    22  	readerCount int32  // number of pending readers
    23  	readerWait  int32  // number of departing readers
    24  }
    25  
    26  const rwmutexMaxReaders = 1 << 30
    27  
    28  // RLock locks rw for reading.
    29  func (rw *RWMutex) RLock() {
    30  	if raceenabled {
    31  		_ = rw.w.state
    32  		raceDisable()
    33  	}
    34  	if atomic.AddInt32(&rw.readerCount, 1) < 0 {
    35  		// A writer is pending, wait for it.
    36  		runtime_Semacquire(&rw.readerSem)
    37  	}
    38  	if raceenabled {
    39  		raceEnable()
    40  		raceAcquire(unsafe.Pointer(&rw.readerSem))
    41  	}
    42  }
    43  
    44  // RUnlock undoes a single RLock call;
    45  // it does not affect other simultaneous readers.
    46  // It is a run-time error if rw is not locked for reading
    47  // on entry to RUnlock.
    48  func (rw *RWMutex) RUnlock() {
    49  	if raceenabled {
    50  		_ = rw.w.state
    51  		raceReleaseMerge(unsafe.Pointer(&rw.writerSem))
    52  		raceDisable()
    53  	}
    54  	if atomic.AddInt32(&rw.readerCount, -1) < 0 {
    55  		// A writer is pending.
    56  		if atomic.AddInt32(&rw.readerWait, -1) == 0 {
    57  			// The last reader unblocks the writer.
    58  			runtime_Semrelease(&rw.writerSem)
    59  		}
    60  	}
    61  	if raceenabled {
    62  		raceEnable()
    63  	}
    64  }
    65  
    66  // Lock locks rw for writing.
    67  // If the lock is already locked for reading or writing,
    68  // Lock blocks until the lock is available.
    69  // To ensure that the lock eventually becomes available,
    70  // a blocked Lock call excludes new readers from acquiring
    71  // the lock.
    72  func (rw *RWMutex) Lock() {
    73  	if raceenabled {
    74  		_ = rw.w.state
    75  		raceDisable()
    76  	}
    77  	// First, resolve competition with other writers.
    78  	rw.w.Lock()
    79  	// Announce to readers there is a pending writer.
    80  	r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
    81  	// Wait for active readers.
    82  	if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
    83  		runtime_Semacquire(&rw.writerSem)
    84  	}
    85  	if raceenabled {
    86  		raceEnable()
    87  		raceAcquire(unsafe.Pointer(&rw.readerSem))
    88  		raceAcquire(unsafe.Pointer(&rw.writerSem))
    89  	}
    90  }
    91  
    92  // Unlock unlocks rw for writing.  It is a run-time error if rw is
    93  // not locked for writing on entry to Unlock.
    94  //
    95  // As with Mutexes, a locked RWMutex is not associated with a particular
    96  // goroutine.  One goroutine may RLock (Lock) an RWMutex and then
    97  // arrange for another goroutine to RUnlock (Unlock) it.
    98  func (rw *RWMutex) Unlock() {
    99  	if raceenabled {
   100  		_ = rw.w.state
   101  		raceRelease(unsafe.Pointer(&rw.readerSem))
   102  		raceRelease(unsafe.Pointer(&rw.writerSem))
   103  		raceDisable()
   104  	}
   105  
   106  	// Announce to readers there is no active writer.
   107  	r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
   108  	// Unblock blocked readers, if any.
   109  	for i := 0; i < int(r); i++ {
   110  		runtime_Semrelease(&rw.readerSem)
   111  	}
   112  	// Allow other writers to proceed.
   113  	rw.w.Unlock()
   114  	if raceenabled {
   115  		raceEnable()
   116  	}
   117  }
   118  
   119  // RLocker returns a Locker interface that implements
   120  // the Lock and Unlock methods by calling rw.RLock and rw.RUnlock.
   121  func (rw *RWMutex) RLocker() Locker {
   122  	return (*rlocker)(rw)
   123  }
   124  
   125  type rlocker RWMutex
   126  
   127  func (r *rlocker) Lock()   { (*RWMutex)(r).RLock() }
   128  func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }