diff options
Diffstat (limited to 'src/internal')
-rw-r--r-- | src/internal/abi/abi.go | 28 | ||||
-rw-r--r-- | src/internal/buildcfg/cfg.go | 16 | ||||
-rw-r--r-- | src/internal/buildcfg/cfg_test.go | 25 | ||||
-rw-r--r-- | src/internal/cfg/cfg.go | 1 | ||||
-rw-r--r-- | src/internal/poll/splice_linux_test.go | 53 |
5 files changed, 85 insertions, 38 deletions
diff --git a/src/internal/abi/abi.go b/src/internal/abi/abi.go index eadff248d9..46dc593bd7 100644 --- a/src/internal/abi/abi.go +++ b/src/internal/abi/abi.go @@ -19,6 +19,14 @@ import ( // when it may not be safe to keep them only in the integer // register space otherwise. type RegArgs struct { + // Values in these slots should be precisely the bit-by-bit + // representation of how they would appear in a register. + // + // This means that on big endian arches, integer values should + // be in the top bits of the slot. Floats are usually just + // directly represented, but some architectures treat narrow + // width floating point values specially (e.g. they're promoted + // first, or they need to be NaN-boxed). Ints [IntArgRegs]uintptr // untyped integer registers Floats [FloatArgRegs]uint64 // untyped float registers @@ -56,26 +64,6 @@ func (r *RegArgs) IntRegArgAddr(reg int, argSize uintptr) unsafe.Pointer { return unsafe.Pointer(uintptr(unsafe.Pointer(&r.Ints[reg])) + offset) } -// FloatRegArgAddr returns a pointer inside of r.Floats[reg] that is appropriately -// offset for an argument of size argSize. -// -// argSize must be non-zero, fit in a register, and a power-of-two. -// -// This method is a helper for dealing with the endianness of different CPU -// architectures, since sub-word-sized arguments in big endian architectures -// need to be "aligned" to the upper edge of the register to be interpreted -// by the CPU correctly. -func (r *RegArgs) FloatRegArgAddr(reg int, argSize uintptr) unsafe.Pointer { - if argSize > EffectiveFloatRegSize || argSize == 0 || argSize&(argSize-1) != 0 { - panic("invalid argSize") - } - offset := uintptr(0) - if goarch.BigEndian { - offset = EffectiveFloatRegSize - argSize - } - return unsafe.Pointer(uintptr(unsafe.Pointer(&r.Floats[reg])) + offset) -} - // IntArgRegBitmap is a bitmap large enough to hold one bit per // integer argument/return register. type IntArgRegBitmap [(IntArgRegs + 7) / 8]uint8 diff --git a/src/internal/buildcfg/cfg.go b/src/internal/buildcfg/cfg.go index 9fe7f211fb..68c10a2824 100644 --- a/src/internal/buildcfg/cfg.go +++ b/src/internal/buildcfg/cfg.go @@ -25,6 +25,7 @@ var ( GOARCH = envOr("GOARCH", defaultGOARCH) GOOS = envOr("GOOS", defaultGOOS) GO386 = envOr("GO386", defaultGO386) + GOAMD64 = goamd64() GOARM = goarm() GOMIPS = gomips() GOMIPS64 = gomips64() @@ -52,6 +53,21 @@ func envOr(key, value string) string { return value } +func goamd64() int { + switch v := envOr("GOAMD64", defaultGOAMD64); v { + case "v1": + return 1 + case "v2": + return 2 + case "v3": + return 3 + case "v4": + return 4 + } + Error = fmt.Errorf("invalid GOAMD64: must be v1, v2, v3, v4") + return int(defaultGOAMD64[len("v")] - '0') +} + func goarm() int { def := defaultGOARM if GOOS == "android" && GOARCH == "arm" { diff --git a/src/internal/buildcfg/cfg_test.go b/src/internal/buildcfg/cfg_test.go new file mode 100644 index 0000000000..9180441c28 --- /dev/null +++ b/src/internal/buildcfg/cfg_test.go @@ -0,0 +1,25 @@ +// Copyright 2021 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. + +package buildcfg + +import ( + "os" + "testing" +) + +func TestConfigFlags(t *testing.T) { + os.Setenv("GOAMD64", "v1") + if goamd64() != 1 { + t.Errorf("Wrong parsing of GOAMD64=v1") + } + os.Setenv("GOAMD64", "v4") + if goamd64() != 4 { + t.Errorf("Wrong parsing of GOAMD64=v4") + } + os.Setenv("GOAMD64", "1") + if goamd64() != 1 { + t.Errorf("Wrong parsing of GOAMD64=1") + } +} diff --git a/src/internal/cfg/cfg.go b/src/internal/cfg/cfg.go index 815994b679..4cb3fbd4f3 100644 --- a/src/internal/cfg/cfg.go +++ b/src/internal/cfg/cfg.go @@ -33,6 +33,7 @@ const KnownEnv = ` GCCGO GO111MODULE GO386 + GOAMD64 GOARCH GOARM GOBIN diff --git a/src/internal/poll/splice_linux_test.go b/src/internal/poll/splice_linux_test.go index 280468c7e7..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,12 +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.Fatal("at least one pipe is still open") + t.Logf("all descriptors: %v", allFDs) + t.Fatalf("leaked descriptors: %v", leakedFDs) default: } } |