-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspinlock.go
74 lines (63 loc) · 1.29 KB
/
spinlock.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package cachePool
import (
"sync/atomic"
_ "unsafe"
)
/*
//this is from allenxuxu
func (l *SpinLock) Lock() {
for !atomic.CompareAndSwapUintptr(&l.lock, 0, 1) {
runtime.Gosched()
}
}
func (l *SpinLock) Unlock() {
atomic.StoreUintptr(&l.lock, 0)
}
*/
func getPid() int {
pid := procPin()
procUnpin()
return pid
}
type SpinLock struct {
lock uint32
}
//go:linkname procPin runtime.procPin
func procPin() int
//go:linkname procUnpin runtime.procUnpin
func procUnpin()
func NewSpinLock() *SpinLock {
return &SpinLock{}
}
/*
if current goroutine Lock() and then schedule away, next goroutine may be loop
dead in Lock(), until the first goroutine running on another P and Unlock(), so
1. make sure between Lokc() and Unlock(), current goroutine don't be scheduled out
by using procPin(). eg. check in sync/atomic/value.go
2. like allenxuxu spinlock, use runtime.Gosched()
*/
func (l *SpinLock) Lock() {
procPin()
for {
//procPin()
if atomic.CompareAndSwapUint32(&l.lock, 0, 1) {
return
}
//procUnpin()
}
}
//Unlock() must be after Lock(), or will painc
func (l *SpinLock) Unlock() {
//n := 0
for {
if atomic.CompareAndSwapUint32(&l.lock, 1, 0) {
procUnpin()
return
}
panic("spinlock unlock fail")
// n++
// if n > 100 {
// panic("spinlock unlock fail")
// }
}
}