rsc.io/go@v0.0.0-20150416155037-e040fd465409/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  		throw("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 > firstmoduledata.noptrdata {
   123  		start = firstmoduledata.noptrdata
   124  	}
   125  	if start > firstmoduledata.data {
   126  		start = firstmoduledata.data
   127  	}
   128  	if start > firstmoduledata.noptrbss {
   129  		start = firstmoduledata.noptrbss
   130  	}
   131  	if start > firstmoduledata.bss {
   132  		start = firstmoduledata.bss
   133  	}
   134  	if end < firstmoduledata.enoptrdata {
   135  		end = firstmoduledata.enoptrdata
   136  	}
   137  	if end < firstmoduledata.edata {
   138  		end = firstmoduledata.edata
   139  	}
   140  	if end < firstmoduledata.enoptrbss {
   141  		end = firstmoduledata.enoptrbss
   142  	}
   143  	if end < firstmoduledata.ebss {
   144  		end = firstmoduledata.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 raceacquire(addr unsafe.Pointer) {
   231  	raceacquireg(getg(), addr)
   232  }
   233  
   234  //go:nosplit
   235  func raceacquireg(gp *g, addr unsafe.Pointer) {
   236  	if getg().raceignore != 0 || !isvalidaddr(addr) {
   237  		return
   238  	}
   239  	racecall(&__tsan_acquire, gp.racectx, uintptr(addr), 0, 0)
   240  }
   241  
   242  //go:nosplit
   243  func racerelease(addr unsafe.Pointer) {
   244  	_g_ := getg()
   245  	if _g_.raceignore != 0 || !isvalidaddr(addr) {
   246  		return
   247  	}
   248  	racereleaseg(_g_, addr)
   249  }
   250  
   251  //go:nosplit
   252  func racereleaseg(gp *g, addr unsafe.Pointer) {
   253  	if getg().raceignore != 0 || !isvalidaddr(addr) {
   254  		return
   255  	}
   256  	racecall(&__tsan_release, gp.racectx, uintptr(addr), 0, 0)
   257  }
   258  
   259  //go:nosplit
   260  func racereleasemerge(addr unsafe.Pointer) {
   261  	racereleasemergeg(getg(), addr)
   262  }
   263  
   264  //go:nosplit
   265  func racereleasemergeg(gp *g, addr unsafe.Pointer) {
   266  	if getg().raceignore != 0 || !isvalidaddr(addr) {
   267  		return
   268  	}
   269  	racecall(&__tsan_release_merge, gp.racectx, uintptr(addr), 0, 0)
   270  }
   271  
   272  //go:nosplit
   273  func racefingo() {
   274  	racecall(&__tsan_finalizer_goroutine, getg().racectx, 0, 0, 0)
   275  }
   276  
   277  //go:nosplit
   278  
   279  func RaceAcquire(addr unsafe.Pointer) {
   280  	raceacquire(addr)
   281  }
   282  
   283  //go:nosplit
   284  
   285  func RaceRelease(addr unsafe.Pointer) {
   286  	racerelease(addr)
   287  }
   288  
   289  //go:nosplit
   290  
   291  func RaceReleaseMerge(addr unsafe.Pointer) {
   292  	racereleasemerge(addr)
   293  }
   294  
   295  //go:nosplit
   296  
   297  // RaceDisable disables handling of race events in the current goroutine.
   298  func RaceDisable() {
   299  	_g_ := getg()
   300  	if _g_.raceignore == 0 {
   301  		racecall(&__tsan_go_ignore_sync_begin, _g_.racectx, 0, 0, 0)
   302  	}
   303  	_g_.raceignore++
   304  }
   305  
   306  //go:nosplit
   307  
   308  // RaceEnable re-enables handling of race events in the current goroutine.
   309  func RaceEnable() {
   310  	_g_ := getg()
   311  	_g_.raceignore--
   312  	if _g_.raceignore == 0 {
   313  		racecall(&__tsan_go_ignore_sync_end, _g_.racectx, 0, 0, 0)
   314  	}
   315  }