github.com/golang-haiku/go-1.4.3@v0.0.0-20190609233734-1f5ae41cc308/src/sync/mutex.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package sync provides basic synchronization primitives such as mutual 6 // exclusion locks. Other than the Once and WaitGroup types, most are intended 7 // for use by low-level library routines. Higher-level synchronization is 8 // better done via channels and communication. 9 // 10 // Values containing the types defined in this package should not be copied. 11 package sync 12 13 import ( 14 "sync/atomic" 15 "unsafe" 16 ) 17 18 // A Mutex is a mutual exclusion lock. 19 // Mutexes can be created as part of other structures; 20 // the zero value for a Mutex is an unlocked mutex. 21 type Mutex struct { 22 state int32 23 sema uint32 24 } 25 26 // A Locker represents an object that can be locked and unlocked. 27 type Locker interface { 28 Lock() 29 Unlock() 30 } 31 32 const ( 33 mutexLocked = 1 << iota // mutex is locked 34 mutexWoken 35 mutexWaiterShift = iota 36 ) 37 38 // Lock locks m. 39 // If the lock is already in use, the calling goroutine 40 // blocks until the mutex is available. 41 func (m *Mutex) Lock() { 42 // Fast path: grab unlocked mutex. 43 if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) { 44 if raceenabled { 45 raceAcquire(unsafe.Pointer(m)) 46 } 47 return 48 } 49 50 awoke := false 51 for { 52 old := m.state 53 new := old | mutexLocked 54 if old&mutexLocked != 0 { 55 new = old + 1<<mutexWaiterShift 56 } 57 if awoke { 58 // The goroutine has been woken from sleep, 59 // so we need to reset the flag in either case. 60 new &^= mutexWoken 61 } 62 if atomic.CompareAndSwapInt32(&m.state, old, new) { 63 if old&mutexLocked == 0 { 64 break 65 } 66 runtime_Semacquire(&m.sema) 67 awoke = true 68 } 69 } 70 71 if raceenabled { 72 raceAcquire(unsafe.Pointer(m)) 73 } 74 } 75 76 // Unlock unlocks m. 77 // It is a run-time error if m is not locked on entry to Unlock. 78 // 79 // A locked Mutex is not associated with a particular goroutine. 80 // It is allowed for one goroutine to lock a Mutex and then 81 // arrange for another goroutine to unlock it. 82 func (m *Mutex) Unlock() { 83 if raceenabled { 84 _ = m.state 85 raceRelease(unsafe.Pointer(m)) 86 } 87 88 // Fast path: drop lock bit. 89 new := atomic.AddInt32(&m.state, -mutexLocked) 90 if (new+mutexLocked)&mutexLocked == 0 { 91 panic("sync: unlock of unlocked mutex") 92 } 93 94 old := new 95 for { 96 // If there are no waiters or a goroutine has already 97 // been woken or grabbed the lock, no need to wake anyone. 98 if old>>mutexWaiterShift == 0 || old&(mutexLocked|mutexWoken) != 0 { 99 return 100 } 101 // Grab the right to wake someone. 102 new = (old - 1<<mutexWaiterShift) | mutexWoken 103 if atomic.CompareAndSwapInt32(&m.state, old, new) { 104 runtime_Semrelease(&m.sema) 105 return 106 } 107 old = m.state 108 } 109 }