mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
98 lines
2.3 KiB
Go
98 lines
2.3 KiB
Go
|
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||
|
|
// Use of this source code is governed by a BSD-style
|
||
|
|
// license that can be found in the LICENSE file.
|
||
|
|
|
||
|
|
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
|
||
|
|
|
||
|
|
package main
|
||
|
|
|
||
|
|
import (
|
||
|
|
"bytes"
|
||
|
|
"internal/trace"
|
||
|
|
"runtime"
|
||
|
|
rtrace "runtime/trace"
|
||
|
|
"sync"
|
||
|
|
"syscall"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
// TestGoroutineInSyscall tests threads for timer goroutines
|
||
|
|
// that preexisted when the tracing started were not counted
|
||
|
|
// as threads in syscall. See golang.org/issues/22574.
|
||
|
|
func TestGoroutineInSyscall(t *testing.T) {
|
||
|
|
// Start one goroutine blocked in syscall.
|
||
|
|
//
|
||
|
|
// TODO: syscall.Pipe used to cause the goroutine to
|
||
|
|
// remain blocked in syscall is not portable. Replace
|
||
|
|
// it with a more portable way so this test can run
|
||
|
|
// on non-unix architecture e.g. Windows.
|
||
|
|
var p [2]int
|
||
|
|
if err := syscall.Pipe(p[:]); err != nil {
|
||
|
|
t.Fatalf("failed to create pipe: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
var wg sync.WaitGroup
|
||
|
|
defer func() {
|
||
|
|
syscall.Write(p[1], []byte("a"))
|
||
|
|
wg.Wait()
|
||
|
|
|
||
|
|
syscall.Close(p[0])
|
||
|
|
syscall.Close(p[1])
|
||
|
|
}()
|
||
|
|
wg.Add(1)
|
||
|
|
go func() {
|
||
|
|
var tmp [1]byte
|
||
|
|
syscall.Read(p[0], tmp[:])
|
||
|
|
wg.Done()
|
||
|
|
}()
|
||
|
|
|
||
|
|
// Start multiple timer goroutines.
|
||
|
|
allTimers := make([]*time.Timer, 2*runtime.GOMAXPROCS(0))
|
||
|
|
defer func() {
|
||
|
|
for _, timer := range allTimers {
|
||
|
|
timer.Stop()
|
||
|
|
}
|
||
|
|
}()
|
||
|
|
|
||
|
|
var timerSetup sync.WaitGroup
|
||
|
|
for i := range allTimers {
|
||
|
|
timerSetup.Add(1)
|
||
|
|
go func(i int) {
|
||
|
|
defer timerSetup.Done()
|
||
|
|
allTimers[i] = time.AfterFunc(time.Hour, nil)
|
||
|
|
}(i)
|
||
|
|
}
|
||
|
|
timerSetup.Wait()
|
||
|
|
|
||
|
|
// Collect and parse trace.
|
||
|
|
buf := new(bytes.Buffer)
|
||
|
|
if err := rtrace.Start(buf); err != nil {
|
||
|
|
t.Fatalf("failed to start tracing: %v", err)
|
||
|
|
}
|
||
|
|
rtrace.Stop()
|
||
|
|
|
||
|
|
res, err := trace.Parse(buf, "")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("failed to parse trace: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check only one thread for the pipe read goroutine is
|
||
|
|
// considered in-syscall.
|
||
|
|
viewerData, err := generateTrace(&traceParams{
|
||
|
|
parsed: res,
|
||
|
|
endTime: int64(1<<63 - 1),
|
||
|
|
})
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("failed to generate ViewerData: %v", err)
|
||
|
|
}
|
||
|
|
for _, ev := range viewerData.Events {
|
||
|
|
if ev.Name == "Threads" {
|
||
|
|
arg := ev.Arg.(*threadCountersArg)
|
||
|
|
if arg.InSyscall > 1 {
|
||
|
|
t.Errorf("%d threads in syscall at time %v; want less than 1 thread in syscall", arg.InSyscall, ev.Time)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|