1// Copyright 2016 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package main
6
7// Test the context argument to SetCgoTraceback.
8// Use fake context, traceback, and symbolizer functions.
9
10/*
11// Defined in tracebackctxt_c.c.
12extern void C1(void);
13extern void C2(void);
14extern void tcContext(void*);
15extern void tcContextSimple(void*);
16extern void tcTraceback(void*);
17extern void tcSymbolizer(void*);
18extern int getContextCount(void);
19extern void TracebackContextPreemptionCallGo(int);
20*/
21import "C"
22
23import (
24	"fmt"
25	"runtime"
26	"sync"
27	"unsafe"
28)
29
30func init() {
31	register("TracebackContext", TracebackContext)
32	register("TracebackContextPreemption", TracebackContextPreemption)
33}
34
35var tracebackOK bool
36
37func TracebackContext() {
38	runtime.SetCgoTraceback(0, unsafe.Pointer(C.tcTraceback), unsafe.Pointer(C.tcContext), unsafe.Pointer(C.tcSymbolizer))
39	C.C1()
40	if got := C.getContextCount(); got != 0 {
41		fmt.Printf("at end contextCount == %d, expected 0\n", got)
42		tracebackOK = false
43	}
44	if tracebackOK {
45		fmt.Println("OK")
46	}
47}
48
49//export G1
50func G1() {
51	C.C2()
52}
53
54//export G2
55func G2() {
56	pc := make([]uintptr, 32)
57	n := runtime.Callers(0, pc)
58	cf := runtime.CallersFrames(pc[:n])
59	var frames []runtime.Frame
60	for {
61		frame, more := cf.Next()
62		frames = append(frames, frame)
63		if !more {
64			break
65		}
66	}
67
68	want := []struct {
69		function string
70		line     int
71	}{
72		{"main.G2", 0},
73		{"cFunction", 0x10200},
74		{"cFunction", 0x200},
75		{"cFunction", 0x10201},
76		{"cFunction", 0x201},
77		{"main.G1", 0},
78		{"cFunction", 0x10100},
79		{"cFunction", 0x100},
80		{"main.TracebackContext", 0},
81	}
82
83	ok := true
84	i := 0
85wantLoop:
86	for _, w := range want {
87		for ; i < len(frames); i++ {
88			if w.function == frames[i].Function {
89				if w.line != 0 && w.line != frames[i].Line {
90					fmt.Printf("found function %s at wrong line %#x (expected %#x)\n", w.function, frames[i].Line, w.line)
91					ok = false
92				}
93				i++
94				continue wantLoop
95			}
96		}
97		fmt.Printf("did not find function %s in\n", w.function)
98		for _, f := range frames {
99			fmt.Println(f)
100		}
101		ok = false
102		break
103	}
104	tracebackOK = ok
105	if got := C.getContextCount(); got != 2 {
106		fmt.Printf("at bottom contextCount == %d, expected 2\n", got)
107		tracebackOK = false
108	}
109}
110
111// Issue 47441.
112func TracebackContextPreemption() {
113	runtime.SetCgoTraceback(0, unsafe.Pointer(C.tcTraceback), unsafe.Pointer(C.tcContextSimple), unsafe.Pointer(C.tcSymbolizer))
114
115	const funcs = 10
116	const calls = 1e5
117	var wg sync.WaitGroup
118	for i := 0; i < funcs; i++ {
119		wg.Add(1)
120		go func(i int) {
121			defer wg.Done()
122			for j := 0; j < calls; j++ {
123				C.TracebackContextPreemptionCallGo(C.int(i*calls + j))
124			}
125		}(i)
126	}
127	wg.Wait()
128
129	fmt.Println("OK")
130}
131
132//export TracebackContextPreemptionGoFunction
133func TracebackContextPreemptionGoFunction(i C.int) {
134	// Do some busy work.
135	fmt.Sprintf("%d\n", i)
136}
137