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#include <pthread.h>
11
12void go_callback();
13
14static void *thr(void *arg) {
15    go_callback();
16    return 0;
17}
18
19static void foo() {
20    pthread_t th;
21    pthread_attr_t attr;
22    pthread_attr_init(&attr);
23    pthread_attr_setstacksize(&attr, 256 << 10);
24    pthread_create(&th, &attr, thr, 0);
25    pthread_join(th, 0);
26}
27*/
28import "C"
29
30import (
31	"fmt"
32	"runtime"
33)
34
35func init() {
36	register("CgoCallbackGC", CgoCallbackGC)
37}
38
39//export go_callback
40func go_callback() {
41	runtime.GC()
42	grow()
43	runtime.GC()
44}
45
46var cnt int
47
48func grow() {
49	x := 10000
50	sum := 0
51	if grow1(&x, &sum) == 0 {
52		panic("bad")
53	}
54}
55
56func grow1(x, sum *int) int {
57	if *x == 0 {
58		return *sum + 1
59	}
60	*x--
61	sum1 := *sum + *x
62	return grow1(x, &sum1)
63}
64
65func CgoCallbackGC() {
66	const P = 100
67	done := make(chan bool)
68	// allocate a bunch of stack frames and spray them with pointers
69	for i := 0; i < P; i++ {
70		go func() {
71			grow()
72			done <- true
73		}()
74	}
75	for i := 0; i < P; i++ {
76		<-done
77	}
78	// now give these stack frames to cgo callbacks
79	for i := 0; i < P; i++ {
80		go func() {
81			C.foo()
82			done <- true
83		}()
84	}
85	for i := 0; i < P; i++ {
86		<-done
87	}
88	fmt.Printf("OK\n")
89}
90