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