1// Copyright 2013 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// Only works on systems with syscall.Close.
6// We need a fast system call to provoke the race,
7// and Close(-1) is nearly universally fast.
8
9// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd plan9
10
11package runtime_test
12
13import (
14	"runtime"
15	"sync"
16	"sync/atomic"
17	"syscall"
18	"testing"
19)
20
21func TestGoroutineProfile(t *testing.T) {
22	// GoroutineProfile used to use the wrong starting sp for
23	// goroutines coming out of system calls, causing possible
24	// crashes.
25	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(100))
26
27	var stop uint32
28	defer atomic.StoreUint32(&stop, 1) // in case of panic
29
30	var wg sync.WaitGroup
31	for i := 0; i < 4; i++ {
32		wg.Add(1)
33		go func() {
34			for atomic.LoadUint32(&stop) == 0 {
35				syscall.Close(-1)
36			}
37			wg.Done()
38		}()
39	}
40
41	max := 10000
42	if testing.Short() {
43		max = 100
44	}
45	stk := make([]runtime.StackRecord, 128)
46	for n := 0; n < max; n++ {
47		_, ok := runtime.GoroutineProfile(stk)
48		if !ok {
49			t.Fatalf("GoroutineProfile failed")
50		}
51	}
52
53	// If the program didn't crash, we passed.
54	atomic.StoreUint32(&stop, 1)
55	wg.Wait()
56}
57