blob: 69078b7bc70883d7643859dc992f8301c8d1b75c [file] [log] [blame]
// Copyright 2016 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.
//go:build !gccgo
// +build !gccgo
package main
// Test the context argument to SetCgoTraceback.
// Use fake context, traceback, and symbolizer functions.
/*
// Defined in tracebackctxt_c.c.
extern void C1(void);
extern void C2(void);
extern void tcContext(void*);
extern void tcContextSimple(void*);
extern void tcTraceback(void*);
extern void tcSymbolizer(void*);
extern int getContextCount(void);
extern void TracebackContextPreemptionCallGo(int);
*/
import "C"
import (
"fmt"
"runtime"
"sync"
"unsafe"
)
func init() {
register("TracebackContext", TracebackContext)
register("TracebackContextPreemption", TracebackContextPreemption)
}
var tracebackOK bool
func TracebackContext() {
runtime.SetCgoTraceback(0, unsafe.Pointer(C.tcTraceback), unsafe.Pointer(C.tcContext), unsafe.Pointer(C.tcSymbolizer))
C.C1()
if got := C.getContextCount(); got != 0 {
fmt.Printf("at end contextCount == %d, expected 0\n", got)
tracebackOK = false
}
if tracebackOK {
fmt.Println("OK")
}
}
//export G1
func G1() {
C.C2()
}
//export G2
func G2() {
pc := make([]uintptr, 32)
n := runtime.Callers(0, pc)
cf := runtime.CallersFrames(pc[:n])
var frames []runtime.Frame
for {
frame, more := cf.Next()
frames = append(frames, frame)
if !more {
break
}
}
want := []struct {
function string
line int
}{
{"main.G2", 0},
{"cFunction", 0x10200},
{"cFunction", 0x200},
{"cFunction", 0x10201},
{"cFunction", 0x201},
{"main.G1", 0},
{"cFunction", 0x10100},
{"cFunction", 0x100},
{"main.TracebackContext", 0},
}
ok := true
i := 0
wantLoop:
for _, w := range want {
for ; i < len(frames); i++ {
if w.function == frames[i].Function {
if w.line != 0 && w.line != frames[i].Line {
fmt.Printf("found function %s at wrong line %#x (expected %#x)\n", w.function, frames[i].Line, w.line)
ok = false
}
i++
continue wantLoop
}
}
fmt.Printf("did not find function %s in\n", w.function)
for _, f := range frames {
fmt.Println(f)
}
ok = false
break
}
tracebackOK = ok
if got := C.getContextCount(); got != 2 {
fmt.Printf("at bottom contextCount == %d, expected 2\n", got)
tracebackOK = false
}
}
// Issue 47441.
func TracebackContextPreemption() {
runtime.SetCgoTraceback(0, unsafe.Pointer(C.tcTraceback), unsafe.Pointer(C.tcContextSimple), unsafe.Pointer(C.tcSymbolizer))
const funcs = 10
const calls = 1e5
var wg sync.WaitGroup
for i := 0; i < funcs; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
for j := 0; j < calls; j++ {
C.TracebackContextPreemptionCallGo(C.int(i*calls + j))
}
}(i)
}
wg.Wait()
fmt.Println("OK")
}
//export TracebackContextPreemptionGoFunction
func TracebackContextPreemptionGoFunction(i C.int) {
// Do some busy work.
fmt.Sprintf("%d\n", i)
}