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 goroutine sitting blocked in a syscall for
6// an entire generation. This is a regression test for
7// #65196.
8
9//go:build ignore
10
11package main
12
13import (
14	"log"
15	"os"
16	"runtime/trace"
17	"syscall"
18	"time"
19)
20
21func main() {
22	// Create a pipe to block on.
23	var p [2]int
24	if err := syscall.Pipe(p[:]); err != nil {
25		log.Fatalf("failed to create pipe: %v", err)
26	}
27	rfd, wfd := p[0], p[1]
28
29	// Create a goroutine that blocks on the pipe.
30	done := make(chan struct{})
31	go func() {
32		var data [1]byte
33		_, err := syscall.Read(rfd, data[:])
34		if err != nil {
35			log.Fatalf("failed to read from pipe: %v", err)
36		}
37		done <- struct{}{}
38	}()
39
40	// Give the goroutine ample chance to block on the pipe.
41	time.Sleep(10 * time.Millisecond)
42
43	// Start tracing.
44	if err := trace.Start(os.Stdout); err != nil {
45		log.Fatalf("failed to start tracing: %v", err)
46	}
47
48	// This isn't enough to have a full generation pass by default,
49	// but it is generally enough in stress mode.
50	time.Sleep(100 * time.Millisecond)
51
52	// Write to the pipe to unblock it.
53	if _, err := syscall.Write(wfd, []byte{10}); err != nil {
54		log.Fatalf("failed to write to pipe: %v", err)
55	}
56
57	// Wait for the goroutine to unblock and start running.
58	// This is helpful to catch incorrect information written
59	// down for the syscall-blocked goroutine, since it'll start
60	// executing, and that execution information will be
61	// inconsistent.
62	<-done
63
64	// Stop tracing.
65	trace.Stop()
66}
67