github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sync/mutex_unsafe.go (about) 1 // Copyright 2019 The gVisor Authors. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 // +build go1.13 7 // +build !go1.18 8 9 // When updating the build constraint (above), check that syncMutex matches the 10 // standard library sync.Mutex definition. 11 12 package sync 13 14 import ( 15 "sync" 16 "sync/atomic" 17 "unsafe" 18 ) 19 20 // CrossGoroutineMutex is equivalent to Mutex, but it need not be unlocked by a 21 // the same goroutine that locked the mutex. 22 type CrossGoroutineMutex struct { 23 sync.Mutex 24 } 25 26 type syncMutex struct { 27 state int32 28 sema uint32 29 } 30 31 func (m *CrossGoroutineMutex) state() *int32 { 32 return &(*syncMutex)(unsafe.Pointer(&m.Mutex)).state 33 } 34 35 // Lock locks the underlying Mutex. 36 // +checklocksignore 37 func (m *CrossGoroutineMutex) Lock() { 38 m.Mutex.Lock() 39 } 40 41 // Unlock unlocks the underlying Mutex. 42 // +checklocksignore 43 func (m *CrossGoroutineMutex) Unlock() { 44 m.Mutex.Unlock() 45 } 46 47 const ( 48 mutexUnlocked = 0 49 mutexLocked = 1 50 ) 51 52 // TryLock tries to acquire the mutex. It returns true if it succeeds and false 53 // otherwise. TryLock does not block. 54 func (m *CrossGoroutineMutex) TryLock() bool { 55 if atomic.CompareAndSwapInt32(m.state(), mutexUnlocked, mutexLocked) { 56 if RaceEnabled { 57 RaceAcquire(unsafe.Pointer(&m.Mutex)) 58 } 59 return true 60 } 61 return false 62 } 63 64 // Mutex is a mutual exclusion lock. The zero value for a Mutex is an unlocked 65 // mutex. 66 // 67 // A Mutex must not be copied after first use. 68 // 69 // A Mutex must be unlocked by the same goroutine that locked it. This 70 // invariant is enforced with the 'checklocks' build tag. 71 type Mutex struct { 72 m CrossGoroutineMutex 73 } 74 75 // Lock locks m. If the lock is already in use, the calling goroutine blocks 76 // until the mutex is available. 77 // +checklocksignore 78 func (m *Mutex) Lock() { 79 noteLock(unsafe.Pointer(m)) 80 m.m.Lock() 81 } 82 83 // Unlock unlocks m. 84 // 85 // Preconditions: 86 // * m is locked. 87 // * m was locked by this goroutine. 88 // +checklocksignore 89 func (m *Mutex) Unlock() { 90 noteUnlock(unsafe.Pointer(m)) 91 m.m.Unlock() 92 } 93 94 // TryLock tries to acquire the mutex. It returns true if it succeeds and false 95 // otherwise. TryLock does not block. 96 // +checklocksignore 97 func (m *Mutex) TryLock() bool { 98 // Note lock first to enforce proper locking even if unsuccessful. 99 noteLock(unsafe.Pointer(m)) 100 locked := m.m.TryLock() 101 if !locked { 102 noteUnlock(unsafe.Pointer(m)) 103 } 104 return locked 105 }