Source file src/runtime/testdata/testprogcgo/callback.go

     1  // Copyright 2015 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  //go:build !plan9 && !windows
     6  // +build !plan9,!windows
     7  
     8  package main
     9  
    10  /*
    11  #include <pthread.h>
    12  
    13  void go_callback();
    14  
    15  static void *thr(void *arg) {
    16      go_callback();
    17      return 0;
    18  }
    19  
    20  static void foo() {
    21      pthread_t th;
    22      pthread_attr_t attr;
    23      pthread_attr_init(&attr);
    24      pthread_attr_setstacksize(&attr, 256 << 10);
    25      pthread_create(&th, &attr, thr, 0);
    26      pthread_join(th, 0);
    27  }
    28  */
    29  import "C"
    30  
    31  import (
    32  	"fmt"
    33  	"os"
    34  	"runtime"
    35  	"sync/atomic"
    36  	_ "unsafe" // for go:linkname
    37  )
    38  
    39  func init() {
    40  	register("CgoCallbackGC", CgoCallbackGC)
    41  	register("CgoToGoCallGoexit", CgoToGoCallGoexit)
    42  }
    43  
    44  func CgoToGoCallGoexit() {
    45  	goexit = true
    46  	C.foo()
    47  }
    48  
    49  var goexit = false
    50  
    51  //export go_callback
    52  func go_callback() {
    53  	if goexit {
    54  		runtime.Goexit()
    55  	}
    56  	if e := extraMInUse.Load(); e == 0 {
    57  		fmt.Printf("in callback extraMInUse got %d want >0\n", e)
    58  		os.Exit(1)
    59  	}
    60  
    61  	runtime.GC()
    62  	grow()
    63  	runtime.GC()
    64  }
    65  
    66  var cnt int
    67  
    68  func grow() {
    69  	x := 10000
    70  	sum := 0
    71  	if grow1(&x, &sum) == 0 {
    72  		panic("bad")
    73  	}
    74  }
    75  
    76  func grow1(x, sum *int) int {
    77  	if *x == 0 {
    78  		return *sum + 1
    79  	}
    80  	*x--
    81  	sum1 := *sum + *x
    82  	return grow1(x, &sum1)
    83  }
    84  
    85  func CgoCallbackGC() {
    86  	P := 100
    87  	if os.Getenv("RUNTIME_TEST_SHORT") != "" {
    88  		P = 10
    89  	}
    90  
    91  	if e := extraMInUse.Load(); e != 0 {
    92  		fmt.Printf("before testing extraMInUse got %d want 0\n", e)
    93  		os.Exit(1)
    94  	}
    95  
    96  	done := make(chan bool)
    97  	// allocate a bunch of stack frames and spray them with pointers
    98  	for i := 0; i < P; i++ {
    99  		go func() {
   100  			grow()
   101  			done <- true
   102  		}()
   103  	}
   104  	for i := 0; i < P; i++ {
   105  		<-done
   106  	}
   107  	// now give these stack frames to cgo callbacks
   108  	for i := 0; i < P; i++ {
   109  		go func() {
   110  			C.foo()
   111  			done <- true
   112  		}()
   113  	}
   114  	for i := 0; i < P; i++ {
   115  		<-done
   116  	}
   117  
   118  	if e := extraMInUse.Load(); e != 0 {
   119  		fmt.Printf("after testing extraMInUse got %d want 0\n", e)
   120  		os.Exit(1)
   121  	}
   122  
   123  	fmt.Printf("OK\n")
   124  }
   125  
   126  //go:linkname extraMInUse runtime.extraMInUse
   127  var extraMInUse atomic.Uint32
   128  

View as plain text