github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/util/syncutil/mutex_sync_race.go (about)

     1  // Copyright 2016 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  //go:build !deadlock && race
    12  // +build !deadlock,race
    13  
    14  package syncutil
    15  
    16  import (
    17  	"sync"
    18  	"sync/atomic"
    19  )
    20  
    21  // DeadlockEnabled is true if the deadlock detector is enabled.
    22  const DeadlockEnabled = false
    23  
    24  // A Mutex is a mutual exclusion lock.
    25  type Mutex struct {
    26  	mu      sync.Mutex
    27  	wLocked int32 // updated atomically
    28  }
    29  
    30  // Lock locks m.
    31  func (m *Mutex) Lock() {
    32  	m.mu.Lock()
    33  	atomic.StoreInt32(&m.wLocked, 1)
    34  }
    35  
    36  // Unlock unlocks m.
    37  func (m *Mutex) Unlock() {
    38  	atomic.StoreInt32(&m.wLocked, 0)
    39  	m.mu.Unlock()
    40  }
    41  
    42  // AssertHeld may panic if the mutex is not locked (but it is not required to
    43  // do so). Functions which require that their callers hold a particular lock
    44  // may use this to enforce this requirement more directly than relying on the
    45  // race detector.
    46  //
    47  // Note that we do not require the lock to be held by any particular thread,
    48  // just that some thread holds the lock. This is both more efficient and allows
    49  // for rare cases where a mutex is locked in one thread and used in another.
    50  func (m *Mutex) AssertHeld() {
    51  	if atomic.LoadInt32(&m.wLocked) == 0 {
    52  		panic("mutex is not write locked")
    53  	}
    54  }
    55  
    56  // An RWMutex is a reader/writer mutual exclusion lock.
    57  type RWMutex struct {
    58  	sync.RWMutex
    59  	wLocked int32 // updated atomically
    60  	rLocked int32 // updated atomically
    61  }
    62  
    63  // Lock locks rw for writing.
    64  func (rw *RWMutex) Lock() {
    65  	rw.RWMutex.Lock()
    66  	atomic.StoreInt32(&rw.wLocked, 1)
    67  }
    68  
    69  // Unlock unlocks rw for writing.
    70  func (rw *RWMutex) Unlock() {
    71  	atomic.StoreInt32(&rw.wLocked, 0)
    72  	rw.RWMutex.Unlock()
    73  }
    74  
    75  // RLock locks m for reading.
    76  func (rw *RWMutex) RLock() {
    77  	rw.RWMutex.RLock()
    78  	atomic.AddInt32(&rw.rLocked, 1)
    79  }
    80  
    81  // RUnlock undoes a single RLock call.
    82  func (rw *RWMutex) RUnlock() {
    83  	atomic.AddInt32(&rw.rLocked, -1)
    84  	rw.RWMutex.RUnlock()
    85  }
    86  
    87  // RLocker returns a Locker interface that implements
    88  // the Lock and Unlock methods by calling rw.RLock and rw.RUnlock.
    89  func (rw *RWMutex) RLocker() sync.Locker {
    90  	return (*rlocker)(rw)
    91  }
    92  
    93  type rlocker RWMutex
    94  
    95  func (r *rlocker) Lock()   { (*RWMutex)(r).RLock() }
    96  func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }
    97  
    98  // AssertHeld may panic if the mutex is not locked for writing (but it is not
    99  // required to do so). Functions which require that their callers hold a
   100  // particular lock may use this to enforce this requirement more directly than
   101  // relying on the race detector.
   102  //
   103  // Note that we do not require the exclusive lock to be held by any particular
   104  // thread, just that some thread holds the lock. This is both more efficient
   105  // and allows for rare cases where a mutex is locked in one thread and used in
   106  // another.
   107  func (rw *RWMutex) AssertHeld() {
   108  	if atomic.LoadInt32(&rw.wLocked) == 0 {
   109  		panic("mutex is not write locked")
   110  	}
   111  }
   112  
   113  // AssertRHeld may panic if the mutex is not locked for reading (but it is not
   114  // required to do so). If the mutex is locked for writing, it is also considered
   115  // to be locked for reading. Functions which require that their callers hold a
   116  // particular lock may use this to enforce this requirement more directly than
   117  // relying on the race detector.
   118  //
   119  // Note that we do not require the shared lock to be held by any particular
   120  // thread, just that some thread holds the lock. This is both more efficient
   121  // and allows for rare cases where a mutex is locked in one thread and used in
   122  // another.
   123  func (rw *RWMutex) AssertRHeld() {
   124  	if atomic.LoadInt32(&rw.wLocked) == 0 && atomic.LoadInt32(&rw.rLocked) == 0 {
   125  		panic("mutex is not read locked")
   126  	}
   127  }