| // Copyright 2012 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. |
| |
| // +build race |
| |
| // Public race detection API, present iff build with -race. |
| |
| package runtime |
| |
| import ( |
| "unsafe" |
| ) |
| |
| func racefini() |
| |
| // RaceDisable disables handling of race events in the current goroutine. |
| func RaceDisable() |
| |
| // RaceEnable re-enables handling of race events in the current goroutine. |
| func RaceEnable() |
| |
| func RaceAcquire(addr unsafe.Pointer) |
| func RaceRelease(addr unsafe.Pointer) |
| func RaceReleaseMerge(addr unsafe.Pointer) |
| |
| func RaceRead(addr unsafe.Pointer) |
| func RaceWrite(addr unsafe.Pointer) |
| func RaceReadRange(addr unsafe.Pointer, len int) |
| func RaceWriteRange(addr unsafe.Pointer, len int) |
| |
| func RaceSemacquire(s *uint32) |
| func RaceSemrelease(s *uint32) |
| |
| // private interface for the runtime |
| const raceenabled = true |
| |
| func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { |
| kind := t.kind & kindMask |
| if kind == kindArray || kind == kindStruct { |
| // for composite objects we have to read every address |
| // because a write might happen to any subobject. |
| racereadrangepc(addr, t.size, callerpc, pc) |
| } else { |
| // for non-composite objects we can read just the start |
| // address, as any write must write the first byte. |
| racereadpc(addr, callerpc, pc) |
| } |
| } |
| |
| func raceWriteObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { |
| kind := t.kind & kindMask |
| if kind == kindArray || kind == kindStruct { |
| // for composite objects we have to write every address |
| // because a write might happen to any subobject. |
| racewriterangepc(addr, t.size, callerpc, pc) |
| } else { |
| // for non-composite objects we can write just the start |
| // address, as any write must write the first byte. |
| racewritepc(addr, callerpc, pc) |
| } |
| } |
| |
| //go:noescape |
| func racereadpc(addr unsafe.Pointer, callpc, pc uintptr) |
| |
| //go:noescape |
| func racewritepc(addr unsafe.Pointer, callpc, pc uintptr) |
| |
| //go:noescape |
| func racereadrangepc(addr unsafe.Pointer, len uintptr, callpc, pc uintptr) |
| |
| //go:noescape |
| func racewriterangepc(addr unsafe.Pointer, len uintptr, callpc, pc uintptr) |
| |
| //go:noescape |
| func raceacquire(addr unsafe.Pointer) |
| |
| //go:noescape |
| func racerelease(addr unsafe.Pointer) |
| |
| //go:noescape |
| func raceacquireg(gp *g, addr unsafe.Pointer) |
| |
| //go:noescape |
| func racereleaseg(gp *g, addr unsafe.Pointer) |
| |
| func racefingo() |
| |
| //go:noescape |
| func racemalloc(p unsafe.Pointer, size uintptr) |
| |
| //go:noescape |
| func racereleasemerge(addr unsafe.Pointer) |
| |
| type symbolizeContext struct { |
| pc uintptr |
| fn *byte |
| file *byte |
| line uintptr |
| off uintptr |
| res uintptr |
| } |
| |
| var qq = [...]byte{'?', '?', 0} |
| var dash = [...]byte{'-', 0} |
| |
| // Callback from C into Go, runs on g0. |
| func racesymbolize(ctx *symbolizeContext) { |
| f := findfunc(ctx.pc) |
| if f == nil { |
| ctx.fn = &qq[0] |
| ctx.file = &dash[0] |
| ctx.line = 0 |
| ctx.off = ctx.pc |
| ctx.res = 1 |
| return |
| } |
| |
| ctx.fn = funcname(f) |
| var file string |
| ctx.line = uintptr(funcline(f, ctx.pc, &file)) |
| ctx.file = &bytes(file)[0] // assume NUL-terminated |
| ctx.off = ctx.pc - f.entry |
| ctx.res = 1 |
| return |
| } |