]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.cc] runtime: convert race implementation from C to Go
authorRuss Cox <rsc@golang.org>
Tue, 11 Nov 2014 22:08:14 +0000 (17:08 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 11 Nov 2014 22:08:14 +0000 (17:08 -0500)
The conversion was done with an automated tool and then
modified only as necessary to make it compile and run.

[This CL is part of the removal of C code from package runtime.
See golang.org/s/dev.cc for an overview.]

LGTM=r
R=r
CC=austin, dvyukov, golang-codereviews, iant, khr
https://golang.org/cl/172250044

src/runtime/norace_test.go
src/runtime/race.c [deleted file]
src/runtime/race.go
src/runtime/race.h [deleted file]
src/runtime/race0.go
src/runtime/race1.go [new file with mode: 0644]

index 3b171877a6f5b77396159a5936e92dae2fd32e5d..3681bf190d24367594fef0fc2bbbb4e327b8950c 100644 (file)
@@ -34,12 +34,12 @@ func benchmarkSyscall(b *testing.B, work, excess int) {
        b.RunParallel(func(pb *testing.PB) {
                foo := 42
                for pb.Next() {
-                       runtime.Entersyscall()
+                       runtime.Entersyscall(0)
                        for i := 0; i < work; i++ {
                                foo *= 2
                                foo /= 2
                        }
-                       runtime.Exitsyscall()
+                       runtime.Exitsyscall(0)
                }
                _ = foo
        })
diff --git a/src/runtime/race.c b/src/runtime/race.c
deleted file mode 100644 (file)
index 9ac73fb..0000000
+++ /dev/null
@@ -1,314 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Implementation of the race detector API.
-// +build race
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "race.h"
-#include "type.h"
-#include "typekind.h"
-#include "textflag.h"
-
-// Race runtime functions called via runtime·racecall.
-void __tsan_init(void);
-void __tsan_fini(void);
-void __tsan_map_shadow(void);
-void __tsan_finalizer_goroutine(void);
-void __tsan_go_start(void);
-void __tsan_go_end(void);
-void __tsan_malloc(void);
-void __tsan_acquire(void);
-void __tsan_release(void);
-void __tsan_release_merge(void);
-void __tsan_go_ignore_sync_begin(void);
-void __tsan_go_ignore_sync_end(void);
-
-// Mimic what cmd/cgo would do.
-#pragma cgo_import_static __tsan_init
-#pragma cgo_import_static __tsan_fini
-#pragma cgo_import_static __tsan_map_shadow
-#pragma cgo_import_static __tsan_finalizer_goroutine
-#pragma cgo_import_static __tsan_go_start
-#pragma cgo_import_static __tsan_go_end
-#pragma cgo_import_static __tsan_malloc
-#pragma cgo_import_static __tsan_acquire
-#pragma cgo_import_static __tsan_release
-#pragma cgo_import_static __tsan_release_merge
-#pragma cgo_import_static __tsan_go_ignore_sync_begin
-#pragma cgo_import_static __tsan_go_ignore_sync_end
-
-// These are called from race_amd64.s.
-#pragma cgo_import_static __tsan_read
-#pragma cgo_import_static __tsan_read_pc
-#pragma cgo_import_static __tsan_read_range
-#pragma cgo_import_static __tsan_write
-#pragma cgo_import_static __tsan_write_pc
-#pragma cgo_import_static __tsan_write_range
-#pragma cgo_import_static __tsan_func_enter
-#pragma cgo_import_static __tsan_func_exit
-
-#pragma cgo_import_static __tsan_go_atomic32_load
-#pragma cgo_import_static __tsan_go_atomic64_load
-#pragma cgo_import_static __tsan_go_atomic32_store
-#pragma cgo_import_static __tsan_go_atomic64_store
-#pragma cgo_import_static __tsan_go_atomic32_exchange
-#pragma cgo_import_static __tsan_go_atomic64_exchange
-#pragma cgo_import_static __tsan_go_atomic32_fetch_add
-#pragma cgo_import_static __tsan_go_atomic64_fetch_add
-#pragma cgo_import_static __tsan_go_atomic32_compare_exchange
-#pragma cgo_import_static __tsan_go_atomic64_compare_exchange
-
-extern byte runtime·noptrdata[];
-extern byte runtime·enoptrbss[];
-  
-// start/end of heap for race_amd64.s
-uintptr runtime·racearenastart;
-uintptr runtime·racearenaend;
-
-void runtime·racefuncenter(void *callpc);
-void runtime·racefuncexit(void);
-void runtime·racereadrangepc1(void *addr, uintptr sz, void *pc);
-void runtime·racewriterangepc1(void *addr, uintptr sz, void *pc);
-void runtime·racesymbolizethunk(void*);
-
-// racecall allows calling an arbitrary function f from C race runtime
-// with up to 4 uintptr arguments.
-void runtime·racecall(void(*f)(void), ...);
-
-// checks if the address has shadow (i.e. heap or data/bss)
-#pragma textflag NOSPLIT
-static bool
-isvalidaddr(uintptr addr)
-{
-       if(addr >= runtime·racearenastart && addr < runtime·racearenaend)
-               return true;
-       if(addr >= (uintptr)runtime·noptrdata && addr < (uintptr)runtime·enoptrbss)
-               return true;
-       return false;
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·raceinit(void)
-{
-       uintptr racectx, start, size;
-
-       // cgo is required to initialize libc, which is used by race runtime
-       if(!runtime·iscgo)
-               runtime·throw("raceinit: race build must use cgo");
-       runtime·racecall(__tsan_init, &racectx, runtime·racesymbolizethunk);
-       // Round data segment to page boundaries, because it's used in mmap().
-       start = (uintptr)runtime·noptrdata & ~(PageSize-1);
-       size = ROUND((uintptr)runtime·enoptrbss - start, PageSize);
-       runtime·racecall(__tsan_map_shadow, start, size);
-       return racectx;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racefini(void)
-{
-       runtime·racecall(__tsan_fini);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racemapshadow(void *addr, uintptr size)
-{
-       if(runtime·racearenastart == 0)
-               runtime·racearenastart = (uintptr)addr;
-       if(runtime·racearenaend < (uintptr)addr+size)
-               runtime·racearenaend = (uintptr)addr+size;
-       runtime·racecall(__tsan_map_shadow, addr, size);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racemalloc(void *p, uintptr sz)
-{
-       runtime·racecall(__tsan_malloc, p, sz);
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·racegostart(void *pc)
-{
-       uintptr racectx;
-       G *spawng;
-
-       if(g->m->curg != nil)
-               spawng = g->m->curg;
-       else
-               spawng = g;
-
-       runtime·racecall(__tsan_go_start, spawng->racectx, &racectx, pc);
-       return racectx;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racegoend(void)
-{
-       runtime·racecall(__tsan_go_end, g->racectx);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc)
-{
-       if(g != g->m->curg) {
-               // The call is coming from manual instrumentation of Go code running on g0/gsignal.
-               // Not interesting.
-               return;
-       }
-       if(callpc != nil)
-               runtime·racefuncenter(callpc);
-       runtime·racewriterangepc1(addr, sz, pc);
-       if(callpc != nil)
-               runtime·racefuncexit();
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc)
-{
-       if(g != g->m->curg) {
-               // The call is coming from manual instrumentation of Go code running on g0/gsignal.
-               // Not interesting.
-               return;
-       }
-       if(callpc != nil)
-               runtime·racefuncenter(callpc);
-       runtime·racereadrangepc1(addr, sz, pc);
-       if(callpc != nil)
-               runtime·racefuncexit();
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc)
-{
-       uint8 kind;
-
-       kind = t->kind & KindMask;
-       if(kind == KindArray || kind == KindStruct)
-               runtime·racewriterangepc(addr, t->size, callpc, pc);
-       else
-               runtime·racewritepc(addr, callpc, pc);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereadobjectpc(void *addr, Type *t, void *callpc, void *pc)
-{
-       uint8 kind;
-
-       kind = t->kind & KindMask;
-       if(kind == KindArray || kind == KindStruct)
-               runtime·racereadrangepc(addr, t->size, callpc, pc);
-       else
-               runtime·racereadpc(addr, callpc, pc);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·raceacquire(void *addr)
-{
-       runtime·raceacquireg(g, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·raceacquireg(G *gp, void *addr)
-{
-       if(g->raceignore || !isvalidaddr((uintptr)addr))
-               return;
-       runtime·racecall(__tsan_acquire, gp->racectx, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racerelease(void *addr)
-{
-       if(g->raceignore || !isvalidaddr((uintptr)addr))
-               return;
-       runtime·racereleaseg(g, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereleaseg(G *gp, void *addr)
-{
-       if(g->raceignore || !isvalidaddr((uintptr)addr))
-               return;
-       runtime·racecall(__tsan_release, gp->racectx, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereleasemerge(void *addr)
-{
-       runtime·racereleasemergeg(g, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereleasemergeg(G *gp, void *addr)
-{
-       if(g->raceignore || !isvalidaddr((uintptr)addr))
-               return;
-       runtime·racecall(__tsan_release_merge, gp->racectx, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racefingo(void)
-{
-       runtime·racecall(__tsan_finalizer_goroutine, g->racectx);
-}
-
-// func RaceAcquire(addr unsafe.Pointer)
-#pragma textflag NOSPLIT
-void
-runtime·RaceAcquire(void *addr)
-{
-       runtime·raceacquire(addr);
-}
-
-// func RaceRelease(addr unsafe.Pointer)
-#pragma textflag NOSPLIT
-void
-runtime·RaceRelease(void *addr)
-{
-       runtime·racerelease(addr);
-}
-
-// func RaceReleaseMerge(addr unsafe.Pointer)
-#pragma textflag NOSPLIT
-void
-runtime·RaceReleaseMerge(void *addr)
-{
-       runtime·racereleasemerge(addr);
-}
-
-// func RaceDisable()
-#pragma textflag NOSPLIT
-void
-runtime·RaceDisable(void)
-{
-       if(g->raceignore++ == 0)
-               runtime·racecall(__tsan_go_ignore_sync_begin, g->racectx);
-}
-
-// func RaceEnable()
-#pragma textflag NOSPLIT
-void
-runtime·RaceEnable(void)
-{
-       if(--g->raceignore == 0)
-               runtime·racecall(__tsan_go_ignore_sync_end, g->racectx);
-}
index bb0ee6df65041b3bb3f0f8d05dcbcf91b29dbc0c..7d38fae1c3f4d1ca06ebe1aeef56b8c33ce92aa0 100644 (file)
@@ -12,18 +12,6 @@ import (
        "unsafe"
 )
 
-func racefini()
-
-// RaceDisable disables handling of race events in the current goroutine.
-func RaceDisable()
-
-// RaceEnable re-enables handling of race events in the current goroutine.
-func RaceEnable()
-
-func RaceAcquire(addr unsafe.Pointer)
-func RaceRelease(addr unsafe.Pointer)
-func RaceReleaseMerge(addr unsafe.Pointer)
-
 func RaceRead(addr unsafe.Pointer)
 func RaceWrite(addr unsafe.Pointer)
 func RaceReadRange(addr unsafe.Pointer, len int)
@@ -67,32 +55,6 @@ func racereadpc(addr unsafe.Pointer, callpc, pc uintptr)
 //go:noescape
 func racewritepc(addr unsafe.Pointer, callpc, pc uintptr)
 
-//go:noescape
-func racereadrangepc(addr unsafe.Pointer, len uintptr, callpc, pc uintptr)
-
-//go:noescape
-func racewriterangepc(addr unsafe.Pointer, len uintptr, callpc, pc uintptr)
-
-//go:noescape
-func raceacquire(addr unsafe.Pointer)
-
-//go:noescape
-func racerelease(addr unsafe.Pointer)
-
-//go:noescape
-func raceacquireg(gp *g, addr unsafe.Pointer)
-
-//go:noescape
-func racereleaseg(gp *g, addr unsafe.Pointer)
-
-func racefingo()
-
-//go:noescape
-func racemalloc(p unsafe.Pointer, size uintptr)
-
-//go:noescape
-func racereleasemerge(addr unsafe.Pointer)
-
 type symbolizeContext struct {
        pc   uintptr
        fn   *byte
diff --git a/src/runtime/race.h b/src/runtime/race.h
deleted file mode 100644 (file)
index fee31e0..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Definitions related to data race detection.
-
-#ifdef RACE
-enum { raceenabled = 1 };
-#else
-enum { raceenabled = 0 };
-#endif
-
-// Initialize race detection subsystem.
-uintptr        runtime·raceinit(void);
-// Finalize race detection subsystem, does not return.
-void   runtime·racefini(void);
-
-void   runtime·racemapshadow(void *addr, uintptr size);
-void   runtime·racemalloc(void *p, uintptr sz);
-uintptr        runtime·racegostart(void *pc);
-void   runtime·racegoend(void);
-void   runtime·racewritepc(void *addr, void *callpc, void *pc);
-void   runtime·racereadpc(void *addr, void *callpc, void *pc);
-void   runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc);
-void   runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc);
-void   runtime·racereadobjectpc(void *addr, Type *t, void *callpc, void *pc);
-void   runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc);
-void   runtime·racefingo(void);
-void   runtime·raceacquire(void *addr);
-void   runtime·raceacquireg(G *gp, void *addr);
-void   runtime·racerelease(void *addr);
-void   runtime·racereleaseg(G *gp, void *addr);
-void   runtime·racereleasemerge(void *addr);
-void   runtime·racereleasemergeg(G *gp, void *addr);
index 5d90cc859a246f3c6ecef5db2d5a722ff974c453..dadb6083fef0f2d55d9b444a1becf4bf89650a6e 100644 (file)
@@ -18,7 +18,7 @@ const raceenabled = false
 
 func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr)  { gothrow("race") }
 func raceWriteObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { gothrow("race") }
-func raceinit()                                                             { gothrow("race") }
+func raceinit() uintptr                                                     { gothrow("race"); return 0 }
 func racefini()                                                             { gothrow("race") }
 func racemapshadow(addr unsafe.Pointer, size uintptr)                       { gothrow("race") }
 func racewritepc(addr unsafe.Pointer, callerpc, pc uintptr)                 { gothrow("race") }
diff --git a/src/runtime/race1.go b/src/runtime/race1.go
new file mode 100644 (file)
index 0000000..4c58042
--- /dev/null
@@ -0,0 +1,304 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Implementation of the race detector API.
+// +build race
+
+package runtime
+
+import "unsafe"
+
+// Race runtime functions called via runtime·racecall.
+//go:linkname __tsan_init __tsan_init
+var __tsan_init byte
+
+//go:linkname __tsan_fini __tsan_fini
+var __tsan_fini byte
+
+//go:linkname __tsan_map_shadow __tsan_map_shadow
+var __tsan_map_shadow byte
+
+//go:linkname __tsan_finalizer_goroutine __tsan_finalizer_goroutine
+var __tsan_finalizer_goroutine byte
+
+//go:linkname __tsan_go_start __tsan_go_start
+var __tsan_go_start byte
+
+//go:linkname __tsan_go_end __tsan_go_end
+var __tsan_go_end byte
+
+//go:linkname __tsan_malloc __tsan_malloc
+var __tsan_malloc byte
+
+//go:linkname __tsan_acquire __tsan_acquire
+var __tsan_acquire byte
+
+//go:linkname __tsan_release __tsan_release
+var __tsan_release byte
+
+//go:linkname __tsan_release_merge __tsan_release_merge
+var __tsan_release_merge byte
+
+//go:linkname __tsan_go_ignore_sync_begin __tsan_go_ignore_sync_begin
+var __tsan_go_ignore_sync_begin byte
+
+//go:linkname __tsan_go_ignore_sync_end __tsan_go_ignore_sync_end
+var __tsan_go_ignore_sync_end byte
+
+// Mimic what cmd/cgo would do.
+//go:cgo_import_static __tsan_init
+//go:cgo_import_static __tsan_fini
+//go:cgo_import_static __tsan_map_shadow
+//go:cgo_import_static __tsan_finalizer_goroutine
+//go:cgo_import_static __tsan_go_start
+//go:cgo_import_static __tsan_go_end
+//go:cgo_import_static __tsan_malloc
+//go:cgo_import_static __tsan_acquire
+//go:cgo_import_static __tsan_release
+//go:cgo_import_static __tsan_release_merge
+//go:cgo_import_static __tsan_go_ignore_sync_begin
+//go:cgo_import_static __tsan_go_ignore_sync_end
+
+// These are called from race_amd64.s.
+//go:cgo_import_static __tsan_read
+//go:cgo_import_static __tsan_read_pc
+//go:cgo_import_static __tsan_read_range
+//go:cgo_import_static __tsan_write
+//go:cgo_import_static __tsan_write_pc
+//go:cgo_import_static __tsan_write_range
+//go:cgo_import_static __tsan_func_enter
+//go:cgo_import_static __tsan_func_exit
+
+//go:cgo_import_static __tsan_go_atomic32_load
+//go:cgo_import_static __tsan_go_atomic64_load
+//go:cgo_import_static __tsan_go_atomic32_store
+//go:cgo_import_static __tsan_go_atomic64_store
+//go:cgo_import_static __tsan_go_atomic32_exchange
+//go:cgo_import_static __tsan_go_atomic64_exchange
+//go:cgo_import_static __tsan_go_atomic32_fetch_add
+//go:cgo_import_static __tsan_go_atomic64_fetch_add
+//go:cgo_import_static __tsan_go_atomic32_compare_exchange
+//go:cgo_import_static __tsan_go_atomic64_compare_exchange
+
+// start/end of heap for race_amd64.s
+var racearenastart uintptr
+var racearenaend uintptr
+
+func racefuncenter(uintptr)
+func racefuncexit()
+func racereadrangepc1(uintptr, uintptr, uintptr)
+func racewriterangepc1(uintptr, uintptr, uintptr)
+func racesymbolizethunk(uintptr)
+
+// racecall allows calling an arbitrary function f from C race runtime
+// with up to 4 uintptr arguments.
+func racecall(*byte, uintptr, uintptr, uintptr, uintptr)
+
+// checks if the address has shadow (i.e. heap or data/bss)
+//go:nosplit
+func isvalidaddr(addr unsafe.Pointer) bool {
+       return racearenastart <= uintptr(addr) && uintptr(addr) < racearenaend ||
+               uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(addr) && uintptr(addr) < uintptr(unsafe.Pointer(&enoptrbss))
+}
+
+//go:nosplit
+func raceinit() uintptr {
+       // cgo is required to initialize libc, which is used by race runtime
+       if !iscgo {
+               gothrow("raceinit: race build must use cgo")
+       }
+
+       var racectx uintptr
+       racecall(&__tsan_init, uintptr(unsafe.Pointer(&racectx)), funcPC(racesymbolizethunk), 0, 0)
+
+       // Round data segment to page boundaries, because it's used in mmap().
+       start := uintptr(unsafe.Pointer(&noptrdata)) &^ (_PageSize - 1)
+       size := round(uintptr(unsafe.Pointer(&enoptrbss))-start, _PageSize)
+       racecall(&__tsan_map_shadow, start, size, 0, 0)
+
+       return racectx
+}
+
+//go:nosplit
+func racefini() {
+       racecall(&__tsan_fini, 0, 0, 0, 0)
+}
+
+//go:nosplit
+func racemapshadow(addr unsafe.Pointer, size uintptr) {
+       if racearenastart == 0 {
+               racearenastart = uintptr(addr)
+       }
+       if racearenaend < uintptr(addr)+size {
+               racearenaend = uintptr(addr) + size
+       }
+       racecall(&__tsan_map_shadow, uintptr(addr), size, 0, 0)
+}
+
+//go:nosplit
+func racemalloc(p unsafe.Pointer, sz uintptr) {
+       racecall(&__tsan_malloc, uintptr(p), sz, 0, 0)
+}
+
+//go:nosplit
+func racegostart(pc uintptr) uintptr {
+       _g_ := getg()
+       var spawng *g
+       if _g_.m.curg != nil {
+               spawng = _g_.m.curg
+       } else {
+               spawng = _g_
+       }
+
+       var racectx uintptr
+       racecall(&__tsan_go_start, spawng.racectx, uintptr(unsafe.Pointer(&racectx)), pc, 0)
+       return racectx
+}
+
+//go:nosplit
+func racegoend() {
+       racecall(&__tsan_go_end, getg().racectx, 0, 0, 0)
+}
+
+//go:nosplit
+func racewriterangepc(addr unsafe.Pointer, sz, callpc, pc uintptr) {
+       _g_ := getg()
+       if _g_ != _g_.m.curg {
+               // The call is coming from manual instrumentation of Go code running on g0/gsignal.
+               // Not interesting.
+               return
+       }
+       if callpc != 0 {
+               racefuncenter(callpc)
+       }
+       racewriterangepc1(uintptr(addr), sz, pc)
+       if callpc != 0 {
+               racefuncexit()
+       }
+}
+
+//go:nosplit
+func racereadrangepc(addr unsafe.Pointer, sz, callpc, pc uintptr) {
+       _g_ := getg()
+       if _g_ != _g_.m.curg {
+               // The call is coming from manual instrumentation of Go code running on g0/gsignal.
+               // Not interesting.
+               return
+       }
+       if callpc != 0 {
+               racefuncenter(callpc)
+       }
+       racereadrangepc1(uintptr(addr), sz, pc)
+       if callpc != 0 {
+               racefuncexit()
+       }
+}
+
+//go:nosplit
+func racewriteobjectpc(addr unsafe.Pointer, t *_type, callpc, pc uintptr) {
+       kind := t.kind & _KindMask
+       if kind == _KindArray || kind == _KindStruct {
+               racewriterangepc(addr, t.size, callpc, pc)
+       } else {
+               racewritepc(addr, callpc, pc)
+       }
+}
+
+//go:nosplit
+func racereadobjectpc(addr unsafe.Pointer, t *_type, callpc, pc uintptr) {
+       kind := t.kind & _KindMask
+       if kind == _KindArray || kind == _KindStruct {
+               racereadrangepc(addr, t.size, callpc, pc)
+       } else {
+               racereadpc(addr, callpc, pc)
+       }
+}
+
+//go:nosplit
+func raceacquire(addr unsafe.Pointer) {
+       raceacquireg(getg(), addr)
+}
+
+//go:nosplit
+func raceacquireg(gp *g, addr unsafe.Pointer) {
+       if getg().raceignore != 0 || !isvalidaddr(addr) {
+               return
+       }
+       racecall(&__tsan_acquire, gp.racectx, uintptr(addr), 0, 0)
+}
+
+//go:nosplit
+func racerelease(addr unsafe.Pointer) {
+       _g_ := getg()
+       if _g_.raceignore != 0 || !isvalidaddr(addr) {
+               return
+       }
+       racereleaseg(_g_, addr)
+}
+
+//go:nosplit
+func racereleaseg(gp *g, addr unsafe.Pointer) {
+       if getg().raceignore != 0 || !isvalidaddr(addr) {
+               return
+       }
+       racecall(&__tsan_release, gp.racectx, uintptr(addr), 0, 0)
+}
+
+//go:nosplit
+func racereleasemerge(addr unsafe.Pointer) {
+       racereleasemergeg(getg(), addr)
+}
+
+//go:nosplit
+func racereleasemergeg(gp *g, addr unsafe.Pointer) {
+       if getg().raceignore != 0 || !isvalidaddr(addr) {
+               return
+       }
+       racecall(&__tsan_release_merge, gp.racectx, uintptr(addr), 0, 0)
+}
+
+//go:nosplit
+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
+
+// RaceEnable re-enables 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
+
+// RaceDisable disables 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)
+       }
+}