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  }