github.com/ccccaoqing/test@v0.0.0-20220510085219-3985d23445c0/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 os.Getenv("GOTRACEBACK") != "2" {
    86  		t.Fatalf("GOTRACEBACK must be 2")
    87  	}
    88  	issue7978sync = 0
    89  	go issue7978go()
    90  	// test in c code, before callback
    91  	issue7978wait(0, 1)
    92  	issue7978check(t, "runtime.cgocall_errno(", "", 1)
    93  	// test in go code, during callback
    94  	issue7978wait(2, 3)
    95  	issue7978check(t, "test.issue7978cb(", "test.issue7978go", 3)
    96  	// test in c code, after callback
    97  	issue7978wait(4, 5)
    98  	issue7978check(t, "runtime.cgocall_errno(", "runtime.cgocallback", 1)
    99  	// test in go code, after return from cgo
   100  	issue7978wait(6, 7)
   101  	issue7978check(t, "test.issue7978go(", "", 3)
   102  	atomic.StoreUint32(&issue7978sync, 8)
   103  }