1
0
mirror of https://github.com/golang/go synced 2024-11-20 09:04:44 -07:00
go/src/pkg/runtime/race.c
Rémy Oudompheng 3be794cdc2 cmd/gc: instrument arrays properly in race detector.
The previous implementation would only record access to
the address of the array but the memory access to the whole
memory range must be recorded instead.

R=golang-dev, dvyukov, r
CC=golang-dev
https://golang.org/cl/8053044
2013-06-14 11:14:45 +02:00

396 lines
8.4 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, void *pc);
void runtimerace·WriteRange(uintptr racectx, void *addr, uintptr sz, 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;
}
}
#pragma textflag 7
void
runtime·racewriterange(uintptr addr, uintptr sz)
{
if(!onstack(addr)) {
m->racecall = true;
runtimerace·WriteRange(g->racectx, (void*)addr, sz, 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;
}
}
#pragma textflag 7
void
runtime·racereadrange(uintptr addr, uintptr sz)
{
if(!onstack(addr)) {
m->racecall = true;
runtimerace·ReadRange(g->racectx, (void*)addr, sz, 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 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, (void*)pc);
else
runtimerace·ReadRange(racectx, addr, size, (void*)pc);
if(callpc)
runtimerace·FuncExit(racectx);
m->racecall = false;
}
}
void
runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc)
{
rangeaccess(addr, sz, (uintptr)callpc, (uintptr)pc, true);
}
void
runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc)
{
rangeaccess(addr, sz, (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, 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, 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;
}