summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/race.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/race.c')
-rw-r--r--src/pkg/runtime/race.c350
1 files changed, 350 insertions, 0 deletions
diff --git a/src/pkg/runtime/race.c b/src/pkg/runtime/race.c
new file mode 100644
index 000000000..cfd97041a
--- /dev/null
+++ b/src/pkg/runtime/race.c
@@ -0,0 +1,350 @@
+// 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"
+
+void runtime∕race·Initialize(uintptr *racectx);
+void runtime∕race·MapShadow(void *addr, uintptr size);
+void runtime∕race·Finalize(void);
+void runtime∕race·FinalizerGoroutine(uintptr racectx);
+void runtime∕race·Read(uintptr racectx, void *addr, void *pc);
+void runtime∕race·Write(uintptr racectx, void *addr, void *pc);
+void runtime∕race·ReadRange(uintptr racectx, void *addr, uintptr sz, uintptr step, void *pc);
+void runtime∕race·WriteRange(uintptr racectx, void *addr, uintptr sz, uintptr step, void *pc);
+void runtime∕race·FuncEnter(uintptr racectx, void *pc);
+void runtime∕race·FuncExit(uintptr racectx);
+void runtime∕race·Malloc(uintptr racectx, void *p, uintptr sz, void *pc);
+void runtime∕race·Free(void *p);
+void runtime∕race·GoStart(uintptr racectx, uintptr *chracectx, void *pc);
+void runtime∕race·GoEnd(uintptr racectx);
+void runtime∕race·Acquire(uintptr racectx, void *addr);
+void runtime∕race·Release(uintptr racectx, void *addr);
+void runtime∕race·ReleaseMerge(uintptr racectx, void *addr);
+
+extern byte noptrdata[];
+extern byte enoptrbss[];
+
+static bool onstack(uintptr argp);
+
+uintptr
+runtime·raceinit(void)
+{
+ uintptr racectx;
+
+ m->racecall = true;
+ runtime∕race·Initialize(&racectx);
+ runtime∕race·MapShadow(noptrdata, enoptrbss - noptrdata);
+ m->racecall = false;
+ return racectx;
+}
+
+void
+runtime·racefini(void)
+{
+ m->racecall = true;
+ runtime∕race·Finalize();
+ m->racecall = false;
+}
+
+void
+runtime·racemapshadow(void *addr, uintptr size)
+{
+ m->racecall = true;
+ runtime∕race·MapShadow(addr, size);
+ m->racecall = false;
+}
+
+// Called from instrumented code.
+// If we split stack, getcallerpc() can return runtime·lessstack().
+#pragma textflag 7
+void
+runtime·racewrite(uintptr addr)
+{
+ if(!onstack(addr)) {
+ m->racecall = true;
+ runtime∕race·Write(g->racectx, (void*)addr, runtime·getcallerpc(&addr));
+ m->racecall = false;
+ }
+}
+
+// Called from instrumented code.
+// If we split stack, getcallerpc() can return runtime·lessstack().
+#pragma textflag 7
+void
+runtime·raceread(uintptr addr)
+{
+ if(!onstack(addr)) {
+ m->racecall = true;
+ runtime∕race·Read(g->racectx, (void*)addr, runtime·getcallerpc(&addr));
+ m->racecall = false;
+ }
+}
+
+// Called from runtime·racefuncenter (assembly).
+#pragma textflag 7
+void
+runtime·racefuncenter1(uintptr pc)
+{
+ // If the caller PC is lessstack, use slower runtime·callers
+ // to walk across the stack split to find the real caller.
+ if(pc == (uintptr)runtime·lessstack)
+ runtime·callers(2, &pc, 1);
+
+ m->racecall = true;
+ runtime∕race·FuncEnter(g->racectx, (void*)pc);
+ m->racecall = false;
+}
+
+// Called from instrumented code.
+#pragma textflag 7
+void
+runtime·racefuncexit(void)
+{
+ m->racecall = true;
+ runtime∕race·FuncExit(g->racectx);
+ m->racecall = false;
+}
+
+void
+runtime·racemalloc(void *p, uintptr sz, void *pc)
+{
+ // use m->curg because runtime·stackalloc() is called from g0
+ if(m->curg == nil)
+ return;
+ m->racecall = true;
+ runtime∕race·Malloc(m->curg->racectx, p, sz, pc);
+ m->racecall = false;
+}
+
+void
+runtime·racefree(void *p)
+{
+ m->racecall = true;
+ runtime∕race·Free(p);
+ m->racecall = false;
+}
+
+uintptr
+runtime·racegostart(void *pc)
+{
+ uintptr racectx;
+
+ m->racecall = true;
+ runtime∕race·GoStart(g->racectx, &racectx, pc);
+ m->racecall = false;
+ return racectx;
+}
+
+void
+runtime·racegoend(void)
+{
+ m->racecall = true;
+ runtime∕race·GoEnd(g->racectx);
+ m->racecall = false;
+}
+
+static void
+memoryaccess(void *addr, uintptr callpc, uintptr pc, bool write)
+{
+ uintptr racectx;
+
+ if(!onstack((uintptr)addr)) {
+ m->racecall = true;
+ racectx = g->racectx;
+ if(callpc) {
+ if(callpc == (uintptr)runtime·lessstack)
+ runtime·callers(3, &callpc, 1);
+ runtime∕race·FuncEnter(racectx, (void*)callpc);
+ }
+ if(write)
+ runtime∕race·Write(racectx, addr, (void*)pc);
+ else
+ runtime∕race·Read(racectx, addr, (void*)pc);
+ if(callpc)
+ runtime∕race·FuncExit(racectx);
+ m->racecall = false;
+ }
+}
+
+void
+runtime·racewritepc(void *addr, void *callpc, void *pc)
+{
+ memoryaccess(addr, (uintptr)callpc, (uintptr)pc, true);
+}
+
+void
+runtime·racereadpc(void *addr, void *callpc, void *pc)
+{
+ memoryaccess(addr, (uintptr)callpc, (uintptr)pc, false);
+}
+
+static void
+rangeaccess(void *addr, uintptr size, uintptr step, uintptr callpc, uintptr pc, bool write)
+{
+ uintptr racectx;
+
+ if(!onstack((uintptr)addr)) {
+ m->racecall = true;
+ racectx = g->racectx;
+ if(callpc) {
+ if(callpc == (uintptr)runtime·lessstack)
+ runtime·callers(3, &callpc, 1);
+ runtime∕race·FuncEnter(racectx, (void*)callpc);
+ }
+ if(write)
+ runtime∕race·WriteRange(racectx, addr, size, step, (void*)pc);
+ else
+ runtime∕race·ReadRange(racectx, addr, size, step, (void*)pc);
+ if(callpc)
+ runtime∕race·FuncExit(racectx);
+ m->racecall = false;
+ }
+}
+
+void
+runtime·racewriterangepc(void *addr, uintptr sz, uintptr step, void *callpc, void *pc)
+{
+ rangeaccess(addr, sz, step, (uintptr)callpc, (uintptr)pc, true);
+}
+
+void
+runtime·racereadrangepc(void *addr, uintptr sz, uintptr step, void *callpc, void *pc)
+{
+ rangeaccess(addr, sz, step, (uintptr)callpc, (uintptr)pc, false);
+}
+
+void
+runtime·raceacquire(void *addr)
+{
+ runtime·raceacquireg(g, addr);
+}
+
+void
+runtime·raceacquireg(G *gp, void *addr)
+{
+ if(g->raceignore)
+ return;
+ m->racecall = true;
+ runtime∕race·Acquire(gp->racectx, addr);
+ m->racecall = false;
+}
+
+void
+runtime·racerelease(void *addr)
+{
+ runtime·racereleaseg(g, addr);
+}
+
+void
+runtime·racereleaseg(G *gp, void *addr)
+{
+ if(g->raceignore)
+ return;
+ m->racecall = true;
+ runtime∕race·Release(gp->racectx, addr);
+ m->racecall = false;
+}
+
+void
+runtime·racereleasemerge(void *addr)
+{
+ runtime·racereleasemergeg(g, addr);
+}
+
+void
+runtime·racereleasemergeg(G *gp, void *addr)
+{
+ if(g->raceignore)
+ return;
+ m->racecall = true;
+ runtime∕race·ReleaseMerge(gp->racectx, addr);
+ m->racecall = false;
+}
+
+void
+runtime·racefingo(void)
+{
+ m->racecall = true;
+ runtime∕race·FinalizerGoroutine(g->racectx);
+ m->racecall = false;
+}
+
+// func RaceAcquire(addr unsafe.Pointer)
+void
+runtime·RaceAcquire(void *addr)
+{
+ runtime·raceacquire(addr);
+}
+
+// func RaceRelease(addr unsafe.Pointer)
+void
+runtime·RaceRelease(void *addr)
+{
+ runtime·racerelease(addr);
+}
+
+// func RaceReleaseMerge(addr unsafe.Pointer)
+void
+runtime·RaceReleaseMerge(void *addr)
+{
+ runtime·racereleasemerge(addr);
+}
+
+// func RaceSemacquire(s *uint32)
+void runtime·RaceSemacquire(uint32 *s)
+{
+ runtime·semacquire(s);
+}
+
+// func RaceSemrelease(s *uint32)
+void runtime·RaceSemrelease(uint32 *s)
+{
+ runtime·semrelease(s);
+}
+
+// func RaceRead(addr unsafe.Pointer)
+#pragma textflag 7
+void
+runtime·RaceRead(void *addr)
+{
+ memoryaccess(addr, 0, (uintptr)runtime·getcallerpc(&addr), false);
+}
+
+// func RaceWrite(addr unsafe.Pointer)
+#pragma textflag 7
+void
+runtime·RaceWrite(void *addr)
+{
+ memoryaccess(addr, 0, (uintptr)runtime·getcallerpc(&addr), true);
+}
+
+// func RaceDisable()
+void runtime·RaceDisable(void)
+{
+ g->raceignore++;
+}
+
+// func RaceEnable()
+void runtime·RaceEnable(void)
+{
+ g->raceignore--;
+}
+
+static bool
+onstack(uintptr argp)
+{
+ // noptrdata, data, bss, noptrbss
+ // the layout is in ../../cmd/ld/data.c
+ if((byte*)argp >= noptrdata && (byte*)argp < enoptrbss)
+ return false;
+ if((byte*)argp >= runtime·mheap->arena_start && (byte*)argp < runtime·mheap->arena_used)
+ return false;
+ return true;
+}