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

267 lines
5.3 KiB
C
Raw Normal View History

// 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(void);
void runtimerace·Finalize(void);
void runtimerace·FinalizerGoroutine(int32);
void runtimerace·Read(int32 goid, void *addr, void *pc);
void runtimerace·Write(int32 goid, void *addr, void *pc);
void runtimerace·FuncEnter(int32 goid, void *pc);
void runtimerace·FuncExit(int32 goid);
void runtimerace·Malloc(int32 goid, void *p, uintptr sz, void *pc);
void runtimerace·Free(void *p);
void runtimerace·GoStart(int32 pgoid, int32 chgoid, void *pc);
void runtimerace·GoEnd(int32 goid);
void runtimerace·Acquire(int32 goid, void *addr);
void runtimerace·Release(int32 goid, void *addr);
void runtimerace·ReleaseMerge(int32 goid, void *addr);
extern byte noptrdata[];
extern byte enoptrbss[];
static bool onstack(uintptr argp);
void
runtime·raceinit(void)
{
m->racecall = true;
runtimerace·Initialize();
m->racecall = false;
}
void
runtime·racefini(void)
{
m->racecall = true;
runtimerace·Finalize();
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->goid-1, (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->goid-1, (void*)addr, runtime·getcallerpc(&addr));
m->racecall = false;
}
}
// Called from instrumented code.
#pragma textflag 7
void
runtime·racefuncenter(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->goid-1, (void*)pc);
m->racecall = false;
}
// Called from instrumented code.
#pragma textflag 7
void
runtime·racefuncexit(void)
{
m->racecall = true;
runtimerace·FuncExit(g->goid-1);
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->goid-1, p, sz, pc);
m->racecall = false;
}
void
runtime·racefree(void *p)
{
m->racecall = true;
runtimerace·Free(p);
m->racecall = false;
}
void
runtime·racegostart(int32 goid, void *pc)
{
m->racecall = true;
runtimerace·GoStart(g->goid-1, goid-1, pc);
m->racecall = false;
}
void
runtime·racegoend(int32 goid)
{
m->racecall = true;
runtimerace·GoEnd(goid-1);
m->racecall = false;
}
void
runtime·racewritepc(void *addr, void *pc)
{
if(!onstack((uintptr)addr)) {
m->racecall = true;
runtimerace·Write(g->goid-1, addr, pc);
m->racecall = false;
}
}
void
runtime·racereadpc(void *addr, void *pc)
{
if(!onstack((uintptr)addr)) {
m->racecall = true;
runtimerace·Read(g->goid-1, addr, pc);
m->racecall = 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->goid-1, 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->goid-1, 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->goid-1, addr);
m->racecall = false;
}
void
runtime·racefingo(void)
{
m->racecall = true;
runtimerace·FinalizerGoroutine(g->goid - 1);
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 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;
}