]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/race1.go
[dev.cc] all: merge dev.power64 (f57928630b36) into dev.cc
[gostls13.git] / src / runtime / race1.go
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Implementation of the race detector API.
6 // +build race
7
8 package runtime
9
10 import "unsafe"
11
12 // Race runtime functions called via runtime·racecall.
13 //go:linkname __tsan_init __tsan_init
14 var __tsan_init byte
15
16 //go:linkname __tsan_fini __tsan_fini
17 var __tsan_fini byte
18
19 //go:linkname __tsan_map_shadow __tsan_map_shadow
20 var __tsan_map_shadow byte
21
22 //go:linkname __tsan_finalizer_goroutine __tsan_finalizer_goroutine
23 var __tsan_finalizer_goroutine byte
24
25 //go:linkname __tsan_go_start __tsan_go_start
26 var __tsan_go_start byte
27
28 //go:linkname __tsan_go_end __tsan_go_end
29 var __tsan_go_end byte
30
31 //go:linkname __tsan_malloc __tsan_malloc
32 var __tsan_malloc byte
33
34 //go:linkname __tsan_acquire __tsan_acquire
35 var __tsan_acquire byte
36
37 //go:linkname __tsan_release __tsan_release
38 var __tsan_release byte
39
40 //go:linkname __tsan_release_merge __tsan_release_merge
41 var __tsan_release_merge byte
42
43 //go:linkname __tsan_go_ignore_sync_begin __tsan_go_ignore_sync_begin
44 var __tsan_go_ignore_sync_begin byte
45
46 //go:linkname __tsan_go_ignore_sync_end __tsan_go_ignore_sync_end
47 var __tsan_go_ignore_sync_end byte
48
49 // Mimic what cmd/cgo would do.
50 //go:cgo_import_static __tsan_init
51 //go:cgo_import_static __tsan_fini
52 //go:cgo_import_static __tsan_map_shadow
53 //go:cgo_import_static __tsan_finalizer_goroutine
54 //go:cgo_import_static __tsan_go_start
55 //go:cgo_import_static __tsan_go_end
56 //go:cgo_import_static __tsan_malloc
57 //go:cgo_import_static __tsan_acquire
58 //go:cgo_import_static __tsan_release
59 //go:cgo_import_static __tsan_release_merge
60 //go:cgo_import_static __tsan_go_ignore_sync_begin
61 //go:cgo_import_static __tsan_go_ignore_sync_end
62
63 // These are called from race_amd64.s.
64 //go:cgo_import_static __tsan_read
65 //go:cgo_import_static __tsan_read_pc
66 //go:cgo_import_static __tsan_read_range
67 //go:cgo_import_static __tsan_write
68 //go:cgo_import_static __tsan_write_pc
69 //go:cgo_import_static __tsan_write_range
70 //go:cgo_import_static __tsan_func_enter
71 //go:cgo_import_static __tsan_func_exit
72
73 //go:cgo_import_static __tsan_go_atomic32_load
74 //go:cgo_import_static __tsan_go_atomic64_load
75 //go:cgo_import_static __tsan_go_atomic32_store
76 //go:cgo_import_static __tsan_go_atomic64_store
77 //go:cgo_import_static __tsan_go_atomic32_exchange
78 //go:cgo_import_static __tsan_go_atomic64_exchange
79 //go:cgo_import_static __tsan_go_atomic32_fetch_add
80 //go:cgo_import_static __tsan_go_atomic64_fetch_add
81 //go:cgo_import_static __tsan_go_atomic32_compare_exchange
82 //go:cgo_import_static __tsan_go_atomic64_compare_exchange
83
84 // start/end of heap for race_amd64.s
85 var racearenastart uintptr
86 var racearenaend uintptr
87
88 func racefuncenter(uintptr)
89 func racefuncexit()
90 func racereadrangepc1(uintptr, uintptr, uintptr)
91 func racewriterangepc1(uintptr, uintptr, uintptr)
92 func racesymbolizethunk(uintptr)
93
94 // racecall allows calling an arbitrary function f from C race runtime
95 // with up to 4 uintptr arguments.
96 func racecall(*byte, uintptr, uintptr, uintptr, uintptr)
97
98 // checks if the address has shadow (i.e. heap or data/bss)
99 //go:nosplit
100 func isvalidaddr(addr unsafe.Pointer) bool {
101         return racearenastart <= uintptr(addr) && uintptr(addr) < racearenaend ||
102                 uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(addr) && uintptr(addr) < uintptr(unsafe.Pointer(&enoptrbss))
103 }
104
105 //go:nosplit
106 func raceinit() uintptr {
107         // cgo is required to initialize libc, which is used by race runtime
108         if !iscgo {
109                 gothrow("raceinit: race build must use cgo")
110         }
111
112         var racectx uintptr
113         racecall(&__tsan_init, uintptr(unsafe.Pointer(&racectx)), funcPC(racesymbolizethunk), 0, 0)
114
115         // Round data segment to page boundaries, because it's used in mmap().
116         start := uintptr(unsafe.Pointer(&noptrdata)) &^ (_PageSize - 1)
117         size := round(uintptr(unsafe.Pointer(&enoptrbss))-start, _PageSize)
118         racecall(&__tsan_map_shadow, start, size, 0, 0)
119
120         return racectx
121 }
122
123 //go:nosplit
124 func racefini() {
125         racecall(&__tsan_fini, 0, 0, 0, 0)
126 }
127
128 //go:nosplit
129 func racemapshadow(addr unsafe.Pointer, size uintptr) {
130         if racearenastart == 0 {
131                 racearenastart = uintptr(addr)
132         }
133         if racearenaend < uintptr(addr)+size {
134                 racearenaend = uintptr(addr) + size
135         }
136         racecall(&__tsan_map_shadow, uintptr(addr), size, 0, 0)
137 }
138
139 //go:nosplit
140 func racemalloc(p unsafe.Pointer, sz uintptr) {
141         racecall(&__tsan_malloc, uintptr(p), sz, 0, 0)
142 }
143
144 //go:nosplit
145 func racegostart(pc uintptr) uintptr {
146         _g_ := getg()
147         var spawng *g
148         if _g_.m.curg != nil {
149                 spawng = _g_.m.curg
150         } else {
151                 spawng = _g_
152         }
153
154         var racectx uintptr
155         racecall(&__tsan_go_start, spawng.racectx, uintptr(unsafe.Pointer(&racectx)), pc, 0)
156         return racectx
157 }
158
159 //go:nosplit
160 func racegoend() {
161         racecall(&__tsan_go_end, getg().racectx, 0, 0, 0)
162 }
163
164 //go:nosplit
165 func racewriterangepc(addr unsafe.Pointer, sz, callpc, pc uintptr) {
166         _g_ := getg()
167         if _g_ != _g_.m.curg {
168                 // The call is coming from manual instrumentation of Go code running on g0/gsignal.
169                 // Not interesting.
170                 return
171         }
172         if callpc != 0 {
173                 racefuncenter(callpc)
174         }
175         racewriterangepc1(uintptr(addr), sz, pc)
176         if callpc != 0 {
177                 racefuncexit()
178         }
179 }
180
181 //go:nosplit
182 func racereadrangepc(addr unsafe.Pointer, sz, callpc, pc uintptr) {
183         _g_ := getg()
184         if _g_ != _g_.m.curg {
185                 // The call is coming from manual instrumentation of Go code running on g0/gsignal.
186                 // Not interesting.
187                 return
188         }
189         if callpc != 0 {
190                 racefuncenter(callpc)
191         }
192         racereadrangepc1(uintptr(addr), sz, pc)
193         if callpc != 0 {
194                 racefuncexit()
195         }
196 }
197
198 //go:nosplit
199 func racewriteobjectpc(addr unsafe.Pointer, t *_type, callpc, pc uintptr) {
200         kind := t.kind & _KindMask
201         if kind == _KindArray || kind == _KindStruct {
202                 racewriterangepc(addr, t.size, callpc, pc)
203         } else {
204                 racewritepc(addr, callpc, pc)
205         }
206 }
207
208 //go:nosplit
209 func racereadobjectpc(addr unsafe.Pointer, t *_type, callpc, pc uintptr) {
210         kind := t.kind & _KindMask
211         if kind == _KindArray || kind == _KindStruct {
212                 racereadrangepc(addr, t.size, callpc, pc)
213         } else {
214                 racereadpc(addr, callpc, pc)
215         }
216 }
217
218 //go:nosplit
219 func raceacquire(addr unsafe.Pointer) {
220         raceacquireg(getg(), addr)
221 }
222
223 //go:nosplit
224 func raceacquireg(gp *g, addr unsafe.Pointer) {
225         if getg().raceignore != 0 || !isvalidaddr(addr) {
226                 return
227         }
228         racecall(&__tsan_acquire, gp.racectx, uintptr(addr), 0, 0)
229 }
230
231 //go:nosplit
232 func racerelease(addr unsafe.Pointer) {
233         _g_ := getg()
234         if _g_.raceignore != 0 || !isvalidaddr(addr) {
235                 return
236         }
237         racereleaseg(_g_, addr)
238 }
239
240 //go:nosplit
241 func racereleaseg(gp *g, addr unsafe.Pointer) {
242         if getg().raceignore != 0 || !isvalidaddr(addr) {
243                 return
244         }
245         racecall(&__tsan_release, gp.racectx, uintptr(addr), 0, 0)
246 }
247
248 //go:nosplit
249 func racereleasemerge(addr unsafe.Pointer) {
250         racereleasemergeg(getg(), addr)
251 }
252
253 //go:nosplit
254 func racereleasemergeg(gp *g, addr unsafe.Pointer) {
255         if getg().raceignore != 0 || !isvalidaddr(addr) {
256                 return
257         }
258         racecall(&__tsan_release_merge, gp.racectx, uintptr(addr), 0, 0)
259 }
260
261 //go:nosplit
262 func racefingo() {
263         racecall(&__tsan_finalizer_goroutine, getg().racectx, 0, 0, 0)
264 }
265
266 //go:nosplit
267
268 func RaceAcquire(addr unsafe.Pointer) {
269         raceacquire(addr)
270 }
271
272 //go:nosplit
273
274 func RaceRelease(addr unsafe.Pointer) {
275         racerelease(addr)
276 }
277
278 //go:nosplit
279
280 func RaceReleaseMerge(addr unsafe.Pointer) {
281         racereleasemerge(addr)
282 }
283
284 //go:nosplit
285
286 // RaceEnable re-enables handling of race events in the current goroutine.
287 func RaceDisable() {
288         _g_ := getg()
289         if _g_.raceignore == 0 {
290                 racecall(&__tsan_go_ignore_sync_begin, _g_.racectx, 0, 0, 0)
291         }
292         _g_.raceignore++
293 }
294
295 //go:nosplit
296
297 // RaceDisable disables handling of race events in the current goroutine.
298 func RaceEnable() {
299         _g_ := getg()
300         _g_.raceignore--
301         if _g_.raceignore == 0 {
302                 racecall(&__tsan_go_ignore_sync_end, _g_.racectx, 0, 0, 0)
303         }
304 }