package main

/*
void call() {}
*/
import "C"

import (
	"fmt"
	"runtime"
	"sync"
	"sync/atomic"
	"time"
)

func init() {
	// Excuse the process's main thread from executing the test code
	runtime.LockOSThread()
}

func main() {
	var ourCount int64
	step1 := func() {
		// Force to run on a new thread
		runtime.LockOSThread()
		C.call()
		atomic.AddInt64(&ourCount, 1)
	}
	step2 := func() {
		// Trigger thread to mexit, due to unbalanced {Lock,Unlock}OSThread calls
		runtime.Goexit()
	}

	var (
		begin   = make(chan struct{})
		first   sync.WaitGroup
		proceed = make(chan struct{})
		final   sync.WaitGroup
	)
	for i := 0; i < 100; i++ {
		first.Add(1)
		final.Add(1)
		go func() {
			defer final.Done()
			<-begin
			step1()
			first.Done()
			<-proceed
			step2()
		}()
	}

	cgoStart := runtime.NumCgoCall()
	ourStart := atomic.LoadInt64(&ourCount)
	close(begin)
	first.Wait()
	cgoMiddle := runtime.NumCgoCall()
	ourMiddle := atomic.LoadInt64(&ourCount)
	close(proceed)
	final.Wait()
	time.Sleep(10 * time.Millisecond)
	cgoEnd := runtime.NumCgoCall()
	ourEnd := atomic.LoadInt64(&ourCount)

	fmt.Printf("our count of calls %d %d %d\n", ourStart, ourMiddle, ourEnd)
	fmt.Printf("runtime.NumCgoCall %d %d %d\n", cgoStart, cgoMiddle, cgoEnd)
}
