github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/src/runtime/race1.go (about) 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 global data (data+bss). 85 var racedatastart uintptr 86 var racedataend uintptr 87 88 // start/end of heap for race_amd64.s 89 var racearenastart uintptr 90 var racearenaend uintptr 91 92 func racefuncenter(uintptr) 93 func racefuncexit() 94 func racereadrangepc1(uintptr, uintptr, uintptr) 95 func racewriterangepc1(uintptr, uintptr, uintptr) 96 func racesymbolizethunk(uintptr) 97 98 // racecall allows calling an arbitrary function f from C race runtime 99 // with up to 4 uintptr arguments. 100 func racecall(*byte, uintptr, uintptr, uintptr, uintptr) 101 102 // checks if the address has shadow (i.e. heap or data/bss) 103 //go:nosplit 104 func isvalidaddr(addr unsafe.Pointer) bool { 105 return racearenastart <= uintptr(addr) && uintptr(addr) < racearenaend || 106 racedatastart <= uintptr(addr) && uintptr(addr) < racedataend 107 } 108 109 //go:nosplit 110 func raceinit() uintptr { 111 // cgo is required to initialize libc, which is used by race runtime 112 if !iscgo { 113 gothrow("raceinit: race build must use cgo") 114 } 115 116 var racectx uintptr 117 racecall(&__tsan_init, uintptr(unsafe.Pointer(&racectx)), funcPC(racesymbolizethunk), 0, 0) 118 119 // Round data segment to page boundaries, because it's used in mmap(). 120 start := ^uintptr(0) 121 end := uintptr(0) 122 if start > uintptr(unsafe.Pointer(&noptrdata)) { 123 start = uintptr(unsafe.Pointer(&noptrdata)) 124 } 125 if start > uintptr(unsafe.Pointer(&data)) { 126 start = uintptr(unsafe.Pointer(&data)) 127 } 128 if start > uintptr(unsafe.Pointer(&noptrbss)) { 129 start = uintptr(unsafe.Pointer(&noptrbss)) 130 } 131 if start > uintptr(unsafe.Pointer(&bss)) { 132 start = uintptr(unsafe.Pointer(&bss)) 133 } 134 if end < uintptr(unsafe.Pointer(&enoptrdata)) { 135 end = uintptr(unsafe.Pointer(&enoptrdata)) 136 } 137 if end < uintptr(unsafe.Pointer(&edata)) { 138 end = uintptr(unsafe.Pointer(&edata)) 139 } 140 if end < uintptr(unsafe.Pointer(&enoptrbss)) { 141 end = uintptr(unsafe.Pointer(&enoptrbss)) 142 } 143 if end < uintptr(unsafe.Pointer(&ebss)) { 144 end = uintptr(unsafe.Pointer(&ebss)) 145 } 146 size := round(end-start, _PageSize) 147 racecall(&__tsan_map_shadow, start, size, 0, 0) 148 racedatastart = start 149 racedataend = start + size 150 151 return racectx 152 } 153 154 //go:nosplit 155 func racefini() { 156 racecall(&__tsan_fini, 0, 0, 0, 0) 157 } 158 159 //go:nosplit 160 func racemapshadow(addr unsafe.Pointer, size uintptr) { 161 if racearenastart == 0 { 162 racearenastart = uintptr(addr) 163 } 164 if racearenaend < uintptr(addr)+size { 165 racearenaend = uintptr(addr) + size 166 } 167 racecall(&__tsan_map_shadow, uintptr(addr), size, 0, 0) 168 } 169 170 //go:nosplit 171 func racemalloc(p unsafe.Pointer, sz uintptr) { 172 racecall(&__tsan_malloc, uintptr(p), sz, 0, 0) 173 } 174 175 //go:nosplit 176 func racegostart(pc uintptr) uintptr { 177 _g_ := getg() 178 var spawng *g 179 if _g_.m.curg != nil { 180 spawng = _g_.m.curg 181 } else { 182 spawng = _g_ 183 } 184 185 var racectx uintptr 186 racecall(&__tsan_go_start, spawng.racectx, uintptr(unsafe.Pointer(&racectx)), pc, 0) 187 return racectx 188 } 189 190 //go:nosplit 191 func racegoend() { 192 racecall(&__tsan_go_end, getg().racectx, 0, 0, 0) 193 } 194 195 //go:nosplit 196 func racewriterangepc(addr unsafe.Pointer, sz, callpc, pc uintptr) { 197 _g_ := getg() 198 if _g_ != _g_.m.curg { 199 // The call is coming from manual instrumentation of Go code running on g0/gsignal. 200 // Not interesting. 201 return 202 } 203 if callpc != 0 { 204 racefuncenter(callpc) 205 } 206 racewriterangepc1(uintptr(addr), sz, pc) 207 if callpc != 0 { 208 racefuncexit() 209 } 210 } 211 212 //go:nosplit 213 func racereadrangepc(addr unsafe.Pointer, sz, callpc, pc uintptr) { 214 _g_ := getg() 215 if _g_ != _g_.m.curg { 216 // The call is coming from manual instrumentation of Go code running on g0/gsignal. 217 // Not interesting. 218 return 219 } 220 if callpc != 0 { 221 racefuncenter(callpc) 222 } 223 racereadrangepc1(uintptr(addr), sz, pc) 224 if callpc != 0 { 225 racefuncexit() 226 } 227 } 228 229 //go:nosplit 230 func racewriteobjectpc(addr unsafe.Pointer, t *_type, callpc, pc uintptr) { 231 kind := t.kind & _KindMask 232 if kind == _KindArray || kind == _KindStruct { 233 racewriterangepc(addr, t.size, callpc, pc) 234 } else { 235 racewritepc(addr, callpc, pc) 236 } 237 } 238 239 //go:nosplit 240 func racereadobjectpc(addr unsafe.Pointer, t *_type, callpc, pc uintptr) { 241 kind := t.kind & _KindMask 242 if kind == _KindArray || kind == _KindStruct { 243 racereadrangepc(addr, t.size, callpc, pc) 244 } else { 245 racereadpc(addr, callpc, pc) 246 } 247 } 248 249 //go:nosplit 250 func raceacquire(addr unsafe.Pointer) { 251 raceacquireg(getg(), addr) 252 } 253 254 //go:nosplit 255 func raceacquireg(gp *g, addr unsafe.Pointer) { 256 if getg().raceignore != 0 || !isvalidaddr(addr) { 257 return 258 } 259 racecall(&__tsan_acquire, gp.racectx, uintptr(addr), 0, 0) 260 } 261 262 //go:nosplit 263 func racerelease(addr unsafe.Pointer) { 264 _g_ := getg() 265 if _g_.raceignore != 0 || !isvalidaddr(addr) { 266 return 267 } 268 racereleaseg(_g_, addr) 269 } 270 271 //go:nosplit 272 func racereleaseg(gp *g, addr unsafe.Pointer) { 273 if getg().raceignore != 0 || !isvalidaddr(addr) { 274 return 275 } 276 racecall(&__tsan_release, gp.racectx, uintptr(addr), 0, 0) 277 } 278 279 //go:nosplit 280 func racereleasemerge(addr unsafe.Pointer) { 281 racereleasemergeg(getg(), addr) 282 } 283 284 //go:nosplit 285 func racereleasemergeg(gp *g, addr unsafe.Pointer) { 286 if getg().raceignore != 0 || !isvalidaddr(addr) { 287 return 288 } 289 racecall(&__tsan_release_merge, gp.racectx, uintptr(addr), 0, 0) 290 } 291 292 //go:nosplit 293 func racefingo() { 294 racecall(&__tsan_finalizer_goroutine, getg().racectx, 0, 0, 0) 295 } 296 297 //go:nosplit 298 299 func RaceAcquire(addr unsafe.Pointer) { 300 raceacquire(addr) 301 } 302 303 //go:nosplit 304 305 func RaceRelease(addr unsafe.Pointer) { 306 racerelease(addr) 307 } 308 309 //go:nosplit 310 311 func RaceReleaseMerge(addr unsafe.Pointer) { 312 racereleasemerge(addr) 313 } 314 315 //go:nosplit 316 317 // RaceEnable re-enables handling of race events in the current goroutine. 318 func RaceDisable() { 319 _g_ := getg() 320 if _g_.raceignore == 0 { 321 racecall(&__tsan_go_ignore_sync_begin, _g_.racectx, 0, 0, 0) 322 } 323 _g_.raceignore++ 324 } 325 326 //go:nosplit 327 328 // RaceDisable disables handling of race events in the current goroutine. 329 func RaceEnable() { 330 _g_ := getg() 331 _g_.raceignore-- 332 if _g_.raceignore == 0 { 333 racecall(&__tsan_go_ignore_sync_end, _g_.racectx, 0, 0, 0) 334 } 335 }