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 }