-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathlocks_amd64.s
173 lines (160 loc) · 3.99 KB
/
locks_amd64.s
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// +build 386 amd64
// HLE instructions can work on 386 or amd64
#include "textflag.h"
// func Pause()
TEXT ·Pause(SB),NOPTR|NOSPLIT,$0-0
PAUSE
RET
// func Mfence()
TEXT ·Mfence(SB),NOPTR|NOSPLIT,$0-0
MFENCE
RET
// SetAndFence32 writes a 1 to val and asserts an MFENCE.
// func SetAndFence32(val *int32)
TEXT ·SetAndFence32(SB),NOPTR|NOSPLIT,$0
MOVQ val+0(FP), CX
MOVL $1, AX
MOVL AX, (CX)
MFENCE
RET
// Atomically write 1 to val while returning the old value.
// func Lock1XCHG8(val *int8) (old int8)
TEXT ·Lock1XCHG8(SB),NOPTR|NOSPLIT,$0
MOVQ val+0(FP), CX
MOVB $1, AX
LOCK
XCHGB AX, (CX)
MOVB AX, old+8(FP)
RET
// Atomically write 1 to val while returning the old value.
// func Lock1XCHG32(val *int32) (old int32)
TEXT ·Lock1XCHG32(SB),NOPTR|NOSPLIT,$0
MOVQ val+0(FP), CX
MOVL $1, AX
LOCK
XCHGL AX, (CX)
MOVL AX, old+8(FP)
RET
// Atomically write 1 to val while returning the old value.
// func Lock1XCHG64(val *int64) (old int64)
TEXT ·Lock1XCHG64(SB),NOPTR|NOSPLIT,$0
MOVQ val+0(FP), CX
MOVL $1, AX
LOCK
XCHGQ AX, (CX)
MOVQ AX, old+8(FP)
RET
// SpinLock implements a basic spin lock that waits forever until the lock
// can be acquired.
// It assumes the lock has been acquired when it successfully writes a 1 to val,
// while the original value was 0.
// This implementation spins on a read only and then uses the XCHG instruction
// in order to claim the lock. The loop makes use of the PAUSE hint instruction.
// func SpinLock(val *int32)
TEXT ·SpinLock(SB),NOPTR|NOSPLIT,$0
MOVQ val+0(FP), CX
tryread:
MOVL (CX), BX
TESTL BX, BX
JE tryacquire
PAUSE
JMP tryread
tryacquire:
MOVL $1, AX
LOCK
XCHGL AX, (CX)
TESTL AX, AX
JNE tryread
RET
// SpinCountLock implements a basic spin lock that tries to acquire the lock
// only attempts times.
// It assumes the lock has been acquired when it successfully writes a 1 to val,
// while the original value was 0.
// This implementation spins on a read only and then uses the XCHG instruction
// in order to claim the lock. The loop makes use of the PAUSE hint instruction.
// func SpinCountLock(val, attempts *int32)
TEXT ·SpinCountLock(SB),NOPTR|NOSPLIT,$0
MOVQ val+0(FP), CX
// Load attempt counter in DX
MOVQ attempts+8(FP), R8
MOVL (R8), DX
tryread:
MOVL (CX), BX
TESTL BX, BX
JE tryacquire
PAUSE
DECL DX
// If DX != 0, abort
JNE tryread
JMP abort
tryacquire:
MOVL $1, AX
LOCK
XCHGL AX, (CX)
TESTL AX, AX
JNE tryread
abort:
// Write back attempt counter
MOVL DX, (R8)
RET
// HLETryLock attempts only once to acquire the lock by writing a 1 to val
// using HLE primitives. This function returns a 0 if the lock was acquired.
// func HLETryLock(val *int32) (old int32)
TEXT ·HLETryLock(SB),NOPTR|NOSPLIT,$0
MOVQ val+0(FP), CX
MOVL $1, AX
XACQUIRE
XCHGL AX, (CX)
MOVL AX, old+8(FP)
RET
// HLEUnlock writes a 0 to val to indicate the lock has been released
// using HLE primitives
// func HLEUnlock(val *int32)
TEXT ·HLEUnlock(SB),NOPTR|NOSPLIT,$0
MOVQ val+0(FP), CX
MOVL $0, AX
XRELEASE
MOVL AX, (CX)
RET
// func HLESpinLock(val *int32)
TEXT ·HLESpinLock(SB),NOPTR|NOSPLIT,$0
MOVQ val+0(FP), CX
tryread:
MOVL (CX), BX
TESTL BX, BX
JE tryacquire
PAUSE
JMP tryread
tryacquire:
MOVL $1, AX
XACQUIRE
XCHGL AX, (CX)
TESTL AX, AX
JNE tryread
RET
// Note: Argument attempts must be greater than 0
// func HLESpinCountLock(val, attempts *int32)
TEXT ·HLESpinCountLock(SB),NOPTR|NOSPLIT,$0
MOVQ val+0(FP), CX
// Load attempt counter in DX
MOVQ attempts+8(FP), R8
MOVL (R8), DX
tryread:
MOVL (CX), BX
TESTL BX, BX
JE tryacquire
PAUSE
DECL DX
// If DX != 0, abort
JNE tryread
JMP abort
tryacquire:
MOVL $1, AX
XACQUIRE
XCHGL AX, (CX)
TESTL AX, AX
JNE tryread
abort:
// Write back attempt counter
MOVL DX, (R8)
RET