github.com/zach-klippenstein/go@v0.0.0-20150108044943-fcfbeb3adf58/misc/cgo/test/issue7978.go (about) 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. 4 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. 7 8 package cgotest 9 10 /* 11 #include <stdint.h> 12 13 void issue7978cb(void); 14 15 // use ugly atomic variable sync since that doesn't require calling back into 16 // Go code or OS dependencies 17 static void issue7978c(uint32_t *sync) { 18 while(__sync_fetch_and_add(sync, 0) != 0) 19 ; 20 __sync_fetch_and_add(sync, 1); 21 while(__sync_fetch_and_add(sync, 0) != 2) 22 ; 23 issue7978cb(); 24 __sync_fetch_and_add(sync, 1); 25 while(__sync_fetch_and_add(sync, 0) != 6) 26 ; 27 } 28 */ 29 import "C" 30 31 import ( 32 "os" 33 "runtime" 34 "strings" 35 "sync/atomic" 36 "testing" 37 ) 38 39 var issue7978sync uint32 40 41 func issue7978check(t *testing.T, wantFunc string, badFunc string, depth int) { 42 runtime.GC() 43 buf := make([]byte, 65536) 44 trace := string(buf[:runtime.Stack(buf, true)]) 45 for _, goroutine := range strings.Split(trace, "\n\n") { 46 if strings.Contains(goroutine, "test.issue7978go") { 47 trace := strings.Split(goroutine, "\n") 48 // look for the expected function in the stack 49 for i := 0; i < depth; i++ { 50 if badFunc != "" && strings.Contains(trace[1+2*i], badFunc) { 51 t.Errorf("bad stack: found %s in the stack:\n%s", badFunc, goroutine) 52 return 53 } 54 if strings.Contains(trace[1+2*i], wantFunc) { 55 return 56 } 57 } 58 t.Errorf("bad stack: didn't find %s in the stack:\n%s", wantFunc, goroutine) 59 return 60 } 61 } 62 t.Errorf("bad stack: goroutine not found. Full stack dump:\n%s", trace) 63 } 64 65 func issue7978wait(store uint32, wait uint32) { 66 if store != 0 { 67 atomic.StoreUint32(&issue7978sync, store) 68 } 69 for atomic.LoadUint32(&issue7978sync) != wait { 70 runtime.Gosched() 71 } 72 } 73 74 //export issue7978cb 75 func issue7978cb() { 76 issue7978wait(3, 4) 77 } 78 79 func issue7978go() { 80 C.issue7978c((*C.uint32_t)(&issue7978sync)) 81 issue7978wait(7, 8) 82 } 83 84 func test7978(t *testing.T) { 85 if runtime.Compiler == "gccgo" { 86 t.Skip("gccgo can not do stack traces of C code") 87 } 88 if os.Getenv("GOTRACEBACK") != "2" { 89 t.Fatalf("GOTRACEBACK must be 2") 90 } 91 issue7978sync = 0 92 go issue7978go() 93 // test in c code, before callback 94 issue7978wait(0, 1) 95 issue7978check(t, "runtime.cgocall_errno(", "", 1) 96 // test in go code, during callback 97 issue7978wait(2, 3) 98 issue7978check(t, "test.issue7978cb(", "test.issue7978go", 3) 99 // test in c code, after callback 100 issue7978wait(4, 5) 101 issue7978check(t, "runtime.cgocall_errno(", "runtime.cgocallback", 1) 102 // test in go code, after return from cgo 103 issue7978wait(6, 7) 104 issue7978check(t, "test.issue7978go(", "", 3) 105 atomic.StoreUint32(&issue7978sync, 8) 106 }