aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Pan <panjf2000@gmail.com>2021-09-15 12:37:20 +0800
committerIan Lance Taylor <iant@golang.org>2021-09-17 19:32:44 +0000
commit74e384f50d3071c97effa3afd43ec29111587d59 (patch)
treed6785f0d9e9253850131b81e006b09d6d1998914
parent323c6f74d35ec29baac2a1aba4270f89b022815a (diff)
downloadgo-74e384f50d3071c97effa3afd43ec29111587d59.tar.gz
go-74e384f50d3071c97effa3afd43ec29111587d59.zip
internal/poll: inject a hook into the runtime finalizer to count the closed pipes
Fixes #48066 Change-Id: Icd6974dfcc496c054bb096e5d70de6e135984517 Reviewed-on: https://go-review.googlesource.com/c/go/+/349774 Reviewed-by: Bryan C. Mills <bcmills@google.com> Reviewed-by: Ian Lance Taylor <iant@golang.org> Trust: Bryan C. Mills <bcmills@google.com> Run-TryBot: Bryan C. Mills <bcmills@google.com> TryBot-Result: Go Bot <gobot@golang.org>
-rw-r--r--src/internal/poll/splice_linux_test.go60
1 files changed, 35 insertions, 25 deletions
diff --git a/src/internal/poll/splice_linux_test.go b/src/internal/poll/splice_linux_test.go
index deac5c3759..8c4363886e 100644
--- a/src/internal/poll/splice_linux_test.go
+++ b/src/internal/poll/splice_linux_test.go
@@ -6,40 +6,48 @@ package poll_test
import (
"internal/poll"
- "internal/syscall/unix"
"runtime"
- "syscall"
+ "sync"
+ "sync/atomic"
"testing"
"time"
)
-// checkPipes returns true if all pipes are closed properly, false otherwise.
-func checkPipes(fds []int) bool {
- for _, fd := range fds {
- // Check if each pipe fd has been closed.
- _, _, errno := syscall.Syscall(unix.FcntlSyscall, uintptr(fd), syscall.F_GETPIPE_SZ, 0)
- if errno == 0 {
- return false
+var closeHook atomic.Value // func(fd int)
+
+func init() {
+ closeFunc := poll.CloseFunc
+ poll.CloseFunc = func(fd int) (err error) {
+ if v := closeHook.Load(); v != nil {
+ if hook := v.(func(int)); hook != nil {
+ hook(fd)
+ }
}
+ return closeFunc(fd)
}
- return true
}
func TestSplicePipePool(t *testing.T) {
const N = 64
var (
- p *poll.SplicePipe
- ps []*poll.SplicePipe
- fds []int
- err error
+ p *poll.SplicePipe
+ ps []*poll.SplicePipe
+ allFDs []int
+ pendingFDs sync.Map // fd → struct{}{}
+ err error
)
+
+ closeHook.Store(func(fd int) { pendingFDs.Delete(fd) })
+ t.Cleanup(func() { closeHook.Store((func(int))(nil)) })
+
for i := 0; i < N; i++ {
p, _, err = poll.GetPipe()
if err != nil {
- t.Skip("failed to create pipe, skip this test")
+ t.Skipf("failed to create pipe due to error(%v), skip this test", err)
}
_, pwfd := poll.GetPipeFds(p)
- fds = append(fds, pwfd)
+ allFDs = append(allFDs, pwfd)
+ pendingFDs.Store(pwfd, struct{}{})
ps = append(ps, p)
}
for _, p = range ps {
@@ -62,19 +70,21 @@ func TestSplicePipePool(t *testing.T) {
for {
runtime.GC()
time.Sleep(10 * time.Millisecond)
- if checkPipes(fds) {
+
+ // Detect whether all pipes are closed properly.
+ var leakedFDs []int
+ pendingFDs.Range(func(k, v interface{}) bool {
+ leakedFDs = append(leakedFDs, k.(int))
+ return true
+ })
+ if len(leakedFDs) == 0 {
break
}
+
select {
case <-expiredTime.C:
- t.Logf("descriptors to check: %v", fds)
- for _, fd := range fds {
- _, _, errno := syscall.Syscall(unix.FcntlSyscall, uintptr(fd), syscall.F_GETPIPE_SZ, 0)
- if errno == 0 {
- t.Errorf("descriptor %d still open", fd)
- }
- }
- t.Fatal("at least one pipe is still open")
+ t.Logf("all descriptors: %v", allFDs)
+ t.Fatalf("leaked descriptors: %v", leakedFDs)
default:
}
}