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 }