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 a many interesting cases (network, syscalls, a little GC, busy goroutines,
6// blocked goroutines, LockOSThread, pipes, and GOMAXPROCS).
7
8//go:build ignore
9
10package main
11
12import (
13	"bytes"
14	"io"
15	"log"
16	"net"
17	"os"
18	"runtime"
19	"runtime/trace"
20	"sync"
21	"time"
22)
23
24func main() {
25	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(8))
26	outerDone := make(chan bool)
27
28	go func() {
29		defer func() {
30			outerDone <- true
31		}()
32
33		var wg sync.WaitGroup
34		done := make(chan bool)
35
36		wg.Add(1)
37		go func() {
38			<-done
39			wg.Done()
40		}()
41
42		rp, wp, err := os.Pipe()
43		if err != nil {
44			log.Fatalf("failed to create pipe: %v", err)
45			return
46		}
47		defer func() {
48			rp.Close()
49			wp.Close()
50		}()
51		wg.Add(1)
52		go func() {
53			var tmp [1]byte
54			rp.Read(tmp[:])
55			<-done
56			wg.Done()
57		}()
58		time.Sleep(time.Millisecond)
59
60		go func() {
61			runtime.LockOSThread()
62			for {
63				select {
64				case <-done:
65					return
66				default:
67					runtime.Gosched()
68				}
69			}
70		}()
71
72		runtime.GC()
73		// Trigger GC from malloc.
74		n := 512
75		for i := 0; i < n; i++ {
76			_ = make([]byte, 1<<20)
77		}
78
79		// Create a bunch of busy goroutines to load all Ps.
80		for p := 0; p < 10; p++ {
81			wg.Add(1)
82			go func() {
83				// Do something useful.
84				tmp := make([]byte, 1<<16)
85				for i := range tmp {
86					tmp[i]++
87				}
88				_ = tmp
89				<-done
90				wg.Done()
91			}()
92		}
93
94		// Block in syscall.
95		wg.Add(1)
96		go func() {
97			var tmp [1]byte
98			rp.Read(tmp[:])
99			<-done
100			wg.Done()
101		}()
102
103		runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
104
105		// Test timers.
106		timerDone := make(chan bool)
107		go func() {
108			time.Sleep(time.Millisecond)
109			timerDone <- true
110		}()
111		<-timerDone
112
113		// A bit of network.
114		ln, err := net.Listen("tcp", "127.0.0.1:0")
115		if err != nil {
116			log.Fatalf("listen failed: %v", err)
117			return
118		}
119		defer ln.Close()
120		go func() {
121			c, err := ln.Accept()
122			if err != nil {
123				return
124			}
125			time.Sleep(time.Millisecond)
126			var buf [1]byte
127			c.Write(buf[:])
128			c.Close()
129		}()
130		c, err := net.Dial("tcp", ln.Addr().String())
131		if err != nil {
132			log.Fatalf("dial failed: %v", err)
133			return
134		}
135		var tmp [1]byte
136		c.Read(tmp[:])
137		c.Close()
138
139		go func() {
140			runtime.Gosched()
141			select {}
142		}()
143
144		// Unblock helper goroutines and wait them to finish.
145		wp.Write(tmp[:])
146		wp.Write(tmp[:])
147		close(done)
148		wg.Wait()
149	}()
150
151	const iters = 5
152	for i := 0; i < iters; i++ {
153		var w io.Writer
154		if i == iters-1 {
155			w = os.Stdout
156		} else {
157			w = new(bytes.Buffer)
158		}
159		if err := trace.Start(w); err != nil {
160			log.Fatalf("failed to start tracing: %v", err)
161		}
162		time.Sleep(time.Millisecond)
163		trace.Stop()
164	}
165	<-outerDone
166}
167