github.com/lzhfromustc/gofuzz@v0.0.0-20211116160056-151b3108bbd1/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  	"internal/race"
     9  	"runtime"
    10  	"sync/atomic"
    11  	"unsafe"
    12  )
    13  
    14  // There is a modified copy of this file in runtime/rwmutex.go.
    15  // If you make any changes here, see if you should make them there.
    16  
    17  // A RWMutex is a reader/writer mutual exclusion lock.
    18  // The lock can be held by an arbitrary number of readers or a single writer.
    19  // The zero value for a RWMutex is an unlocked mutex.
    20  //
    21  // A RWMutex must not be copied after first use.
    22  //
    23  // If a goroutine holds a RWMutex for reading and another goroutine might
    24  // call Lock, no goroutine should expect to be able to acquire a read lock
    25  // until the initial read lock is released. In particular, this prohibits
    26  // recursive read locking. This is to ensure that the lock eventually becomes
    27  // available; a blocked Lock call excludes new readers from acquiring the
    28  // lock.
    29  type RWMutex struct {
    30  	w           Mutex  // held if there are pending writers
    31  	writerSem   uint32 // semaphore for writers to wait for completing readers
    32  	readerSem   uint32 // semaphore for readers to wait for completing writers
    33  	readerCount int32  // number of pending readers
    34  	readerWait  int32  // number of departing readers
    35  
    36  	///MYCODE
    37  	Record TradRecord
    38  	Info runtime.RWMuInfo
    39  }
    40  
    41  const rwmutexMaxReaders = 1 << 30
    42  
    43  // Happens-before relationships are indicated to the race detector via:
    44  // - Unlock  -> Lock:  readerSem
    45  // - Unlock  -> RLock: readerSem
    46  // - RUnlock -> Lock:  writerSem
    47  //
    48  // The methods below temporarily disable handling of race synchronization
    49  // events in order to provide the more precise model above to the race
    50  // detector.
    51  //
    52  // For example, atomic.AddInt32 in RLock should not appear to provide
    53  // acquire-release semantics, which would incorrectly synchronize racing
    54  // readers, thus potentially missing races.
    55  
    56  // RLock locks rw for reading.
    57  //
    58  // It should not be used for recursive read locking; a blocked Lock
    59  // call excludes new readers from acquiring the lock. See the
    60  // documentation on the RWMutex type.
    61  func (rw *RWMutex) RLock() {
    62  	///MYCODE:
    63  	blockEntry := runtime.EnqueueBlockEntry([]runtime.PrimInfo{&rw.Info}, runtime.MuLock)
    64  	defer runtime.DequeueBlockEntry(blockEntry)
    65  	runtime.Monitor(&rw.Info)
    66  
    67  	if runtime.BoolRecordTrad {
    68  		runtime.RecordTradOp(&rw.Record.PreLoc)
    69  	}
    70  
    71  	if race.Enabled {
    72  		_ = rw.w.state
    73  		race.Disable()
    74  	}
    75  	if atomic.AddInt32(&rw.readerCount, 1) < 0 {
    76  		// A writer is pending, wait for it.
    77  		runtime_SemacquireMutex(&rw.readerSem, false, 0)
    78  	}
    79  	if race.Enabled {
    80  		race.Enable()
    81  		race.Acquire(unsafe.Pointer(&rw.readerSem))
    82  	}
    83  }
    84  
    85  // RUnlock undoes a single RLock call;
    86  // it does not affect other simultaneous readers.
    87  // It is a run-time error if rw is not locked for reading
    88  // on entry to RUnlock.
    89  func (rw *RWMutex) RUnlock() {
    90  	///MYCODE:
    91  	runtime.Monitor(&rw.Info)
    92  	if runtime.BoolRecordTrad {
    93  		runtime.RecordTradOp(&rw.Record.PreLoc)
    94  	}
    95  
    96  	if race.Enabled {
    97  		_ = rw.w.state
    98  		race.ReleaseMerge(unsafe.Pointer(&rw.writerSem))
    99  		race.Disable()
   100  	}
   101  	if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
   102  		// Outlined slow-path to allow the fast-path to be inlined
   103  		rw.rUnlockSlow(r)
   104  	}
   105  	if race.Enabled {
   106  		race.Enable()
   107  	}
   108  }
   109  
   110  func (rw *RWMutex) rUnlockSlow(r int32) {
   111  	if r+1 == 0 || r+1 == -rwmutexMaxReaders {
   112  		race.Enable()
   113  		throw("sync: RUnlock of unlocked RWMutex")
   114  	}
   115  	// A writer is pending.
   116  	if atomic.AddInt32(&rw.readerWait, -1) == 0 {
   117  		// The last reader unblocks the writer.
   118  		runtime_Semrelease(&rw.writerSem, false, 1)
   119  	}
   120  }
   121  
   122  // Lock locks rw for writing.
   123  // If the lock is already locked for reading or writing,
   124  // Lock blocks until the lock is available.
   125  func (rw *RWMutex) Lock() {
   126  	///MYCODE:
   127  	blockEntry := runtime.EnqueueBlockEntry([]runtime.PrimInfo{&rw.Info}, runtime.MuLock)
   128  	defer runtime.DequeueBlockEntry(blockEntry)
   129  	runtime.Monitor(&rw.Info)
   130  	if runtime.BoolRecordTrad {
   131  		runtime.RecordTradOp(&rw.Record.PreLoc)
   132  	}
   133  
   134  	if race.Enabled {
   135  		_ = rw.w.state
   136  		race.Disable()
   137  	}
   138  	// First, resolve competition with other writers.
   139  	rw.w.Lock()
   140  	// Announce to readers there is a pending writer.
   141  	r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
   142  	// Wait for active readers.
   143  	if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
   144  		runtime_SemacquireMutex(&rw.writerSem, false, 0)
   145  	}
   146  	if race.Enabled {
   147  		race.Enable()
   148  		race.Acquire(unsafe.Pointer(&rw.readerSem))
   149  		race.Acquire(unsafe.Pointer(&rw.writerSem))
   150  	}
   151  }
   152  
   153  // Unlock unlocks rw for writing. It is a run-time error if rw is
   154  // not locked for writing on entry to Unlock.
   155  //
   156  // As with Mutexes, a locked RWMutex is not associated with a particular
   157  // goroutine. One goroutine may RLock (Lock) a RWMutex and then
   158  // arrange for another goroutine to RUnlock (Unlock) it.
   159  func (rw *RWMutex) Unlock() {
   160  	///MYCODE:
   161  	runtime.Monitor(&rw.Info)
   162  	if runtime.BoolRecordTrad {
   163  		runtime.RecordTradOp(&rw.Record.PreLoc)
   164  	}
   165  
   166  	if race.Enabled {
   167  		_ = rw.w.state
   168  		race.Release(unsafe.Pointer(&rw.readerSem))
   169  		race.Disable()
   170  	}
   171  
   172  	// Announce to readers there is no active writer.
   173  	r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
   174  	if r >= rwmutexMaxReaders {
   175  		race.Enable()
   176  		throw("sync: Unlock of unlocked RWMutex")
   177  	}
   178  	// Unblock blocked readers, if any.
   179  	for i := 0; i < int(r); i++ {
   180  		runtime_Semrelease(&rw.readerSem, false, 0)
   181  	}
   182  	// Allow other writers to proceed.
   183  	rw.w.Unlock()
   184  	if race.Enabled {
   185  		race.Enable()
   186  	}
   187  }
   188  
   189  // RLocker returns a Locker interface that implements
   190  // the Lock and Unlock methods by calling rw.RLock and rw.RUnlock.
   191  func (rw *RWMutex) RLocker() Locker {
   192  	return (*rlocker)(rw)
   193  }
   194  
   195  type rlocker RWMutex
   196  
   197  func (r *rlocker) Lock()   { (*RWMutex)(r).RLock() }
   198  func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }