@@ -6,34 +6,34 @@ import (
66)
77
88type Mutex struct {
9- locked bool
10- blocked task.Stack
9+ futex task.Futex
1110}
1211
1312//go:linkname scheduleTask runtime.scheduleTask
1413func scheduleTask (* task.Task )
1514
1615func (m * Mutex ) Lock () {
17- if m .locked {
18- // Push self onto stack of blocked tasks, and wait to be resumed.
19- m .blocked .Push (task .Current ())
20- task .Pause ()
16+ // Fast path: try to take an uncontended lock.
17+ if m .futex .CompareAndSwap (0 , 1 ) {
18+ // We obtained the mutex.
2119 return
2220 }
2321
24- m .locked = true
22+ // Try to lock the mutex. If it changed from 0 to 2, we took a contended
23+ // lock.
24+ for m .futex .Swap (2 ) != 0 {
25+ // Wait until we get resumed in Unlock.
26+ m .futex .Wait (2 )
27+ }
2528}
2629
2730func (m * Mutex ) Unlock () {
28- if ! m .locked {
31+ if old := m .futex .Swap (0 ); old == 0 {
32+ // Mutex wasn't locked before.
2933 panic ("sync: unlock of unlocked Mutex" )
30- }
31-
32- // Wake up a blocked task, if applicable.
33- if t := m .blocked .Pop (); t != nil {
34- scheduleTask (t )
35- } else {
36- m .locked = false
34+ } else if old == 2 {
35+ // Mutex was a contended lock, so we need to wake the next waiter.
36+ m .futex .Wake ()
3737 }
3838}
3939
@@ -43,11 +43,12 @@ func (m *Mutex) Unlock() {
4343// and use of TryLock is often a sign of a deeper problem
4444// in a particular use of mutexes.
4545func (m * Mutex ) TryLock () bool {
46- if m .locked {
47- return false
46+ // Fast path: try to take an uncontended lock.
47+ if m .futex .CompareAndSwap (0 , 1 ) {
48+ // We obtained the mutex.
49+ return true
4850 }
49- m .Lock ()
50- return true
51+ return false
5152}
5253
5354type RWMutex struct {
0 commit comments