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 
5 // The C definitions for tracebackctxt.go. That file uses //export so
6 // it can't put function definitions in the "C" import comment.
7 
8 #include <stdlib.h>
9 #include <stdint.h>
10 
11 // Functions exported from Go.
12 extern void G1(void);
13 extern void G2(void);
14 extern void TracebackContextPreemptionGoFunction(int);
15 
C1()16 void C1() {
17 	G1();
18 }
19 
C2()20 void C2() {
21 	G2();
22 }
23 
24 struct cgoContextArg {
25 	uintptr_t context;
26 };
27 
28 struct cgoTracebackArg {
29 	uintptr_t  context;
30 	uintptr_t  sigContext;
31 	uintptr_t* buf;
32 	uintptr_t  max;
33 };
34 
35 struct cgoSymbolizerArg {
36 	uintptr_t   pc;
37 	const char* file;
38 	uintptr_t   lineno;
39 	const char* func;
40 	uintptr_t   entry;
41 	uintptr_t   more;
42 	uintptr_t   data;
43 };
44 
45 // Uses atomic adds and subtracts to catch the possibility of
46 // erroneous calls from multiple threads; that should be impossible in
47 // this test case, but we check just in case.
48 static int contextCount;
49 
getContextCount()50 int getContextCount() {
51 	return __sync_add_and_fetch(&contextCount, 0);
52 }
53 
tcContext(void * parg)54 void tcContext(void* parg) {
55 	struct cgoContextArg* arg = (struct cgoContextArg*)(parg);
56 	if (arg->context == 0) {
57 		arg->context = __sync_add_and_fetch(&contextCount, 1);
58 	} else {
59 		if (arg->context != __sync_add_and_fetch(&contextCount, 0)) {
60 			abort();
61 		}
62 		__sync_sub_and_fetch(&contextCount, 1);
63 	}
64 }
65 
tcContextSimple(void * parg)66 void tcContextSimple(void* parg) {
67 	struct cgoContextArg* arg = (struct cgoContextArg*)(parg);
68 	if (arg->context == 0) {
69 		arg->context = 1;
70 	}
71 }
72 
tcTraceback(void * parg)73 void tcTraceback(void* parg) {
74 	int base, i;
75 	struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg);
76 	if (arg->context == 0 && arg->sigContext == 0) {
77 		// This shouldn't happen in this program.
78 		abort();
79 	}
80 	// Return a variable number of PC values.
81 	base = arg->context << 8;
82 	for (i = 0; i < arg->context; i++) {
83 		if (i < arg->max) {
84 			arg->buf[i] = base + i;
85 		}
86 	}
87 }
88 
tcSymbolizer(void * parg)89 void tcSymbolizer(void *parg) {
90 	struct cgoSymbolizerArg* arg = (struct cgoSymbolizerArg*)(parg);
91 	if (arg->pc == 0) {
92 		return;
93 	}
94 	// Report two lines per PC returned by traceback, to test more handling.
95 	arg->more = arg->file == NULL;
96 	arg->file = "tracebackctxt.go";
97 	arg->func = "cFunction";
98 	arg->lineno = arg->pc + (arg->more << 16);
99 }
100 
TracebackContextPreemptionCallGo(int i)101 void TracebackContextPreemptionCallGo(int i) {
102 	TracebackContextPreemptionGoFunction(i);
103 }
104