root/src/pkg/runtime/race.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. runtime·raceinit
  2. runtime·racefini
  3. runtime·racemapshadow
  4. runtime·racemalloc
  5. runtime·racegostart
  6. runtime·racegoend
  7. runtime·racewriterangepc
  8. runtime·racereadrangepc
  9. runtime·racewriteobjectpc
  10. runtime·racereadobjectpc
  11. runtime·raceacquire
  12. runtime·raceacquireg
  13. runtime·racerelease
  14. runtime·racereleaseg
  15. runtime·racereleasemerge
  16. runtime·racereleasemergeg
  17. runtime·racefingo
  18. runtime·RaceAcquire
  19. runtime·RaceRelease
  20. runtime·RaceReleaseMerge
  21. runtime·RaceSemacquire
  22. runtime·RaceSemrelease
  23. runtime·RaceDisable
  24. runtime·RaceEnable
  25. runtime·racesymbolize

// 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), ...);

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 & ~KindNoPointers;
        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 & ~KindNoPointers;
        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)
                return;
        runtime·racecall(__tsan_acquire, gp->racectx, addr);
}

void
runtime·racerelease(void *addr)
{
        runtime·racereleaseg(g, addr);
}

void
runtime·racereleaseg(G *gp, void *addr)
{
        if(g->raceignore)
                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)
                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;
}

/* [<][>][^][v][top][bottom][index][help] */