introduce TDF_compare_debug, omit OBJ_TYPE_REF casts with it
[official-gcc.git] / libgo / misc / cgo / test / issue7978.go
blob7fb62e807ba8cca661794309bb2fb34c50d10743
1 // Copyright 2014 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.
5 // Issue 7978. Stack tracing didn't work during cgo code after calling a Go
6 // callback. Make sure GC works and the stack trace is correct.
8 package cgotest
11 #include <stdint.h>
13 void issue7978cb(void);
15 #if defined(__APPLE__) && defined(__arm__)
16 // on Darwin/ARM, libSystem doesn't provide implementation of the __sync_fetch_and_add
17 // primitive, and although gcc supports it, it doesn't inline its definition.
18 // Clang could inline its definition, so we require clang on Darwin/ARM.
19 #if defined(__clang__)
20 #define HAS_SYNC_FETCH_AND_ADD 1
21 #else
22 #define HAS_SYNC_FETCH_AND_ADD 0
23 #endif
24 #else
25 #define HAS_SYNC_FETCH_AND_ADD 1
26 #endif
28 // use ugly atomic variable sync since that doesn't require calling back into
29 // Go code or OS dependencies
30 static void issue7978c(uint32_t *sync) {
31 #if HAS_SYNC_FETCH_AND_ADD
32 while(__sync_fetch_and_add(sync, 0) != 0)
34 __sync_fetch_and_add(sync, 1);
35 while(__sync_fetch_and_add(sync, 0) != 2)
37 issue7978cb();
38 __sync_fetch_and_add(sync, 1);
39 while(__sync_fetch_and_add(sync, 0) != 6)
41 #endif
44 import "C"
46 import (
47 "os"
48 "runtime"
49 "strings"
50 "sync/atomic"
51 "testing"
54 var issue7978sync uint32
56 func issue7978check(t *testing.T, wantFunc string, badFunc string, depth int) {
57 runtime.GC()
58 buf := make([]byte, 65536)
59 trace := string(buf[:runtime.Stack(buf, true)])
60 for _, goroutine := range strings.Split(trace, "\n\n") {
61 if strings.Contains(goroutine, "test.issue7978go") {
62 trace := strings.Split(goroutine, "\n")
63 // look for the expected function in the stack
64 for i := 0; i < depth; i++ {
65 if badFunc != "" && strings.Contains(trace[1+2*i], badFunc) {
66 t.Errorf("bad stack: found %s in the stack:\n%s", badFunc, goroutine)
67 return
69 if strings.Contains(trace[1+2*i], wantFunc) {
70 return
73 t.Errorf("bad stack: didn't find %s in the stack:\n%s", wantFunc, goroutine)
74 return
77 t.Errorf("bad stack: goroutine not found. Full stack dump:\n%s", trace)
80 func issue7978wait(store uint32, wait uint32) {
81 if store != 0 {
82 atomic.StoreUint32(&issue7978sync, store)
84 for atomic.LoadUint32(&issue7978sync) != wait {
85 runtime.Gosched()
89 //export issue7978cb
90 func issue7978cb() {
91 // Force a stack growth from the callback to put extra
92 // pressure on the runtime. See issue #17785.
93 growStack(64)
94 issue7978wait(3, 4)
97 func growStack(n int) int {
98 var buf [128]int
99 if n == 0 {
100 return 0
102 return buf[growStack(n-1)]
105 func issue7978go() {
106 C.issue7978c((*C.uint32_t)(&issue7978sync))
107 issue7978wait(7, 8)
110 func test7978(t *testing.T) {
111 if runtime.Compiler == "gccgo" {
112 t.Skip("gccgo can not do stack traces of C code")
114 if C.HAS_SYNC_FETCH_AND_ADD == 0 {
115 t.Skip("clang required for __sync_fetch_and_add support on darwin/arm")
117 if runtime.GOOS == "android" || runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
118 t.Skip("GOTRACEBACK is not passed on to the exec wrapper")
120 if os.Getenv("GOTRACEBACK") != "2" {
121 t.Fatalf("GOTRACEBACK must be 2")
123 issue7978sync = 0
124 go issue7978go()
125 // test in c code, before callback
126 issue7978wait(0, 1)
127 issue7978check(t, "_Cfunc_issue7978c(", "", 1)
128 // test in go code, during callback
129 issue7978wait(2, 3)
130 issue7978check(t, "test.issue7978cb(", "test.issue7978go", 3)
131 // test in c code, after callback
132 issue7978wait(4, 5)
133 issue7978check(t, "_Cfunc_issue7978c(", "_cgoexpwrap", 1)
134 // test in go code, after return from cgo
135 issue7978wait(6, 7)
136 issue7978check(t, "test.issue7978go(", "", 3)
137 atomic.StoreUint32(&issue7978sync, 8)