1
0
mirror of https://github.com/golang/go synced 2024-10-04 14:31:21 -06:00
go/src/pkg/runtime/race.c
Dmitriy Vyukov cd17a717f9 runtime: simpler and faster GC
Implement the design described in:
https://docs.google.com/document/d/1v4Oqa0WwHunqlb8C3ObL_uNQw3DfSY-ztoA-4wWbKcg/pub

Summary of the changes:
GC uses "2-bits per word" pointer type info embed directly into bitmap.
Scanning of stacks/data/heap is unified.
The old spans types go away.
Compiler generates "sparse" 4-bits type info for GC (directly for GC bitmap).
Linker generates "dense" 2-bits type info for data/bss (the same as stacks use).

Summary of results:
-1680 lines of code total (-1000+ in mgc0.c only)
-25% memory consumption
-3-7% binary size
-15% GC pause reduction
-7% run time reduction

LGTM=khr
R=golang-codereviews, rsc, christoph, khr
CC=golang-codereviews, rlh
https://golang.org/cl/106260045
2014-07-29 11:01:02 +04:00

306 lines
6.6 KiB
C

// 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"
#include "type.h"
#include "typekind.h"
// Race runtime functions called via runtime·racecall.
void __tsan_init(void);
void __tsan_fini(void);
void __tsan_map_shadow(void);
void __tsan_finalizer_goroutine(void);
void __tsan_go_start(void);
void __tsan_go_end(void);
void __tsan_malloc(void);
void __tsan_acquire(void);
void __tsan_release(void);
void __tsan_release_merge(void);
// Mimic what cmd/cgo would do.
#pragma cgo_import_static __tsan_init
#pragma cgo_import_static __tsan_fini
#pragma cgo_import_static __tsan_map_shadow
#pragma cgo_import_static __tsan_finalizer_goroutine
#pragma cgo_import_static __tsan_go_start
#pragma cgo_import_static __tsan_go_end
#pragma cgo_import_static __tsan_malloc
#pragma cgo_import_static __tsan_acquire
#pragma cgo_import_static __tsan_release
#pragma cgo_import_static __tsan_release_merge
// These are called from race_amd64.s.
#pragma cgo_import_static __tsan_read
#pragma cgo_import_static __tsan_read_pc
#pragma cgo_import_static __tsan_read_range
#pragma cgo_import_static __tsan_write
#pragma cgo_import_static __tsan_write_pc
#pragma cgo_import_static __tsan_write_range
#pragma cgo_import_static __tsan_func_enter
#pragma cgo_import_static __tsan_func_exit
extern byte noptrdata[];
extern byte enoptrbss[];
// start/end of heap for race_amd64.s
uintptr runtime·racearenastart;
uintptr runtime·racearenaend;
void runtime·racefuncenter(void *callpc);
void runtime·racefuncexit(void);
void runtime·racereadrangepc1(void *addr, uintptr sz, void *pc);
void runtime·racewriterangepc1(void *addr, uintptr sz, void *pc);
void runtime·racesymbolizethunk(void*);
// racecall allows calling an arbitrary function f from C race runtime
// with up to 4 uintptr arguments.
void runtime·racecall(void(*f)(void), ...);
// checks if the address has shadow (i.e. heap or data/bss)
static bool
isvalidaddr(uintptr addr)
{
if(addr >= runtime·racearenastart && addr < runtime·racearenaend)
return true;
if(addr >= (uintptr)noptrdata && addr < (uintptr)enoptrbss)
return true;
return false;
}
uintptr
runtime·raceinit(void)
{
uintptr racectx, start, size;
// cgo is required to initialize libc, which is used by race runtime
if(!runtime·iscgo)
runtime·throw("raceinit: race build must use cgo");
runtime·racecall(__tsan_init, &racectx, runtime·racesymbolizethunk);
// Round data segment to page boundaries, because it's used in mmap().
start = (uintptr)noptrdata & ~(PageSize-1);
size = ROUND((uintptr)enoptrbss - start, PageSize);
runtime·racecall(__tsan_map_shadow, start, size);
return racectx;
}
void
runtime·racefini(void)
{
runtime·racecall(__tsan_fini);
}
void
runtime·racemapshadow(void *addr, uintptr size)
{
if(runtime·racearenastart == 0)
runtime·racearenastart = (uintptr)addr;
if(runtime·racearenaend < (uintptr)addr+size)
runtime·racearenaend = (uintptr)addr+size;
runtime·racecall(__tsan_map_shadow, addr, size);
}
void
runtime·racemalloc(void *p, uintptr sz)
{
runtime·racecall(__tsan_malloc, p, sz);
}
uintptr
runtime·racegostart(void *pc)
{
uintptr racectx;
runtime·racecall(__tsan_go_start, g->racectx, &racectx, pc);
return racectx;
}
void
runtime·racegoend(void)
{
runtime·racecall(__tsan_go_end, g->racectx);
}
void
runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc)
{
if(callpc != nil)
runtime·racefuncenter(callpc);
runtime·racewriterangepc1(addr, sz, pc);
if(callpc != nil)
runtime·racefuncexit();
}
void
runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc)
{
if(callpc != nil)
runtime·racefuncenter(callpc);
runtime·racereadrangepc1(addr, sz, pc);
if(callpc != nil)
runtime·racefuncexit();
}
void
runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc)
{
uint8 kind;
kind = t->kind & KindMask;
if(kind == KindArray || kind == KindStruct)
runtime·racewriterangepc(addr, t->size, callpc, pc);
else
runtime·racewritepc(addr, callpc, pc);
}
void
runtime·racereadobjectpc(void *addr, Type *t, void *callpc, void *pc)
{
uint8 kind;
kind = t->kind & KindMask;
if(kind == KindArray || kind == KindStruct)
runtime·racereadrangepc(addr, t->size, callpc, pc);
else
runtime·racereadpc(addr, callpc, pc);
}
void
runtime·raceacquire(void *addr)
{
runtime·raceacquireg(g, addr);
}
void
runtime·raceacquireg(G *gp, void *addr)
{
if(g->raceignore || !isvalidaddr((uintptr)addr))
return;
runtime·racecall(__tsan_acquire, gp->racectx, addr);
}
void
runtime·racerelease(void *addr)
{
if(g->raceignore || !isvalidaddr((uintptr)addr))
return;
runtime·racereleaseg(g, addr);
}
void
runtime·racereleaseg(G *gp, void *addr)
{
if(g->raceignore || !isvalidaddr((uintptr)addr))
return;
runtime·racecall(__tsan_release, gp->racectx, addr);
}
void
runtime·racereleasemerge(void *addr)
{
runtime·racereleasemergeg(g, addr);
}
void
runtime·racereleasemergeg(G *gp, void *addr)
{
if(g->raceignore || !isvalidaddr((uintptr)addr))
return;
runtime·racecall(__tsan_release_merge, gp->racectx, addr);
}
void
runtime·racefingo(void)
{
runtime·racecall(__tsan_finalizer_goroutine, g->racectx);
}
// 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, false);
}
// 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--;
}
typedef struct SymbolizeContext SymbolizeContext;
struct SymbolizeContext
{
uintptr pc;
int8* func;
int8* file;
uintptr line;
uintptr off;
uintptr res;
};
// Callback from C into Go, runs on g0.
void
runtime·racesymbolize(SymbolizeContext *ctx)
{
Func *f;
String file;
f = runtime·findfunc(ctx->pc);
if(f == nil) {
ctx->func = "??";
ctx->file = "-";
ctx->line = 0;
ctx->off = ctx->pc;
ctx->res = 1;
return;
}
ctx->func = runtime·funcname(f);
ctx->line = runtime·funcline(f, ctx->pc, &file);
ctx->file = (int8*)file.str; // assume zero-terminated
ctx->off = ctx->pc - f->entry;
ctx->res = 1;
}