1
0
mirror of https://github.com/golang/go synced 2024-10-04 22:31:22 -06:00
go/src/pkg/runtime/race.c
2013-06-10 22:40:35 +04:00

374 lines
8.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 runtimerace·Initialize(uintptr *racectx);
void runtimerace·MapShadow(void *addr, uintptr size);
void runtimerace·Finalize(void);
void runtimerace·FinalizerGoroutine(uintptr racectx);
void runtimerace·Read(uintptr racectx, void *addr, void *pc);
void runtimerace·Write(uintptr racectx, void *addr, void *pc);
void runtimerace·ReadRange(uintptr racectx, void *addr, uintptr sz, uintptr step, void *pc);
void runtimerace·WriteRange(uintptr racectx, void *addr, uintptr sz, uintptr step, void *pc);
void runtimerace·FuncEnter(uintptr racectx, void *pc);
void runtimerace·FuncExit(uintptr racectx);
void runtimerace·Malloc(uintptr racectx, void *p, uintptr sz, void *pc);
void runtimerace·Free(void *p);
void runtimerace·GoStart(uintptr racectx, uintptr *chracectx, void *pc);
void runtimerace·GoEnd(uintptr racectx);
void runtimerace·Acquire(uintptr racectx, void *addr);
void runtimerace·Release(uintptr racectx, void *addr);
void runtimerace·ReleaseMerge(uintptr racectx, void *addr);
extern byte noptrdata[];
extern byte enoptrbss[];
static bool onstack(uintptr argp);
uintptr
runtime·raceinit(void)
{
uintptr racectx, start, size;
m->racecall = true;
runtimerace·Initialize(&racectx);
// Round data segment to page boundaries, because it's used in mmap().
start = (uintptr)noptrdata & ~(PageSize-1);
size = ROUND((uintptr)enoptrbss - start, PageSize);
runtimerace·MapShadow((void*)start, size);
m->racecall = false;
return racectx;
}
void
runtime·racefini(void)
{
m->racecall = true;
runtimerace·Finalize();
m->racecall = false;
}
void
runtime·racemapshadow(void *addr, uintptr size)
{
m->racecall = true;
runtimerace·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;
runtimerace·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;
runtimerace·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;
runtimerace·FuncEnter(g->racectx, (void*)pc);
m->racecall = false;
}
// Called from instrumented code.
#pragma textflag 7
void
runtime·racefuncexit(void)
{
m->racecall = true;
runtimerace·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;
runtimerace·Malloc(m->curg->racectx, p, sz, pc);
m->racecall = false;
}
void
runtime·racefree(void *p)
{
m->racecall = true;
runtimerace·Free(p);
m->racecall = false;
}
uintptr
runtime·racegostart(void *pc)
{
uintptr racectx;
m->racecall = true;
runtimerace·GoStart(g->racectx, &racectx, pc);
m->racecall = false;
return racectx;
}
void
runtime·racegoend(void)
{
m->racecall = true;
runtimerace·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);
runtimerace·FuncEnter(racectx, (void*)callpc);
}
if(write)
runtimerace·Write(racectx, addr, (void*)pc);
else
runtimerace·Read(racectx, addr, (void*)pc);
if(callpc)
runtimerace·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);
runtimerace·FuncEnter(racectx, (void*)callpc);
}
if(write)
runtimerace·WriteRange(racectx, addr, size, step, (void*)pc);
else
runtimerace·ReadRange(racectx, addr, size, step, (void*)pc);
if(callpc)
runtimerace·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;
runtimerace·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;
runtimerace·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;
runtimerace·ReleaseMerge(gp->racectx, addr);
m->racecall = false;
}
void
runtime·racefingo(void)
{
m->racecall = true;
runtimerace·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 RaceReadRange(addr unsafe.Pointer, len int)
#pragma textflag 7
void
runtime·RaceReadRange(void *addr, intgo len)
{
rangeaccess(addr, len, 1, 0, (uintptr)runtime·getcallerpc(&addr), false);
}
// func RaceWriteRange(addr unsafe.Pointer, len int)
#pragma textflag 7
void
runtime·RaceWriteRange(void *addr, intgo len)
{
rangeaccess(addr, len, 1, 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;
}