github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/runtime/race.go (about)

     1  // Copyright 2012 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  // +build race
     6  
     7  // Public race detection API, present iff build with -race.
     8  
     9  package runtime
    10  
    11  import (
    12  	"unsafe"
    13  )
    14  
    15  func RaceRead(addr unsafe.Pointer)
    16  func RaceWrite(addr unsafe.Pointer)
    17  func RaceReadRange(addr unsafe.Pointer, len int)
    18  func RaceWriteRange(addr unsafe.Pointer, len int)
    19  
    20  func RaceSemacquire(s *uint32)
    21  func RaceSemrelease(s *uint32)
    22  
    23  // private interface for the runtime
    24  const raceenabled = true
    25  
    26  // For all functions accepting callerpc and pc,
    27  // callerpc is a return PC of the function that calls this function,
    28  // pc is start PC of the function that calls this function.
    29  func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) {
    30  	kind := t.kind & kindMask
    31  	if kind == kindArray || kind == kindStruct {
    32  		// for composite objects we have to read every address
    33  		// because a write might happen to any subobject.
    34  		racereadrangepc(addr, t.size, callerpc, pc)
    35  	} else {
    36  		// for non-composite objects we can read just the start
    37  		// address, as any write must write the first byte.
    38  		racereadpc(addr, callerpc, pc)
    39  	}
    40  }
    41  
    42  func raceWriteObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) {
    43  	kind := t.kind & kindMask
    44  	if kind == kindArray || kind == kindStruct {
    45  		// for composite objects we have to write every address
    46  		// because a write might happen to any subobject.
    47  		racewriterangepc(addr, t.size, callerpc, pc)
    48  	} else {
    49  		// for non-composite objects we can write just the start
    50  		// address, as any write must write the first byte.
    51  		racewritepc(addr, callerpc, pc)
    52  	}
    53  }
    54  
    55  //go:noescape
    56  func racereadpc(addr unsafe.Pointer, callpc, pc uintptr)
    57  
    58  //go:noescape
    59  func racewritepc(addr unsafe.Pointer, callpc, pc uintptr)
    60  
    61  type symbolizeContext struct {
    62  	pc   uintptr
    63  	fn   *byte
    64  	file *byte
    65  	line uintptr
    66  	off  uintptr
    67  	res  uintptr
    68  }
    69  
    70  var qq = [...]byte{'?', '?', 0}
    71  var dash = [...]byte{'-', 0}
    72  
    73  // Callback from C into Go, runs on g0.
    74  func racesymbolize(ctx *symbolizeContext) {
    75  	f := findfunc(ctx.pc)
    76  	if f == nil {
    77  		ctx.fn = &qq[0]
    78  		ctx.file = &dash[0]
    79  		ctx.line = 0
    80  		ctx.off = ctx.pc
    81  		ctx.res = 1
    82  		return
    83  	}
    84  
    85  	ctx.fn = cfuncname(f)
    86  	file, line := funcline(f, ctx.pc)
    87  	ctx.line = uintptr(line)
    88  	ctx.file = &bytes(file)[0] // assume NUL-terminated
    89  	ctx.off = ctx.pc - f.entry
    90  	ctx.res = 1
    91  	return
    92  }
    93  
    94  // Race runtime functions called via runtime·racecall.
    95  //go:linkname __tsan_init __tsan_init
    96  var __tsan_init byte
    97  
    98  //go:linkname __tsan_fini __tsan_fini
    99  var __tsan_fini byte
   100  
   101  //go:linkname __tsan_map_shadow __tsan_map_shadow
   102  var __tsan_map_shadow byte
   103  
   104  //go:linkname __tsan_finalizer_goroutine __tsan_finalizer_goroutine
   105  var __tsan_finalizer_goroutine byte
   106  
   107  //go:linkname __tsan_go_start __tsan_go_start
   108  var __tsan_go_start byte
   109  
   110  //go:linkname __tsan_go_end __tsan_go_end
   111  var __tsan_go_end byte
   112  
   113  //go:linkname __tsan_malloc __tsan_malloc
   114  var __tsan_malloc byte
   115  
   116  //go:linkname __tsan_acquire __tsan_acquire
   117  var __tsan_acquire byte
   118  
   119  //go:linkname __tsan_release __tsan_release
   120  var __tsan_release byte
   121  
   122  //go:linkname __tsan_release_merge __tsan_release_merge
   123  var __tsan_release_merge byte
   124  
   125  //go:linkname __tsan_go_ignore_sync_begin __tsan_go_ignore_sync_begin
   126  var __tsan_go_ignore_sync_begin byte
   127  
   128  //go:linkname __tsan_go_ignore_sync_end __tsan_go_ignore_sync_end
   129  var __tsan_go_ignore_sync_end byte
   130  
   131  // Mimic what cmd/cgo would do.
   132  //go:cgo_import_static __tsan_init
   133  //go:cgo_import_static __tsan_fini
   134  //go:cgo_import_static __tsan_map_shadow
   135  //go:cgo_import_static __tsan_finalizer_goroutine
   136  //go:cgo_import_static __tsan_go_start
   137  //go:cgo_import_static __tsan_go_end
   138  //go:cgo_import_static __tsan_malloc
   139  //go:cgo_import_static __tsan_acquire
   140  //go:cgo_import_static __tsan_release
   141  //go:cgo_import_static __tsan_release_merge
   142  //go:cgo_import_static __tsan_go_ignore_sync_begin
   143  //go:cgo_import_static __tsan_go_ignore_sync_end
   144  
   145  // These are called from race_amd64.s.
   146  //go:cgo_import_static __tsan_read
   147  //go:cgo_import_static __tsan_read_pc
   148  //go:cgo_import_static __tsan_read_range
   149  //go:cgo_import_static __tsan_write
   150  //go:cgo_import_static __tsan_write_pc
   151  //go:cgo_import_static __tsan_write_range
   152  //go:cgo_import_static __tsan_func_enter
   153  //go:cgo_import_static __tsan_func_exit
   154  
   155  //go:cgo_import_static __tsan_go_atomic32_load
   156  //go:cgo_import_static __tsan_go_atomic64_load
   157  //go:cgo_import_static __tsan_go_atomic32_store
   158  //go:cgo_import_static __tsan_go_atomic64_store
   159  //go:cgo_import_static __tsan_go_atomic32_exchange
   160  //go:cgo_import_static __tsan_go_atomic64_exchange
   161  //go:cgo_import_static __tsan_go_atomic32_fetch_add
   162  //go:cgo_import_static __tsan_go_atomic64_fetch_add
   163  //go:cgo_import_static __tsan_go_atomic32_compare_exchange
   164  //go:cgo_import_static __tsan_go_atomic64_compare_exchange
   165  
   166  // start/end of global data (data+bss).
   167  var racedatastart uintptr
   168  var racedataend uintptr
   169  
   170  // start/end of heap for race_amd64.s
   171  var racearenastart uintptr
   172  var racearenaend uintptr
   173  
   174  func racefuncenter(uintptr)
   175  func racefuncexit()
   176  func racereadrangepc1(uintptr, uintptr, uintptr)
   177  func racewriterangepc1(uintptr, uintptr, uintptr)
   178  func racesymbolizethunk(uintptr)
   179  
   180  // racecall allows calling an arbitrary function f from C race runtime
   181  // with up to 4 uintptr arguments.
   182  func racecall(*byte, uintptr, uintptr, uintptr, uintptr)
   183  
   184  // checks if the address has shadow (i.e. heap or data/bss)
   185  //go:nosplit
   186  func isvalidaddr(addr unsafe.Pointer) bool {
   187  	return racearenastart <= uintptr(addr) && uintptr(addr) < racearenaend ||
   188  		racedatastart <= uintptr(addr) && uintptr(addr) < racedataend
   189  }
   190  
   191  //go:nosplit
   192  func raceinit() uintptr {
   193  	// cgo is required to initialize libc, which is used by race runtime
   194  	if !iscgo {
   195  		throw("raceinit: race build must use cgo")
   196  	}
   197  
   198  	var racectx uintptr
   199  	racecall(&__tsan_init, uintptr(unsafe.Pointer(&racectx)), funcPC(racesymbolizethunk), 0, 0)
   200  
   201  	// Round data segment to page boundaries, because it's used in mmap().
   202  	start := ^uintptr(0)
   203  	end := uintptr(0)
   204  	if start > firstmoduledata.noptrdata {
   205  		start = firstmoduledata.noptrdata
   206  	}
   207  	if start > firstmoduledata.data {
   208  		start = firstmoduledata.data
   209  	}
   210  	if start > firstmoduledata.noptrbss {
   211  		start = firstmoduledata.noptrbss
   212  	}
   213  	if start > firstmoduledata.bss {
   214  		start = firstmoduledata.bss
   215  	}
   216  	if end < firstmoduledata.enoptrdata {
   217  		end = firstmoduledata.enoptrdata
   218  	}
   219  	if end < firstmoduledata.edata {
   220  		end = firstmoduledata.edata
   221  	}
   222  	if end < firstmoduledata.enoptrbss {
   223  		end = firstmoduledata.enoptrbss
   224  	}
   225  	if end < firstmoduledata.ebss {
   226  		end = firstmoduledata.ebss
   227  	}
   228  	size := round(end-start, _PageSize)
   229  	racecall(&__tsan_map_shadow, start, size, 0, 0)
   230  	racedatastart = start
   231  	racedataend = start + size
   232  
   233  	return racectx
   234  }
   235  
   236  //go:nosplit
   237  func racefini() {
   238  	racecall(&__tsan_fini, 0, 0, 0, 0)
   239  }
   240  
   241  //go:nosplit
   242  func racemapshadow(addr unsafe.Pointer, size uintptr) {
   243  	if racearenastart == 0 {
   244  		racearenastart = uintptr(addr)
   245  	}
   246  	if racearenaend < uintptr(addr)+size {
   247  		racearenaend = uintptr(addr) + size
   248  	}
   249  	racecall(&__tsan_map_shadow, uintptr(addr), size, 0, 0)
   250  }
   251  
   252  //go:nosplit
   253  func racemalloc(p unsafe.Pointer, sz uintptr) {
   254  	racecall(&__tsan_malloc, uintptr(p), sz, 0, 0)
   255  }
   256  
   257  //go:nosplit
   258  func racegostart(pc uintptr) uintptr {
   259  	_g_ := getg()
   260  	var spawng *g
   261  	if _g_.m.curg != nil {
   262  		spawng = _g_.m.curg
   263  	} else {
   264  		spawng = _g_
   265  	}
   266  
   267  	var racectx uintptr
   268  	racecall(&__tsan_go_start, spawng.racectx, uintptr(unsafe.Pointer(&racectx)), pc, 0)
   269  	return racectx
   270  }
   271  
   272  //go:nosplit
   273  func racegoend() {
   274  	racecall(&__tsan_go_end, getg().racectx, 0, 0, 0)
   275  }
   276  
   277  //go:nosplit
   278  func racewriterangepc(addr unsafe.Pointer, sz, callpc, pc uintptr) {
   279  	_g_ := getg()
   280  	if _g_ != _g_.m.curg {
   281  		// The call is coming from manual instrumentation of Go code running on g0/gsignal.
   282  		// Not interesting.
   283  		return
   284  	}
   285  	if callpc != 0 {
   286  		racefuncenter(callpc)
   287  	}
   288  	racewriterangepc1(uintptr(addr), sz, pc)
   289  	if callpc != 0 {
   290  		racefuncexit()
   291  	}
   292  }
   293  
   294  //go:nosplit
   295  func racereadrangepc(addr unsafe.Pointer, sz, callpc, pc uintptr) {
   296  	_g_ := getg()
   297  	if _g_ != _g_.m.curg {
   298  		// The call is coming from manual instrumentation of Go code running on g0/gsignal.
   299  		// Not interesting.
   300  		return
   301  	}
   302  	if callpc != 0 {
   303  		racefuncenter(callpc)
   304  	}
   305  	racereadrangepc1(uintptr(addr), sz, pc)
   306  	if callpc != 0 {
   307  		racefuncexit()
   308  	}
   309  }
   310  
   311  //go:nosplit
   312  func raceacquire(addr unsafe.Pointer) {
   313  	raceacquireg(getg(), addr)
   314  }
   315  
   316  //go:nosplit
   317  func raceacquireg(gp *g, addr unsafe.Pointer) {
   318  	if getg().raceignore != 0 || !isvalidaddr(addr) {
   319  		return
   320  	}
   321  	racecall(&__tsan_acquire, gp.racectx, uintptr(addr), 0, 0)
   322  }
   323  
   324  //go:nosplit
   325  func racerelease(addr unsafe.Pointer) {
   326  	_g_ := getg()
   327  	if _g_.raceignore != 0 || !isvalidaddr(addr) {
   328  		return
   329  	}
   330  	racereleaseg(_g_, addr)
   331  }
   332  
   333  //go:nosplit
   334  func racereleaseg(gp *g, addr unsafe.Pointer) {
   335  	if getg().raceignore != 0 || !isvalidaddr(addr) {
   336  		return
   337  	}
   338  	racecall(&__tsan_release, gp.racectx, uintptr(addr), 0, 0)
   339  }
   340  
   341  //go:nosplit
   342  func racereleasemerge(addr unsafe.Pointer) {
   343  	racereleasemergeg(getg(), addr)
   344  }
   345  
   346  //go:nosplit
   347  func racereleasemergeg(gp *g, addr unsafe.Pointer) {
   348  	if getg().raceignore != 0 || !isvalidaddr(addr) {
   349  		return
   350  	}
   351  	racecall(&__tsan_release_merge, gp.racectx, uintptr(addr), 0, 0)
   352  }
   353  
   354  //go:nosplit
   355  func racefingo() {
   356  	racecall(&__tsan_finalizer_goroutine, getg().racectx, 0, 0, 0)
   357  }
   358  
   359  //go:nosplit
   360  
   361  func RaceAcquire(addr unsafe.Pointer) {
   362  	raceacquire(addr)
   363  }
   364  
   365  //go:nosplit
   366  
   367  func RaceRelease(addr unsafe.Pointer) {
   368  	racerelease(addr)
   369  }
   370  
   371  //go:nosplit
   372  
   373  func RaceReleaseMerge(addr unsafe.Pointer) {
   374  	racereleasemerge(addr)
   375  }
   376  
   377  //go:nosplit
   378  
   379  // RaceDisable disables handling of race events in the current goroutine.
   380  func RaceDisable() {
   381  	_g_ := getg()
   382  	if _g_.raceignore == 0 {
   383  		racecall(&__tsan_go_ignore_sync_begin, _g_.racectx, 0, 0, 0)
   384  	}
   385  	_g_.raceignore++
   386  }
   387  
   388  //go:nosplit
   389  
   390  // RaceEnable re-enables handling of race events in the current goroutine.
   391  func RaceEnable() {
   392  	_g_ := getg()
   393  	_g_.raceignore--
   394  	if _g_.raceignore == 0 {
   395  		racecall(&__tsan_go_ignore_sync_end, _g_.racectx, 0, 0, 0)
   396  	}
   397  }