Skip to content

Commit 4e6078f

Browse files
committed
sync: implement futex-based Mutex
1 parent cc81a82 commit 4e6078f

File tree

1 file changed

+21
-19
lines changed

1 file changed

+21
-19
lines changed

src/sync/mutex.go

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,40 @@
11
package sync
22

33
import (
4+
"internal/llsync"
45
"internal/task"
56
_ "unsafe"
67
)
78

89
type Mutex struct {
9-
locked bool
10-
blocked task.Stack
10+
futex llsync.Futex
1111
}
1212

1313
//go:linkname resumeTask runtime.resumeTask
1414
func resumeTask(*task.Task)
1515

1616
func (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()
17+
// Fast path: try to take an uncontended lock.
18+
if m.futex.CompareAndSwap(0, 1) {
19+
// We obtained the mutex.
2120
return
2221
}
2322

24-
m.locked = true
23+
// Try to lock the mutex. If it changed from 0 to 2, we took a contended
24+
// lock.
25+
for m.futex.Swap(2) != 0 {
26+
// Wait until we get resumed in Unlock.
27+
m.futex.Wait(2)
28+
}
2529
}
2630

2731
func (m *Mutex) Unlock() {
28-
if !m.locked {
32+
if old := m.futex.Swap(0); old == 0 {
33+
// Mutex wasn't locked before.
2934
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-
resumeTask(t)
35-
} else {
36-
m.locked = false
35+
} else if old == 2 {
36+
// Mutex was a contended lock, so we need to wake the next waiter.
37+
m.futex.Wake()
3738
}
3839
}
3940

@@ -43,11 +44,12 @@ func (m *Mutex) Unlock() {
4344
// and use of TryLock is often a sign of a deeper problem
4445
// in a particular use of mutexes.
4546
func (m *Mutex) TryLock() bool {
46-
if m.locked {
47-
return false
47+
// Fast path: try to take an uncontended lock.
48+
if m.futex.CompareAndSwap(0, 1) {
49+
// We obtained the mutex.
50+
return true
4851
}
49-
m.Lock()
50-
return true
52+
return false
5153
}
5254

5355
type RWMutex struct {

0 commit comments

Comments
 (0)