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  }
    42  
    43  //export go_callback
    44  func go_callback() {
    45  	if e := extraMInUse.Load(); e == 0 {
    46  		fmt.Printf("in callback extraMInUse got %d want >0\n", e)
    47  		os.Exit(1)
    48  	}
    49  
    50  	runtime.GC()
    51  	grow()
    52  	runtime.GC()
    53  }
    54  
    55  var cnt int
    56  
    57  func grow() {
    58  	x := 10000
    59  	sum := 0
    60  	if grow1(&x, &sum) == 0 {
    61  		panic("bad")
    62  	}
    63  }
    64  
    65  func grow1(x, sum *int) int {
    66  	if *x == 0 {
    67  		return *sum + 1
    68  	}
    69  	*x--
    70  	sum1 := *sum + *x
    71  	return grow1(x, &sum1)
    72  }
    73  
    74  func CgoCallbackGC() {
    75  	P := 100
    76  	if os.Getenv("RUNTIME_TEST_SHORT") != "" {
    77  		P = 10
    78  	}
    79  
    80  	if e := extraMInUse.Load(); e != 0 {
    81  		fmt.Printf("before testing extraMInUse got %d want 0\n", e)
    82  		os.Exit(1)
    83  	}
    84  
    85  	done := make(chan bool)
    86  	// allocate a bunch of stack frames and spray them with pointers
    87  	for i := 0; i < P; i++ {
    88  		go func() {
    89  			grow()
    90  			done <- true
    91  		}()
    92  	}
    93  	for i := 0; i < P; i++ {
    94  		<-done
    95  	}
    96  	// now give these stack frames to cgo callbacks
    97  	for i := 0; i < P; i++ {
    98  		go func() {
    99  			C.foo()
   100  			done <- true
   101  		}()
   102  	}
   103  	for i := 0; i < P; i++ {
   104  		<-done
   105  	}
   106  
   107  	if e := extraMInUse.Load(); e != 0 {
   108  		fmt.Printf("after testing extraMInUse got %d want 0\n", e)
   109  		os.Exit(1)
   110  	}
   111  
   112  	fmt.Printf("OK\n")
   113  }
   114  
   115  //go:linkname extraMInUse runtime.extraMInUse
   116  var extraMInUse atomic.Uint32
   117  

View as plain text