1// Copyright 2023 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// Tests stack symbolization.
6
7//go:build ignore
8
9package main
10
11import (
12	"log"
13	"net"
14	"os"
15	"runtime"
16	"runtime/trace"
17	"sync"
18	"time"
19)
20
21func main() {
22	if err := trace.Start(os.Stdout); err != nil {
23		log.Fatalf("failed to start tracing: %v", err)
24	}
25	defer trace.Stop() // in case of early return
26
27	// Now we will do a bunch of things for which we verify stacks later.
28	// It is impossible to ensure that a goroutine has actually blocked
29	// on a channel, in a select or otherwise. So we kick off goroutines
30	// that need to block first in the hope that while we are executing
31	// the rest of the test, they will block.
32	go func() { // func1
33		select {}
34	}()
35	go func() { // func2
36		var c chan int
37		c <- 0
38	}()
39	go func() { // func3
40		var c chan int
41		<-c
42	}()
43	done1 := make(chan bool)
44	go func() { // func4
45		<-done1
46	}()
47	done2 := make(chan bool)
48	go func() { // func5
49		done2 <- true
50	}()
51	c1 := make(chan int)
52	c2 := make(chan int)
53	go func() { // func6
54		select {
55		case <-c1:
56		case <-c2:
57		}
58	}()
59	var mu sync.Mutex
60	mu.Lock()
61	go func() { // func7
62		mu.Lock()
63		mu.Unlock()
64	}()
65	var wg sync.WaitGroup
66	wg.Add(1)
67	go func() { // func8
68		wg.Wait()
69	}()
70	cv := sync.NewCond(&sync.Mutex{})
71	go func() { // func9
72		cv.L.Lock()
73		cv.Wait()
74		cv.L.Unlock()
75	}()
76	ln, err := net.Listen("tcp", "127.0.0.1:0")
77	if err != nil {
78		log.Fatalf("failed to listen: %v", err)
79	}
80	go func() { // func10
81		c, err := ln.Accept()
82		if err != nil {
83			log.Printf("failed to accept: %v", err)
84			return
85		}
86		c.Close()
87	}()
88	rp, wp, err := os.Pipe()
89	if err != nil {
90		log.Fatalf("failed to create a pipe: %v", err)
91	}
92	defer rp.Close()
93	defer wp.Close()
94	pipeReadDone := make(chan bool)
95	go func() { // func11
96		var data [1]byte
97		rp.Read(data[:])
98		pipeReadDone <- true
99	}()
100
101	time.Sleep(100 * time.Millisecond)
102	runtime.GC()
103	runtime.Gosched()
104	time.Sleep(100 * time.Millisecond) // the last chance for the goroutines above to block
105	done1 <- true
106	<-done2
107	select {
108	case c1 <- 0:
109	case c2 <- 0:
110	}
111	mu.Unlock()
112	wg.Done()
113	cv.Signal()
114	c, err := net.Dial("tcp", ln.Addr().String())
115	if err != nil {
116		log.Fatalf("failed to dial: %v", err)
117	}
118	c.Close()
119	var data [1]byte
120	wp.Write(data[:])
121	<-pipeReadDone
122
123	oldGoMaxProcs := runtime.GOMAXPROCS(0)
124	runtime.GOMAXPROCS(oldGoMaxProcs + 1)
125
126	trace.Stop()
127
128	runtime.GOMAXPROCS(oldGoMaxProcs)
129}
130