diff --git a/src/runtime/race.go b/src/runtime/race.go index 49495cc783..20f19ea719 100644 --- a/src/runtime/race.go +++ b/src/runtime/race.go @@ -4,14 +4,14 @@ // +build race -// Public race detection API, present iff build with -race. - package runtime import ( "unsafe" ) +// Public race detection API, present iff build with -race. + func RaceRead(addr unsafe.Pointer) func RaceWrite(addr unsafe.Pointer) func RaceReadRange(addr unsafe.Pointer, len int) @@ -23,7 +23,69 @@ func RaceErrors() int { return int(n) } -// private interface for the runtime +//go:nosplit + +// RaceAcquire/RaceRelease/RaceReleaseMerge establish happens-before relations +// between goroutines. These inform the race detector about actual synchronization +// that it can't see for some reason (e.g. synchronization within RaceDisable/RaceEnable +// sections of code). +// RaceAcquire establishes a happens-before relation with the preceeding +// RaceReleaseMerge on addr up to and including the last RaceRelease on addr. +// In terms of the C memory model (C11 §5.1.2.4, §7.17.3), +// RaceAcquire is equivalent to atomic_load(memory_order_acquire). +func RaceAcquire(addr unsafe.Pointer) { + raceacquire(addr) +} + +//go:nosplit + +// RaceRelease performs a release operation on addr that +// can synchronize with a later RaceAcquire on addr. +// +// In terms of the C memory model, RaceRelease is equivalent to +// atomic_store(memory_order_release). +func RaceRelease(addr unsafe.Pointer) { + racerelease(addr) +} + +//go:nosplit + +// RaceReleaseMerge is like RaceRelease, but also establishes a happens-before +// relation with the preceeding RaceRelease or RaceReleaseMerge on addr. +// +// In terms of the C memory model, RaceReleaseMerge is equivalent to +// atomic_exchange(memory_order_release). +func RaceReleaseMerge(addr unsafe.Pointer) { + racereleasemerge(addr) +} + +//go:nosplit + +// RaceDisable disables handling of race synchronization events in the current goroutine. +// Handling is re-enabled with RaceEnable. RaceDisable/RaceEnable can be nested. +// Non-synchronization events (memory accesses, function entry/exit) still affect +// the race detector. +func RaceDisable() { + _g_ := getg() + if _g_.raceignore == 0 { + racecall(&__tsan_go_ignore_sync_begin, _g_.racectx, 0, 0, 0) + } + _g_.raceignore++ +} + +//go:nosplit + +// RaceEnable re-enables handling of race events in the current goroutine. +func RaceEnable() { + _g_ := getg() + _g_.raceignore-- + if _g_.raceignore == 0 { + racecall(&__tsan_go_ignore_sync_end, _g_.racectx, 0, 0, 0) + } +} + +// Private interface for the runtime. + const raceenabled = true // For all functions accepting callerpc and pc, @@ -433,43 +495,3 @@ func racereleasemergeg(gp *g, addr unsafe.Pointer) { func racefingo() { racecall(&__tsan_finalizer_goroutine, getg().racectx, 0, 0, 0) } - -//go:nosplit - -func RaceAcquire(addr unsafe.Pointer) { - raceacquire(addr) -} - -//go:nosplit - -func RaceRelease(addr unsafe.Pointer) { - racerelease(addr) -} - -//go:nosplit - -func RaceReleaseMerge(addr unsafe.Pointer) { - racereleasemerge(addr) -} - -//go:nosplit - -// RaceDisable disables handling of race events in the current goroutine. -func RaceDisable() { - _g_ := getg() - if _g_.raceignore == 0 { - racecall(&__tsan_go_ignore_sync_begin, _g_.racectx, 0, 0, 0) - } - _g_.raceignore++ -} - -//go:nosplit - -// RaceEnable re-enables handling of race events in the current goroutine. -func RaceEnable() { - _g_ := getg() - _g_.raceignore-- - if _g_.raceignore == 0 { - racecall(&__tsan_go_ignore_sync_end, _g_.racectx, 0, 0, 0) - } -}