diff options
Diffstat (limited to 'src/sync/mutex.go')
-rw-r--r-- | src/sync/mutex.go | 40 |
1 files changed, 35 insertions, 5 deletions
diff --git a/src/sync/mutex.go b/src/sync/mutex.go index e12bf40c1..59f320d5d 100644 --- a/src/sync/mutex.go +++ b/src/sync/mutex.go @@ -3,10 +3,12 @@ package sync import ( "internal/task" _ "unsafe" + + "runtime/volatile" ) type Mutex struct { - locked bool + state uint8 // Set to non-zero if locked. blocked task.Stack } @@ -14,18 +16,18 @@ type Mutex struct { func scheduleTask(*task.Task) func (m *Mutex) Lock() { - if m.locked { + if m.islocked() { // Push self onto stack of blocked tasks, and wait to be resumed. m.blocked.Push(task.Current()) task.Pause() return } - m.locked = true + m.setlock(true) } func (m *Mutex) Unlock() { - if !m.locked { + if !m.islocked() { panic("sync: unlock of unlocked Mutex") } @@ -33,8 +35,36 @@ func (m *Mutex) Unlock() { if t := m.blocked.Pop(); t != nil { scheduleTask(t) } else { - m.locked = false + m.setlock(false) + } +} + +// TryLock tries to lock m and reports whether it succeeded. +// +// Note that while correct uses of TryLock do exist, they are rare, +// and use of TryLock is often a sign of a deeper problem +// in a particular use of mutexes. +func (m *Mutex) TryLock() bool { + if m.islocked() { + return false + } + m.Lock() + return true +} + +func (m *Mutex) islocked() bool { + return volatile.LoadUint8(&m.state) != 0 +} + +func (m *Mutex) setlock(b bool) { + volatile.StoreUint8(&m.state, boolToU8(b)) +} + +func boolToU8(b bool) uint8 { + if b { + return 1 } + return 0 } type RWMutex struct { |