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// +build !plan9,!windows
6
7package main
8
9/*
10#cgo CFLAGS: -pthread
11#cgo LDFLAGS: -pthread
12
13#include <pthread.h>
14
15void go_callback();
16
17static void *thr(void *arg) {
18    go_callback();
19    return 0;
20}
21
22static void foo() {
23    pthread_t th;
24    pthread_attr_t attr;
25    pthread_attr_init(&attr);
26    // For gccgo use a stack size large enough for all the callbacks,
27    // in case we are on a platform that does not support -fsplit-stack.
28    pthread_attr_setstacksize(&attr, 512 * 10000);
29    pthread_create(&th, &attr, thr, 0);
30    pthread_join(th, 0);
31}
32*/
33import "C"
34
35import (
36	"fmt"
37	"os"
38	"runtime"
39)
40
41func init() {
42	register("CgoCallbackGC", CgoCallbackGC)
43}
44
45//export go_callback
46func go_callback() {
47	runtime.GC()
48	grow()
49	runtime.GC()
50}
51
52var cnt int
53
54func grow() {
55	x := 10000
56	sum := 0
57	if grow1(&x, &sum) == 0 {
58		panic("bad")
59	}
60}
61
62func grow1(x, sum *int) int {
63	if *x == 0 {
64		return *sum + 1
65	}
66	*x--
67	sum1 := *sum + *x
68	return grow1(x, &sum1)
69}
70
71func CgoCallbackGC() {
72	P := 100
73	if os.Getenv("RUNTIME_TESTING_SHORT") != "" {
74		P = 10
75	}
76	done := make(chan bool)
77	// allocate a bunch of stack frames and spray them with pointers
78	for i := 0; i < P; i++ {
79		go func() {
80			grow()
81			done <- true
82		}()
83	}
84	for i := 0; i < P; i++ {
85		<-done
86	}
87	// now give these stack frames to cgo callbacks
88	for i := 0; i < P; i++ {
89		go func() {
90			C.foo()
91			done <- true
92		}()
93	}
94	for i := 0; i < P; i++ {
95		<-done
96	}
97	fmt.Printf("OK\n")
98}
99