diff options
Diffstat (limited to 'src/pkg/runtime/race.c')
-rw-r--r-- | src/pkg/runtime/race.c | 350 |
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; +} |