Source file src/pkg/sync/mutex.go
1
2
3
4
5
6
7
8
9
10
11 package sync
12
13 import (
14 "sync/atomic"
15 "unsafe"
16 )
17
18
19
20
21 type Mutex struct {
22 state int32
23 sema uint32
24 }
25
26
27 type Locker interface {
28 Lock()
29 Unlock()
30 }
31
32 const (
33 mutexLocked = 1 << iota
34 mutexWoken
35 mutexWaiterShift = iota
36 )
37
38
39
40
41 func (m *Mutex) Lock() {
42
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
59
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
77
78
79
80
81
82 func (m *Mutex) Unlock() {
83 if raceenabled {
84 _ = m.state
85 raceRelease(unsafe.Pointer(m))
86 }
87
88
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
97
98 if old>>mutexWaiterShift == 0 || old&(mutexLocked|mutexWoken) != 0 {
99 return
100 }
101
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 }
View as plain text