2016-04-10 14:32:26 -07:00
|
|
|
// Copyright 2016 The Go Authors. All rights reserved.
|
2016-03-22 18:17:43 -07:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
2023-05-12 15:19:23 -04:00
|
|
|
// This test uses various syscall.SIG* constants that are defined on Unix
|
|
|
|
|
// platforms and Windows.
|
|
|
|
|
|
|
|
|
|
//go:build unix || windows
|
|
|
|
|
|
2016-03-22 18:17:43 -07:00
|
|
|
package carchive_test
|
|
|
|
|
|
|
|
|
|
import (
|
2016-03-22 22:11:42 -05:00
|
|
|
"bufio"
|
2017-10-11 16:02:59 -04:00
|
|
|
"bytes"
|
2023-05-22 10:32:31 -04:00
|
|
|
"cmd/cgo/internal/cgotest"
|
2016-06-16 12:59:09 -07:00
|
|
|
"debug/elf"
|
2019-05-15 14:31:48 -04:00
|
|
|
"flag"
|
2016-03-22 18:17:43 -07:00
|
|
|
"fmt"
|
cmd/dist: drop host test support
Host tests are used for emulated builders that use cross-compilation.
Today, this is the android-{386,amd64}-emu builders and all wasm
builders. These builders run all.bash on a linux/amd64 host to build
all packages and most tests for the emulated guest, and then run the
resulting test binaries inside the emulated guest. A small number of
test packages are “host tests”: these run on the host rather than the
guest because they invoke the Go toolchain themselves (which only
lives on the host) and run the resulting binaries in the guest.
However, this host test mechanism is barely used today, despite being
quite complex. This complexity is also causing significant friction to
implementing structured all.bash output.
As of this CL, the whole host test mechanism runs a total of 10 test
cases on a total of two builders (android-{386,amd64}-emu). There are
clearly several tests that are incorrectly being skipped, so we could
expand it to cover more test cases, but it would still apply to only
two builders. Furthermore, the two other Android builders
(android-{arm,arm64}-corellium) build the Go toolchain directly inside
Android and also have access to a C toolchain, so they are able to get
significantly better test coverage without the use of host tests. This
suggests that the android-*-emu builders could do the same. All of
these tests are cgo-related, so they don't run on the wasm hosts
anyway.
Given the incredibly low value of host tests today, they are not worth
their implementation complexity and the friction they cause. Hence,
this CL drops support for host tests. (This was also the last use of
rtSequential, so we drop support for sequential tests, too.)
Fixes #59999.
Change-Id: I3eaca853a8907abc8247709f15a0d19a872dd22d
Reviewed-on: https://go-review.googlesource.com/c/go/+/492986
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2023-05-05 13:52:31 -04:00
|
|
|
"internal/testenv"
|
2021-12-21 10:00:23 -08:00
|
|
|
"io"
|
2019-02-21 12:34:27 -05:00
|
|
|
"log"
|
2016-03-22 18:17:43 -07:00
|
|
|
"os"
|
|
|
|
|
"os/exec"
|
|
|
|
|
"path/filepath"
|
2018-04-19 12:56:29 -07:00
|
|
|
"regexp"
|
2017-02-24 15:46:40 -08:00
|
|
|
"runtime"
|
2021-12-21 10:00:23 -08:00
|
|
|
"strconv"
|
2016-03-22 18:17:43 -07:00
|
|
|
"strings"
|
2022-08-19 14:43:47 -07:00
|
|
|
"sync"
|
2016-03-22 22:11:42 -05:00
|
|
|
"syscall"
|
2016-03-22 18:17:43 -07:00
|
|
|
"testing"
|
2016-03-25 15:57:25 -07:00
|
|
|
"time"
|
2016-03-22 18:17:43 -07:00
|
|
|
"unicode"
|
|
|
|
|
)
|
|
|
|
|
|
runtime: update and restore g0 stack bounds at cgocallback
Currently, at a cgo callback where there is already a Go frame on
the stack (i.e. C->Go->C->Go), we require that at the inner Go
callback the SP is within the g0's stack bounds set by a previous
callback. This is to prevent that the C code switches stack while
having a Go frame on the stack, which we don't really support. But
this could also happen when we cannot get accurate stack bounds,
e.g. when pthread_getattr_np is not available. Since the stack
bounds are just estimates based on the current SP, if there are
multiple C->Go callbacks with various stack depth, it is possible
that the SP of a later callback falls out of a previous call's
estimate. This leads to runtime throw in a seemingly reasonable
program.
This CL changes it to save the old g0 stack bounds at cgocallback,
update the bounds, and restore the old bounds at return. So each
callback will get its own stack bounds based on the current SP,
and when it returns, the outer callback has the its old stack
bounds restored.
Also, at a cgo callback when there is no Go frame on the stack,
we currently always get new stack bounds. We do this because if
we can only get estimated bounds based on the SP, and the stack
depth varies a lot between two C->Go calls, the previous
estimates may be off and we fall out or nearly fall out of the
previous bounds. But this causes a performance problem: the
pthread API to get accurate stack bounds (pthread_getattr_np) is
very slow when called on the main thread. Getting the stack bounds
every time significantly slows down repeated C->Go calls on the
main thread.
This CL fixes it by "caching" the stack bounds if they are
accurate. I.e. at the second time Go calls into C, if the previous
stack bounds are accurate, and the current SP is in bounds, we can
be sure it is the same stack and we don't need to update the bounds.
This avoids the repeated calls to pthread_getattr_np. If we cannot
get the accurate bounds, we continue to update the stack bounds
based on the SP, and that operation is very cheap.
On a Linux/AMD64 machine with glibc:
name old time/op new time/op delta
CgoCallbackMainThread-8 96.4µs ± 3% 0.1µs ± 2% -99.92% (p=0.000 n=10+9)
Fixes #68285.
Fixes #68587.
Change-Id: I3422badd5ad8ff63e1a733152d05fb7a44d5d435
Reviewed-on: https://go-review.googlesource.com/c/go/+/600296
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
2024-07-22 16:23:43 -04:00
|
|
|
var globalSkip = func(t testing.TB) {}
|
2023-05-22 15:19:49 -04:00
|
|
|
|
2016-03-22 18:17:43 -07:00
|
|
|
// Program to run.
|
|
|
|
|
var bin []string
|
|
|
|
|
|
2016-03-24 21:47:02 +01:00
|
|
|
// C compiler with args (from $(go env CC) $(go env GOGCCFLAGS)).
|
2016-03-22 18:17:43 -07:00
|
|
|
var cc []string
|
|
|
|
|
|
|
|
|
|
// ".exe" on Windows.
|
|
|
|
|
var exeSuffix string
|
|
|
|
|
|
2019-02-21 12:34:27 -05:00
|
|
|
var GOOS, GOARCH, GOPATH string
|
2016-04-27 18:03:49 -04:00
|
|
|
var libgodir string
|
2016-03-24 21:47:02 +01:00
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
var testWork bool // If true, preserve temporary directories.
|
|
|
|
|
|
2019-02-21 12:34:27 -05:00
|
|
|
func TestMain(m *testing.M) {
|
2019-11-20 10:19:43 -05:00
|
|
|
flag.BoolVar(&testWork, "testwork", false, "if true, log and preserve the test's temporary working directory")
|
2019-05-15 14:31:48 -04:00
|
|
|
flag.Parse()
|
2023-05-22 15:19:49 -04:00
|
|
|
|
|
|
|
|
log.SetFlags(log.Lshortfile)
|
|
|
|
|
os.Exit(testMain(m))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testMain(m *testing.M) int {
|
2025-09-11 23:48:04 +00:00
|
|
|
if testing.Short() && testenv.Builder() == "" {
|
runtime: update and restore g0 stack bounds at cgocallback
Currently, at a cgo callback where there is already a Go frame on
the stack (i.e. C->Go->C->Go), we require that at the inner Go
callback the SP is within the g0's stack bounds set by a previous
callback. This is to prevent that the C code switches stack while
having a Go frame on the stack, which we don't really support. But
this could also happen when we cannot get accurate stack bounds,
e.g. when pthread_getattr_np is not available. Since the stack
bounds are just estimates based on the current SP, if there are
multiple C->Go callbacks with various stack depth, it is possible
that the SP of a later callback falls out of a previous call's
estimate. This leads to runtime throw in a seemingly reasonable
program.
This CL changes it to save the old g0 stack bounds at cgocallback,
update the bounds, and restore the old bounds at return. So each
callback will get its own stack bounds based on the current SP,
and when it returns, the outer callback has the its old stack
bounds restored.
Also, at a cgo callback when there is no Go frame on the stack,
we currently always get new stack bounds. We do this because if
we can only get estimated bounds based on the SP, and the stack
depth varies a lot between two C->Go calls, the previous
estimates may be off and we fall out or nearly fall out of the
previous bounds. But this causes a performance problem: the
pthread API to get accurate stack bounds (pthread_getattr_np) is
very slow when called on the main thread. Getting the stack bounds
every time significantly slows down repeated C->Go calls on the
main thread.
This CL fixes it by "caching" the stack bounds if they are
accurate. I.e. at the second time Go calls into C, if the previous
stack bounds are accurate, and the current SP is in bounds, we can
be sure it is the same stack and we don't need to update the bounds.
This avoids the repeated calls to pthread_getattr_np. If we cannot
get the accurate bounds, we continue to update the stack bounds
based on the SP, and that operation is very cheap.
On a Linux/AMD64 machine with glibc:
name old time/op new time/op delta
CgoCallbackMainThread-8 96.4µs ± 3% 0.1µs ± 2% -99.92% (p=0.000 n=10+9)
Fixes #68285.
Fixes #68587.
Change-Id: I3422badd5ad8ff63e1a733152d05fb7a44d5d435
Reviewed-on: https://go-review.googlesource.com/c/go/+/600296
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
2024-07-22 16:23:43 -04:00
|
|
|
globalSkip = func(t testing.TB) { t.Skip("short mode and $GO_BUILDER_NAME not set") }
|
2023-05-22 15:19:49 -04:00
|
|
|
return m.Run()
|
2019-05-15 14:31:48 -04:00
|
|
|
}
|
2022-07-29 00:32:14 -04:00
|
|
|
if runtime.GOOS == "linux" {
|
|
|
|
|
if _, err := os.Stat("/etc/alpine-release"); err == nil {
|
runtime: update and restore g0 stack bounds at cgocallback
Currently, at a cgo callback where there is already a Go frame on
the stack (i.e. C->Go->C->Go), we require that at the inner Go
callback the SP is within the g0's stack bounds set by a previous
callback. This is to prevent that the C code switches stack while
having a Go frame on the stack, which we don't really support. But
this could also happen when we cannot get accurate stack bounds,
e.g. when pthread_getattr_np is not available. Since the stack
bounds are just estimates based on the current SP, if there are
multiple C->Go callbacks with various stack depth, it is possible
that the SP of a later callback falls out of a previous call's
estimate. This leads to runtime throw in a seemingly reasonable
program.
This CL changes it to save the old g0 stack bounds at cgocallback,
update the bounds, and restore the old bounds at return. So each
callback will get its own stack bounds based on the current SP,
and when it returns, the outer callback has the its old stack
bounds restored.
Also, at a cgo callback when there is no Go frame on the stack,
we currently always get new stack bounds. We do this because if
we can only get estimated bounds based on the SP, and the stack
depth varies a lot between two C->Go calls, the previous
estimates may be off and we fall out or nearly fall out of the
previous bounds. But this causes a performance problem: the
pthread API to get accurate stack bounds (pthread_getattr_np) is
very slow when called on the main thread. Getting the stack bounds
every time significantly slows down repeated C->Go calls on the
main thread.
This CL fixes it by "caching" the stack bounds if they are
accurate. I.e. at the second time Go calls into C, if the previous
stack bounds are accurate, and the current SP is in bounds, we can
be sure it is the same stack and we don't need to update the bounds.
This avoids the repeated calls to pthread_getattr_np. If we cannot
get the accurate bounds, we continue to update the stack bounds
based on the SP, and that operation is very cheap.
On a Linux/AMD64 machine with glibc:
name old time/op new time/op delta
CgoCallbackMainThread-8 96.4µs ± 3% 0.1µs ± 2% -99.92% (p=0.000 n=10+9)
Fixes #68285.
Fixes #68587.
Change-Id: I3422badd5ad8ff63e1a733152d05fb7a44d5d435
Reviewed-on: https://go-review.googlesource.com/c/go/+/600296
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
2024-07-22 16:23:43 -04:00
|
|
|
globalSkip = func(t testing.TB) { t.Skip("skipping failing test on alpine - go.dev/issue/19938") }
|
2023-05-22 15:19:49 -04:00
|
|
|
return m.Run()
|
2022-07-29 00:32:14 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-21 12:34:27 -05:00
|
|
|
// We need a writable GOPATH in which to run the tests.
|
|
|
|
|
// Construct one in a temporary directory.
|
|
|
|
|
var err error
|
2021-04-03 08:10:47 +00:00
|
|
|
GOPATH, err = os.MkdirTemp("", "carchive_test")
|
2019-02-21 12:34:27 -05:00
|
|
|
if err != nil {
|
|
|
|
|
log.Panic(err)
|
|
|
|
|
}
|
2019-11-20 10:19:43 -05:00
|
|
|
if testWork {
|
|
|
|
|
log.Println(GOPATH)
|
|
|
|
|
} else {
|
|
|
|
|
defer os.RemoveAll(GOPATH)
|
|
|
|
|
}
|
2019-02-21 12:34:27 -05:00
|
|
|
os.Setenv("GOPATH", GOPATH)
|
|
|
|
|
|
|
|
|
|
// Copy testdata into GOPATH/src/testarchive, along with a go.mod file
|
|
|
|
|
// declaring the same path.
|
|
|
|
|
modRoot := filepath.Join(GOPATH, "src", "testcarchive")
|
2023-05-22 10:32:31 -04:00
|
|
|
if err := cgotest.OverlayDir(modRoot, "testdata"); err != nil {
|
2019-02-21 12:34:27 -05:00
|
|
|
log.Panic(err)
|
|
|
|
|
}
|
|
|
|
|
if err := os.Chdir(modRoot); err != nil {
|
|
|
|
|
log.Panic(err)
|
|
|
|
|
}
|
2019-02-25 22:09:46 -05:00
|
|
|
os.Setenv("PWD", modRoot)
|
2021-04-03 08:10:47 +00:00
|
|
|
if err := os.WriteFile("go.mod", []byte("module testcarchive\n"), 0666); err != nil {
|
2019-02-21 12:34:27 -05:00
|
|
|
log.Panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-24 21:47:02 +01:00
|
|
|
GOOS = goEnv("GOOS")
|
|
|
|
|
GOARCH = goEnv("GOARCH")
|
2016-10-14 17:03:01 +11:00
|
|
|
bin = cmdToRun("./testp")
|
2016-03-22 18:17:43 -07:00
|
|
|
|
2016-03-24 21:47:02 +01:00
|
|
|
ccOut := goEnv("CC")
|
2025-10-19 19:53:27 +00:00
|
|
|
cc = []string{ccOut}
|
2016-03-22 18:17:43 -07:00
|
|
|
|
2016-03-24 21:47:02 +01:00
|
|
|
out := goEnv("GOGCCFLAGS")
|
2016-03-22 18:17:43 -07:00
|
|
|
quote := '\000'
|
|
|
|
|
start := 0
|
|
|
|
|
lastSpace := true
|
|
|
|
|
backslash := false
|
2025-10-19 19:53:27 +00:00
|
|
|
s := out
|
2016-03-22 18:17:43 -07:00
|
|
|
for i, c := range s {
|
|
|
|
|
if quote == '\000' && unicode.IsSpace(c) {
|
|
|
|
|
if !lastSpace {
|
|
|
|
|
cc = append(cc, s[start:i])
|
|
|
|
|
lastSpace = true
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if lastSpace {
|
|
|
|
|
start = i
|
|
|
|
|
lastSpace = false
|
|
|
|
|
}
|
|
|
|
|
if quote == '\000' && !backslash && (c == '"' || c == '\'') {
|
|
|
|
|
quote = c
|
|
|
|
|
backslash = false
|
|
|
|
|
} else if !backslash && quote == c {
|
|
|
|
|
quote = '\000'
|
|
|
|
|
} else if (quote == '\000' || quote == '"') && !backslash && c == '\\' {
|
|
|
|
|
backslash = true
|
|
|
|
|
} else {
|
|
|
|
|
backslash = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !lastSpace {
|
|
|
|
|
cc = append(cc, s[start:])
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-25 10:34:57 +01:00
|
|
|
if GOOS == "aix" {
|
|
|
|
|
// -Wl,-bnoobjreorder is mandatory to keep the same layout
|
|
|
|
|
// in .text section.
|
|
|
|
|
cc = append(cc, "-Wl,-bnoobjreorder")
|
|
|
|
|
}
|
2023-02-01 12:33:11 -05:00
|
|
|
if GOOS == "ios" {
|
|
|
|
|
// Linking runtime/cgo on ios requires the CoreFoundation framework because
|
|
|
|
|
// x_cgo_init uses CoreFoundation APIs to switch directory to the app root.
|
|
|
|
|
//
|
|
|
|
|
// TODO(#58225): This special case probably should not be needed.
|
|
|
|
|
// runtime/cgo is a very low-level package, and should not provide
|
|
|
|
|
// high-level behaviors like changing the current working directory at init.
|
|
|
|
|
cc = append(cc, "-framework", "CoreFoundation")
|
|
|
|
|
}
|
2019-02-21 12:34:27 -05:00
|
|
|
libbase := GOOS + "_" + GOARCH
|
2017-02-24 15:46:40 -08:00
|
|
|
if runtime.Compiler == "gccgo" {
|
2019-02-21 12:34:27 -05:00
|
|
|
libbase = "gccgo_" + libgodir + "_fPIC"
|
2017-02-24 15:46:40 -08:00
|
|
|
} else {
|
|
|
|
|
switch GOOS {
|
2020-09-16 16:59:58 -04:00
|
|
|
case "darwin", "ios":
|
2020-04-03 12:22:27 -04:00
|
|
|
if GOARCH == "arm64" {
|
2019-02-21 12:34:27 -05:00
|
|
|
libbase += "_shared"
|
2017-02-24 15:46:40 -08:00
|
|
|
}
|
2019-04-29 13:50:49 +00:00
|
|
|
case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris", "illumos":
|
2019-02-21 12:34:27 -05:00
|
|
|
libbase += "_shared"
|
2016-03-22 18:17:43 -07:00
|
|
|
}
|
|
|
|
|
}
|
2019-02-21 12:34:27 -05:00
|
|
|
libgodir = filepath.Join(GOPATH, "pkg", libbase, "testcarchive")
|
|
|
|
|
cc = append(cc, "-I", libgodir)
|
2016-03-22 18:17:43 -07:00
|
|
|
|
2022-02-07 11:33:30 -05:00
|
|
|
// Force reallocation (and avoid aliasing bugs) for parallel tests that append to cc.
|
|
|
|
|
cc = cc[:len(cc):len(cc)]
|
|
|
|
|
|
2016-03-24 21:47:02 +01:00
|
|
|
if GOOS == "windows" {
|
2016-03-22 18:17:43 -07:00
|
|
|
exeSuffix = ".exe"
|
|
|
|
|
}
|
2019-02-21 12:34:27 -05:00
|
|
|
|
|
|
|
|
return m.Run()
|
2016-03-22 18:17:43 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-24 21:47:02 +01:00
|
|
|
func goEnv(key string) string {
|
|
|
|
|
out, err := exec.Command("go", "env", key).Output()
|
|
|
|
|
if err != nil {
|
2017-05-24 14:59:22 -07:00
|
|
|
if ee, ok := err.(*exec.ExitError); ok {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "%s", ee.Stderr)
|
|
|
|
|
}
|
2019-02-21 12:34:27 -05:00
|
|
|
log.Panicf("go env %s failed:\n%s\n", key, err)
|
2016-03-24 21:47:02 +01:00
|
|
|
}
|
|
|
|
|
return strings.TrimSpace(string(out))
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-14 17:03:01 +11:00
|
|
|
func cmdToRun(name string) []string {
|
|
|
|
|
execScript := "go_" + goEnv("GOOS") + "_" + goEnv("GOARCH") + "_exec"
|
|
|
|
|
executor, err := exec.LookPath(execScript)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return []string{name}
|
2016-03-24 17:50:21 -04:00
|
|
|
}
|
2016-10-14 17:03:01 +11:00
|
|
|
return []string{executor, name}
|
2016-03-24 17:50:21 -04:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
// genHeader writes a C header file for the C-exported declarations found in .go
|
|
|
|
|
// source files in dir.
|
|
|
|
|
//
|
|
|
|
|
// TODO(golang.org/issue/35715): This should be simpler.
|
|
|
|
|
func genHeader(t *testing.T, header, dir string) {
|
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
|
|
// The 'cgo' command generates a number of additional artifacts,
|
|
|
|
|
// but we're only interested in the header.
|
|
|
|
|
// Shunt the rest of the outputs to a temporary directory.
|
2021-04-03 08:10:47 +00:00
|
|
|
objDir, err := os.MkdirTemp(GOPATH, "_obj")
|
2019-11-20 10:19:43 -05:00
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
defer os.RemoveAll(objDir)
|
|
|
|
|
|
|
|
|
|
files, err := filepath.Glob(filepath.Join(dir, "*.go"))
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-24 10:21:01 +01:00
|
|
|
cmd := exec.Command(testenv.GoToolPath(t), "tool", "cgo",
|
2019-11-20 10:19:43 -05:00
|
|
|
"-objdir", objDir,
|
|
|
|
|
"-exportheader", header)
|
|
|
|
|
cmd.Args = append(cmd.Args, files...)
|
|
|
|
|
t.Log(cmd.Args)
|
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-14 17:03:01 +11:00
|
|
|
func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) {
|
2017-10-09 21:07:32 -04:00
|
|
|
t.Helper()
|
2016-10-14 17:03:01 +11:00
|
|
|
cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
|
2022-07-11 13:06:56 -04:00
|
|
|
cmd.Env = append(cmd.Environ(), "GO111MODULE=off") // 'go install' only works in GOPATH mode
|
2017-10-09 21:07:32 -04:00
|
|
|
t.Log(buildcmd)
|
2016-03-22 18:17:43 -07:00
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
2019-11-20 10:19:43 -05:00
|
|
|
if !testWork {
|
|
|
|
|
defer func() {
|
|
|
|
|
os.Remove(libgoa)
|
|
|
|
|
os.Remove(libgoh)
|
|
|
|
|
}()
|
|
|
|
|
}
|
2016-03-22 18:17:43 -07:00
|
|
|
|
2016-10-14 17:03:01 +11:00
|
|
|
ccArgs := append(cc, "-o", exe, "main.c")
|
|
|
|
|
if GOOS == "windows" {
|
|
|
|
|
ccArgs = append(ccArgs, "main_windows.c", libgoa, "-lntdll", "-lws2_32", "-lwinmm")
|
|
|
|
|
} else {
|
|
|
|
|
ccArgs = append(ccArgs, "main_unix.c", libgoa)
|
2016-03-22 18:17:43 -07:00
|
|
|
}
|
2017-02-24 15:46:40 -08:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
|
}
|
2016-10-14 17:03:01 +11:00
|
|
|
t.Log(ccArgs)
|
|
|
|
|
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
2016-03-22 18:17:43 -07:00
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
2019-11-20 10:19:43 -05:00
|
|
|
if !testWork {
|
|
|
|
|
defer os.Remove(exe)
|
|
|
|
|
}
|
2016-03-22 18:17:43 -07:00
|
|
|
|
2016-10-14 17:03:01 +11:00
|
|
|
binArgs := append(cmdToRun(exe), "arg1", "arg2")
|
2017-02-24 15:46:40 -08:00
|
|
|
cmd = exec.Command(binArgs[0], binArgs[1:]...)
|
|
|
|
|
if runtime.Compiler == "gccgo" {
|
2022-07-11 13:06:56 -04:00
|
|
|
cmd.Env = append(cmd.Environ(), "GCCGO=1")
|
2017-02-24 15:46:40 -08:00
|
|
|
}
|
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
2016-03-22 18:17:43 -07:00
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
2018-04-19 12:56:29 -07:00
|
|
|
|
|
|
|
|
checkLineComments(t, libgoh)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var badLineRegexp = regexp.MustCompile(`(?m)^#line [0-9]+ "/.*$`)
|
|
|
|
|
|
|
|
|
|
// checkLineComments checks that the export header generated by
|
|
|
|
|
// -buildmode=c-archive doesn't have any absolute paths in the #line
|
|
|
|
|
// comments. We don't want those paths because they are unhelpful for
|
|
|
|
|
// the user and make the files change based on details of the location
|
|
|
|
|
// of GOPATH.
|
|
|
|
|
func checkLineComments(t *testing.T, hdrname string) {
|
2021-04-03 08:10:47 +00:00
|
|
|
hdr, err := os.ReadFile(hdrname)
|
2018-04-19 12:56:29 -07:00
|
|
|
if err != nil {
|
|
|
|
|
if !os.IsNotExist(err) {
|
|
|
|
|
t.Error(err)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if line := badLineRegexp.Find(hdr); line != nil {
|
|
|
|
|
t.Errorf("bad #line directive with absolute path in %s: %q", hdrname, line)
|
|
|
|
|
}
|
2016-10-14 17:03:01 +11:00
|
|
|
}
|
2016-03-22 18:17:43 -07:00
|
|
|
|
2021-12-21 10:00:23 -08:00
|
|
|
// checkArchive verifies that the created library looks OK.
|
|
|
|
|
// We just check a couple of things now, we can add more checks as needed.
|
|
|
|
|
func checkArchive(t *testing.T, arname string) {
|
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
|
|
switch GOOS {
|
|
|
|
|
case "aix", "darwin", "ios", "windows":
|
|
|
|
|
// We don't have any checks for non-ELF libraries yet.
|
|
|
|
|
if _, err := os.Stat(arname); err != nil {
|
|
|
|
|
t.Errorf("archive %s does not exist: %v", arname, err)
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
checkELFArchive(t, arname)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// checkELFArchive checks an ELF archive.
|
|
|
|
|
func checkELFArchive(t *testing.T, arname string) {
|
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
|
|
f, err := os.Open(arname)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("archive %s does not exist: %v", arname, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
|
|
// TODO(iant): put these in a shared package? But where?
|
|
|
|
|
const (
|
|
|
|
|
magic = "!<arch>\n"
|
|
|
|
|
fmag = "`\n"
|
|
|
|
|
|
|
|
|
|
namelen = 16
|
|
|
|
|
datelen = 12
|
|
|
|
|
uidlen = 6
|
|
|
|
|
gidlen = 6
|
|
|
|
|
modelen = 8
|
|
|
|
|
sizelen = 10
|
|
|
|
|
fmaglen = 2
|
|
|
|
|
hdrlen = namelen + datelen + uidlen + gidlen + modelen + sizelen + fmaglen
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type arhdr struct {
|
|
|
|
|
name string
|
|
|
|
|
date string
|
|
|
|
|
uid string
|
|
|
|
|
gid string
|
|
|
|
|
mode string
|
|
|
|
|
size string
|
|
|
|
|
fmag string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var magbuf [len(magic)]byte
|
|
|
|
|
if _, err := io.ReadFull(f, magbuf[:]); err != nil {
|
|
|
|
|
t.Errorf("%s: archive too short", arname)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if string(magbuf[:]) != magic {
|
|
|
|
|
t.Errorf("%s: incorrect archive magic string %q", arname, magbuf)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
off := int64(len(magic))
|
|
|
|
|
for {
|
|
|
|
|
if off&1 != 0 {
|
|
|
|
|
var b [1]byte
|
|
|
|
|
if _, err := f.Read(b[:]); err != nil {
|
|
|
|
|
if err == io.EOF {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
t.Errorf("%s: error skipping alignment byte at %d: %v", arname, off, err)
|
|
|
|
|
}
|
|
|
|
|
off++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var hdrbuf [hdrlen]byte
|
|
|
|
|
if _, err := io.ReadFull(f, hdrbuf[:]); err != nil {
|
|
|
|
|
if err == io.EOF {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
t.Errorf("%s: error reading archive header at %d: %v", arname, off, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var hdr arhdr
|
|
|
|
|
hdrslice := hdrbuf[:]
|
|
|
|
|
set := func(len int, ps *string) {
|
|
|
|
|
*ps = string(bytes.TrimSpace(hdrslice[:len]))
|
|
|
|
|
hdrslice = hdrslice[len:]
|
|
|
|
|
}
|
|
|
|
|
set(namelen, &hdr.name)
|
|
|
|
|
set(datelen, &hdr.date)
|
|
|
|
|
set(uidlen, &hdr.uid)
|
|
|
|
|
set(gidlen, &hdr.gid)
|
|
|
|
|
set(modelen, &hdr.mode)
|
|
|
|
|
set(sizelen, &hdr.size)
|
|
|
|
|
hdr.fmag = string(hdrslice[:fmaglen])
|
|
|
|
|
hdrslice = hdrslice[fmaglen:]
|
|
|
|
|
if len(hdrslice) != 0 {
|
|
|
|
|
t.Fatalf("internal error: len(hdrslice) == %d", len(hdrslice))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if hdr.fmag != fmag {
|
|
|
|
|
t.Errorf("%s: invalid fmagic value %q at %d", arname, hdr.fmag, off)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size, err := strconv.ParseInt(hdr.size, 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("%s: error parsing size %q at %d: %v", arname, hdr.size, off, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
off += hdrlen
|
|
|
|
|
|
|
|
|
|
switch hdr.name {
|
|
|
|
|
case "__.SYMDEF", "/", "/SYM64/":
|
|
|
|
|
// The archive symbol map.
|
|
|
|
|
case "//", "ARFILENAMES/":
|
|
|
|
|
// The extended name table.
|
|
|
|
|
default:
|
|
|
|
|
// This should be an ELF object.
|
|
|
|
|
checkELFArchiveObject(t, arname, off, io.NewSectionReader(f, off, size))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
off += size
|
2022-09-16 08:13:23 +08:00
|
|
|
if _, err := f.Seek(off, io.SeekStart); err != nil {
|
2021-12-21 10:00:23 -08:00
|
|
|
t.Errorf("%s: failed to seek to %d: %v", arname, off, err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// checkELFArchiveObject checks an object in an ELF archive.
|
|
|
|
|
func checkELFArchiveObject(t *testing.T, arname string, off int64, obj io.ReaderAt) {
|
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
|
|
ef, err := elf.NewFile(obj)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("%s: failed to open ELF file at %d: %v", arname, off, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
defer ef.Close()
|
|
|
|
|
|
|
|
|
|
// Verify section types.
|
|
|
|
|
for _, sec := range ef.Sections {
|
|
|
|
|
want := elf.SHT_NULL
|
|
|
|
|
switch sec.Name {
|
|
|
|
|
case ".text", ".data":
|
|
|
|
|
want = elf.SHT_PROGBITS
|
|
|
|
|
case ".bss":
|
|
|
|
|
want = elf.SHT_NOBITS
|
|
|
|
|
case ".symtab":
|
|
|
|
|
want = elf.SHT_SYMTAB
|
|
|
|
|
case ".strtab":
|
|
|
|
|
want = elf.SHT_STRTAB
|
|
|
|
|
case ".init_array":
|
|
|
|
|
want = elf.SHT_INIT_ARRAY
|
|
|
|
|
case ".fini_array":
|
|
|
|
|
want = elf.SHT_FINI_ARRAY
|
|
|
|
|
case ".preinit_array":
|
|
|
|
|
want = elf.SHT_PREINIT_ARRAY
|
|
|
|
|
}
|
|
|
|
|
if want != elf.SHT_NULL && sec.Type != want {
|
|
|
|
|
t.Errorf("%s: incorrect section type in elf file at %d for section %q: got %v want %v", arname, off, sec.Name, sec.Type, want)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-14 17:03:01 +11:00
|
|
|
func TestInstall(t *testing.T) {
|
2023-05-22 15:19:49 -04:00
|
|
|
globalSkip(t)
|
cmd/dist: drop host test support
Host tests are used for emulated builders that use cross-compilation.
Today, this is the android-{386,amd64}-emu builders and all wasm
builders. These builders run all.bash on a linux/amd64 host to build
all packages and most tests for the emulated guest, and then run the
resulting test binaries inside the emulated guest. A small number of
test packages are “host tests”: these run on the host rather than the
guest because they invoke the Go toolchain themselves (which only
lives on the host) and run the resulting binaries in the guest.
However, this host test mechanism is barely used today, despite being
quite complex. This complexity is also causing significant friction to
implementing structured all.bash output.
As of this CL, the whole host test mechanism runs a total of 10 test
cases on a total of two builders (android-{386,amd64}-emu). There are
clearly several tests that are incorrectly being skipped, so we could
expand it to cover more test cases, but it would still apply to only
two builders. Furthermore, the two other Android builders
(android-{arm,arm64}-corellium) build the Go toolchain directly inside
Android and also have access to a C toolchain, so they are able to get
significantly better test coverage without the use of host tests. This
suggests that the android-*-emu builders could do the same. All of
these tests are cgo-related, so they don't run on the wasm hosts
anyway.
Given the incredibly low value of host tests today, they are not worth
their implementation complexity and the friction they cause. Hence,
this CL drops support for host tests. (This was also the last use of
rtSequential, so we drop support for sequential tests, too.)
Fixes #59999.
Change-Id: I3eaca853a8907abc8247709f15a0d19a872dd22d
Reviewed-on: https://go-review.googlesource.com/c/go/+/492986
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2023-05-05 13:52:31 -04:00
|
|
|
testenv.MustHaveGoBuild(t)
|
2023-04-26 12:16:26 -04:00
|
|
|
testenv.MustHaveCGO(t)
|
|
|
|
|
testenv.MustHaveBuildMode(t, "c-archive")
|
cmd/dist: drop host test support
Host tests are used for emulated builders that use cross-compilation.
Today, this is the android-{386,amd64}-emu builders and all wasm
builders. These builders run all.bash on a linux/amd64 host to build
all packages and most tests for the emulated guest, and then run the
resulting test binaries inside the emulated guest. A small number of
test packages are “host tests”: these run on the host rather than the
guest because they invoke the Go toolchain themselves (which only
lives on the host) and run the resulting binaries in the guest.
However, this host test mechanism is barely used today, despite being
quite complex. This complexity is also causing significant friction to
implementing structured all.bash output.
As of this CL, the whole host test mechanism runs a total of 10 test
cases on a total of two builders (android-{386,amd64}-emu). There are
clearly several tests that are incorrectly being skipped, so we could
expand it to cover more test cases, but it would still apply to only
two builders. Furthermore, the two other Android builders
(android-{arm,arm64}-corellium) build the Go toolchain directly inside
Android and also have access to a C toolchain, so they are able to get
significantly better test coverage without the use of host tests. This
suggests that the android-*-emu builders could do the same. All of
these tests are cgo-related, so they don't run on the wasm hosts
anyway.
Given the incredibly low value of host tests today, they are not worth
their implementation complexity and the friction they cause. Hence,
this CL drops support for host tests. (This was also the last use of
rtSequential, so we drop support for sequential tests, too.)
Fixes #59999.
Change-Id: I3eaca853a8907abc8247709f15a0d19a872dd22d
Reviewed-on: https://go-review.googlesource.com/c/go/+/492986
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2023-05-05 13:52:31 -04:00
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
if !testWork {
|
|
|
|
|
defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
|
|
|
|
|
}
|
2016-03-22 18:17:43 -07:00
|
|
|
|
2017-02-24 15:46:40 -08:00
|
|
|
libgoa := "libgo.a"
|
|
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
|
libgoa = "liblibgo.a"
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
// Generate the p.h header file.
|
|
|
|
|
//
|
|
|
|
|
// 'go install -i -buildmode=c-archive ./libgo' would do that too, but that
|
|
|
|
|
// would also attempt to install transitive standard-library dependencies to
|
|
|
|
|
// GOROOT, and we cannot assume that GOROOT is writable. (A non-root user may
|
|
|
|
|
// be running this test in a GOROOT owned by root.)
|
|
|
|
|
genHeader(t, "p.h", "./p")
|
|
|
|
|
|
2016-10-14 17:03:01 +11:00
|
|
|
testInstall(t, "./testp1"+exeSuffix,
|
2019-02-21 12:34:27 -05:00
|
|
|
filepath.Join(libgodir, libgoa),
|
|
|
|
|
filepath.Join(libgodir, "libgo.h"),
|
2019-11-20 10:19:43 -05:00
|
|
|
"go", "install", "-buildmode=c-archive", "./libgo")
|
2016-03-22 18:17:43 -07:00
|
|
|
|
2016-10-14 17:03:01 +11:00
|
|
|
// Test building libgo other than installing it.
|
|
|
|
|
// Header files are now present.
|
|
|
|
|
testInstall(t, "./testp2"+exeSuffix, "libgo.a", "libgo.h",
|
2019-02-21 12:34:27 -05:00
|
|
|
"go", "build", "-buildmode=c-archive", filepath.Join(".", "libgo", "libgo.go"))
|
2016-03-22 18:17:43 -07:00
|
|
|
|
2016-10-14 17:03:01 +11:00
|
|
|
testInstall(t, "./testp3"+exeSuffix, "libgo.a", "libgo.h",
|
2019-02-21 12:34:27 -05:00
|
|
|
"go", "build", "-buildmode=c-archive", "-o", "libgo.a", "./libgo")
|
2016-03-22 18:17:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestEarlySignalHandler(t *testing.T) {
|
2016-03-24 21:47:02 +01:00
|
|
|
switch GOOS {
|
2020-09-16 16:59:58 -04:00
|
|
|
case "darwin", "ios":
|
2016-03-24 21:47:02 +01:00
|
|
|
switch GOARCH {
|
2020-04-03 12:22:27 -04:00
|
|
|
case "arm64":
|
2016-03-24 21:47:02 +01:00
|
|
|
t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
|
2016-03-22 18:17:43 -07:00
|
|
|
}
|
|
|
|
|
case "windows":
|
|
|
|
|
t.Skip("skipping signal test on Windows")
|
|
|
|
|
}
|
2023-05-22 15:19:49 -04:00
|
|
|
globalSkip(t)
|
cmd/dist: drop host test support
Host tests are used for emulated builders that use cross-compilation.
Today, this is the android-{386,amd64}-emu builders and all wasm
builders. These builders run all.bash on a linux/amd64 host to build
all packages and most tests for the emulated guest, and then run the
resulting test binaries inside the emulated guest. A small number of
test packages are “host tests”: these run on the host rather than the
guest because they invoke the Go toolchain themselves (which only
lives on the host) and run the resulting binaries in the guest.
However, this host test mechanism is barely used today, despite being
quite complex. This complexity is also causing significant friction to
implementing structured all.bash output.
As of this CL, the whole host test mechanism runs a total of 10 test
cases on a total of two builders (android-{386,amd64}-emu). There are
clearly several tests that are incorrectly being skipped, so we could
expand it to cover more test cases, but it would still apply to only
two builders. Furthermore, the two other Android builders
(android-{arm,arm64}-corellium) build the Go toolchain directly inside
Android and also have access to a C toolchain, so they are able to get
significantly better test coverage without the use of host tests. This
suggests that the android-*-emu builders could do the same. All of
these tests are cgo-related, so they don't run on the wasm hosts
anyway.
Given the incredibly low value of host tests today, they are not worth
their implementation complexity and the friction they cause. Hence,
this CL drops support for host tests. (This was also the last use of
rtSequential, so we drop support for sequential tests, too.)
Fixes #59999.
Change-Id: I3eaca853a8907abc8247709f15a0d19a872dd22d
Reviewed-on: https://go-review.googlesource.com/c/go/+/492986
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2023-05-05 13:52:31 -04:00
|
|
|
testenv.MustHaveGoBuild(t)
|
2023-04-26 12:16:26 -04:00
|
|
|
testenv.MustHaveCGO(t)
|
|
|
|
|
testenv.MustHaveBuildMode(t, "c-archive")
|
2016-03-22 18:17:43 -07:00
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
if !testWork {
|
|
|
|
|
defer func() {
|
|
|
|
|
os.Remove("libgo2.a")
|
|
|
|
|
os.Remove("libgo2.h")
|
2021-12-03 10:33:02 -05:00
|
|
|
os.Remove("testp" + exeSuffix)
|
2019-11-20 10:19:43 -05:00
|
|
|
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
|
|
|
|
|
}()
|
|
|
|
|
}
|
2016-03-22 18:17:43 -07:00
|
|
|
|
2025-02-24 10:21:01 +01:00
|
|
|
cmd := exec.Command(testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-o", "libgo2.a", "./libgo2")
|
2016-03-22 18:17:43 -07:00
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
2018-04-19 12:56:29 -07:00
|
|
|
checkLineComments(t, "libgo2.h")
|
2021-12-21 10:00:23 -08:00
|
|
|
checkArchive(t, "libgo2.a")
|
2016-03-22 18:17:43 -07:00
|
|
|
|
|
|
|
|
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main2.c", "libgo2.a")
|
2017-02-24 15:46:40 -08:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
|
}
|
2016-03-22 18:17:43 -07:00
|
|
|
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
|
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-31 14:33:57 +02:00
|
|
|
darwin := "0"
|
|
|
|
|
if runtime.GOOS == "darwin" {
|
|
|
|
|
darwin = "1"
|
|
|
|
|
}
|
|
|
|
|
cmd = exec.Command(bin[0], append(bin[1:], darwin)...)
|
|
|
|
|
|
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
2016-03-22 18:17:43 -07:00
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-22 22:11:42 -05:00
|
|
|
func TestSignalForwarding(t *testing.T) {
|
2023-05-22 15:19:49 -04:00
|
|
|
globalSkip(t)
|
2017-05-09 14:34:16 -07:00
|
|
|
checkSignalForwardingTest(t)
|
2022-08-19 14:43:47 -07:00
|
|
|
buildSignalForwardingTest(t)
|
2016-03-22 22:11:42 -05:00
|
|
|
|
2022-08-19 14:43:47 -07:00
|
|
|
cmd := exec.Command(bin[0], append(bin[1:], "1")...)
|
2016-03-22 22:11:42 -05:00
|
|
|
|
|
|
|
|
out, err := cmd.CombinedOutput()
|
2021-12-03 10:33:02 -05:00
|
|
|
t.Logf("%v\n%s", cmd.Args, out)
|
2022-08-19 14:43:47 -07:00
|
|
|
expectSignal(t, err, syscall.SIGSEGV, 0)
|
2017-01-29 15:34:50 +01:00
|
|
|
|
2019-07-31 14:33:57 +02:00
|
|
|
// SIGPIPE is never forwarded on darwin. See golang.org/issue/33384.
|
2020-09-16 16:59:58 -04:00
|
|
|
if runtime.GOOS != "darwin" && runtime.GOOS != "ios" {
|
2019-07-31 14:33:57 +02:00
|
|
|
// Test SIGPIPE forwarding
|
|
|
|
|
cmd = exec.Command(bin[0], append(bin[1:], "3")...)
|
2017-01-29 15:34:50 +01:00
|
|
|
|
2019-07-31 14:33:57 +02:00
|
|
|
out, err = cmd.CombinedOutput()
|
2021-12-03 10:33:02 -05:00
|
|
|
if len(out) > 0 {
|
|
|
|
|
t.Logf("%s", out)
|
|
|
|
|
}
|
2022-08-19 14:43:47 -07:00
|
|
|
expectSignal(t, err, syscall.SIGPIPE, 0)
|
2019-07-31 14:33:57 +02:00
|
|
|
}
|
2016-03-22 22:11:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSignalForwardingExternal(t *testing.T) {
|
2019-03-25 10:34:57 +01:00
|
|
|
if GOOS == "freebsd" || GOOS == "aix" {
|
2018-02-13 19:00:17 -08:00
|
|
|
t.Skipf("skipping on %s/%s; signal always goes to the Go runtime", GOOS, GOARCH)
|
2019-04-02 15:05:33 -07:00
|
|
|
} else if GOOS == "darwin" && GOARCH == "amd64" {
|
|
|
|
|
t.Skipf("skipping on %s/%s: runtime does not permit SI_USER SIGSEGV", GOOS, GOARCH)
|
2018-02-13 19:00:17 -08:00
|
|
|
}
|
2023-05-22 15:19:49 -04:00
|
|
|
globalSkip(t)
|
2017-05-09 14:34:16 -07:00
|
|
|
checkSignalForwardingTest(t)
|
2022-08-19 14:43:47 -07:00
|
|
|
buildSignalForwardingTest(t)
|
|
|
|
|
|
|
|
|
|
// We want to send the process a signal and see if it dies.
|
|
|
|
|
// Normally the signal goes to the C thread, the Go signal
|
|
|
|
|
// handler picks it up, sees that it is running in a C thread,
|
|
|
|
|
// and the program dies. Unfortunately, occasionally the
|
|
|
|
|
// signal is delivered to a Go thread, which winds up
|
|
|
|
|
// discarding it because it was sent by another program and
|
|
|
|
|
// there is no Go handler for it. To avoid this, run the
|
|
|
|
|
// program several times in the hopes that it will eventually
|
|
|
|
|
// fail.
|
|
|
|
|
const tries = 20
|
|
|
|
|
for i := 0; i < tries; i++ {
|
|
|
|
|
err := runSignalForwardingTest(t, "2")
|
|
|
|
|
if err == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the signal is delivered to a C thread, as expected,
|
|
|
|
|
// the Go signal handler will disable itself and re-raise
|
|
|
|
|
// the signal, causing the program to die with SIGSEGV.
|
|
|
|
|
//
|
|
|
|
|
// It is also possible that the signal will be
|
|
|
|
|
// delivered to a Go thread, such as a GC thread.
|
|
|
|
|
// Currently when the Go runtime sees that a SIGSEGV was
|
|
|
|
|
// sent from a different program, it first tries to send
|
|
|
|
|
// the signal to the os/signal API. If nothing is looking
|
|
|
|
|
// for (or explicitly ignoring) SIGSEGV, then it crashes.
|
|
|
|
|
// Because the Go runtime is invoked via a c-archive,
|
|
|
|
|
// it treats this as GOTRACEBACK=crash, meaning that it
|
|
|
|
|
// dumps a stack trace for all goroutines, which it does
|
|
|
|
|
// by raising SIGQUIT. The effect is that we will see the
|
|
|
|
|
// program die with SIGQUIT in that case, not SIGSEGV.
|
|
|
|
|
if expectSignal(t, err, syscall.SIGSEGV, syscall.SIGQUIT) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t.Errorf("program succeeded unexpectedly %d times", tries)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSignalForwardingGo(t *testing.T) {
|
|
|
|
|
// This test fails on darwin-amd64 because of the special
|
|
|
|
|
// handling of user-generated SIGSEGV signals in fixsigcode in
|
|
|
|
|
// runtime/signal_darwin_amd64.go.
|
|
|
|
|
if runtime.GOOS == "darwin" && runtime.GOARCH == "amd64" {
|
|
|
|
|
t.Skip("not supported on darwin-amd64")
|
|
|
|
|
}
|
2023-05-22 15:19:49 -04:00
|
|
|
globalSkip(t)
|
2022-08-19 14:43:47 -07:00
|
|
|
|
|
|
|
|
checkSignalForwardingTest(t)
|
|
|
|
|
buildSignalForwardingTest(t)
|
|
|
|
|
err := runSignalForwardingTest(t, "4")
|
|
|
|
|
|
|
|
|
|
// Occasionally the signal will be delivered to a C thread,
|
|
|
|
|
// and the program will crash with SIGSEGV.
|
|
|
|
|
expectSignal(t, err, syscall.SIGQUIT, syscall.SIGSEGV)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// checkSignalForwardingTest calls t.Skip if the SignalForwarding test
|
|
|
|
|
// doesn't work on this platform.
|
|
|
|
|
func checkSignalForwardingTest(t *testing.T) {
|
|
|
|
|
switch GOOS {
|
|
|
|
|
case "darwin", "ios":
|
|
|
|
|
switch GOARCH {
|
|
|
|
|
case "arm64":
|
|
|
|
|
t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
|
|
|
|
|
}
|
|
|
|
|
case "windows":
|
|
|
|
|
t.Skip("skipping signal test on Windows")
|
|
|
|
|
}
|
2023-04-26 12:16:26 -04:00
|
|
|
testenv.MustHaveGoBuild(t)
|
|
|
|
|
testenv.MustHaveCGO(t)
|
|
|
|
|
testenv.MustHaveBuildMode(t, "c-archive")
|
2022-08-19 14:43:47 -07:00
|
|
|
}
|
2016-03-22 22:11:42 -05:00
|
|
|
|
2022-08-19 14:43:47 -07:00
|
|
|
// buildSignalForwardingTest builds the executable used by the various
|
|
|
|
|
// signal forwarding tests.
|
|
|
|
|
func buildSignalForwardingTest(t *testing.T) {
|
2019-11-20 10:19:43 -05:00
|
|
|
if !testWork {
|
2022-08-19 14:43:47 -07:00
|
|
|
t.Cleanup(func() {
|
2019-11-20 10:19:43 -05:00
|
|
|
os.Remove("libgo2.a")
|
|
|
|
|
os.Remove("libgo2.h")
|
2021-12-03 10:33:02 -05:00
|
|
|
os.Remove("testp" + exeSuffix)
|
2019-11-20 10:19:43 -05:00
|
|
|
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
|
2022-08-19 14:43:47 -07:00
|
|
|
})
|
2019-11-20 10:19:43 -05:00
|
|
|
}
|
2016-03-22 22:11:42 -05:00
|
|
|
|
2022-08-19 14:43:47 -07:00
|
|
|
t.Log("go build -buildmode=c-archive -o libgo2.a ./libgo2")
|
2025-02-24 10:21:01 +01:00
|
|
|
cmd := exec.Command(testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-o", "libgo2.a", "./libgo2")
|
2022-08-19 14:43:47 -07:00
|
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
|
if len(out) > 0 {
|
2016-03-22 22:11:42 -05:00
|
|
|
t.Logf("%s", out)
|
2022-08-19 14:43:47 -07:00
|
|
|
}
|
|
|
|
|
if err != nil {
|
2016-03-22 22:11:42 -05:00
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
2022-08-19 14:43:47 -07:00
|
|
|
|
2018-04-19 12:56:29 -07:00
|
|
|
checkLineComments(t, "libgo2.h")
|
2021-12-21 10:00:23 -08:00
|
|
|
checkArchive(t, "libgo2.a")
|
2016-03-22 22:11:42 -05:00
|
|
|
|
|
|
|
|
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
|
2017-02-24 15:46:40 -08:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
|
}
|
2022-08-19 14:43:47 -07:00
|
|
|
t.Log(ccArgs)
|
|
|
|
|
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
|
|
|
|
if len(out) > 0 {
|
2016-03-22 22:11:42 -05:00
|
|
|
t.Logf("%s", out)
|
2022-08-19 14:43:47 -07:00
|
|
|
}
|
|
|
|
|
if err != nil {
|
2016-03-22 22:11:42 -05:00
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
2022-08-19 14:43:47 -07:00
|
|
|
}
|
2016-03-22 22:11:42 -05:00
|
|
|
|
2022-08-19 14:43:47 -07:00
|
|
|
func runSignalForwardingTest(t *testing.T, arg string) error {
|
|
|
|
|
t.Logf("%v %s", bin, arg)
|
|
|
|
|
cmd := exec.Command(bin[0], append(bin[1:], arg)...)
|
2016-03-25 15:57:25 -07:00
|
|
|
|
2022-08-19 14:43:47 -07:00
|
|
|
var out strings.Builder
|
|
|
|
|
cmd.Stdout = &out
|
2016-03-22 22:11:42 -05:00
|
|
|
|
2022-08-19 14:43:47 -07:00
|
|
|
stderr, err := cmd.StderrPipe()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
defer stderr.Close()
|
2016-03-22 22:11:42 -05:00
|
|
|
|
2022-08-19 14:43:47 -07:00
|
|
|
r := bufio.NewReader(stderr)
|
2016-03-22 22:11:42 -05:00
|
|
|
|
2022-08-19 14:43:47 -07:00
|
|
|
err = cmd.Start()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
2016-03-22 22:11:42 -05:00
|
|
|
|
2022-08-19 14:43:47 -07:00
|
|
|
// Wait for trigger to ensure that process is started.
|
|
|
|
|
ok, err := r.ReadString('\n')
|
2016-03-22 22:11:42 -05:00
|
|
|
|
2022-08-19 14:43:47 -07:00
|
|
|
// Verify trigger.
|
|
|
|
|
if err != nil || ok != "OK\n" {
|
|
|
|
|
t.Fatal("Did not receive OK signal")
|
|
|
|
|
}
|
2016-03-22 22:11:42 -05:00
|
|
|
|
2022-08-19 14:43:47 -07:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
var errsb strings.Builder
|
|
|
|
|
go func() {
|
|
|
|
|
defer wg.Done()
|
|
|
|
|
io.Copy(&errsb, r)
|
|
|
|
|
}()
|
2016-03-22 22:11:42 -05:00
|
|
|
|
2022-08-19 14:43:47 -07:00
|
|
|
// Give the program a chance to enter the function.
|
|
|
|
|
// If the program doesn't get there the test will still
|
|
|
|
|
// pass, although it doesn't quite test what we intended.
|
|
|
|
|
// This is fine as long as the program normally makes it.
|
|
|
|
|
time.Sleep(time.Millisecond)
|
2016-03-22 22:11:42 -05:00
|
|
|
|
2022-08-19 14:43:47 -07:00
|
|
|
cmd.Process.Signal(syscall.SIGSEGV)
|
2016-03-22 22:11:42 -05:00
|
|
|
|
2022-08-19 14:43:47 -07:00
|
|
|
err = cmd.Wait()
|
2016-03-25 15:57:25 -07:00
|
|
|
|
2022-08-19 14:43:47 -07:00
|
|
|
s := out.String()
|
|
|
|
|
if len(s) > 0 {
|
|
|
|
|
t.Log(s)
|
2017-05-09 14:34:16 -07:00
|
|
|
}
|
2022-08-19 14:43:47 -07:00
|
|
|
wg.Wait()
|
|
|
|
|
s = errsb.String()
|
|
|
|
|
if len(s) > 0 {
|
|
|
|
|
t.Log(s)
|
2022-08-19 13:42:38 +00:00
|
|
|
}
|
2022-08-19 14:43:47 -07:00
|
|
|
|
|
|
|
|
return err
|
2017-05-09 14:34:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// expectSignal checks that err, the exit status of a test program,
|
2022-08-19 14:43:47 -07:00
|
|
|
// shows a failure due to a specific signal or two. Returns whether we
|
|
|
|
|
// found an expected signal.
|
|
|
|
|
func expectSignal(t *testing.T, err error, sig1, sig2 syscall.Signal) bool {
|
|
|
|
|
t.Helper()
|
2017-05-09 14:34:16 -07:00
|
|
|
if err == nil {
|
|
|
|
|
t.Error("test program succeeded unexpectedly")
|
|
|
|
|
} else if ee, ok := err.(*exec.ExitError); !ok {
|
|
|
|
|
t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err)
|
|
|
|
|
} else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
|
|
|
|
|
t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys())
|
2022-08-19 14:43:47 -07:00
|
|
|
} else if !ws.Signaled() || (ws.Signal() != sig1 && ws.Signal() != sig2) {
|
|
|
|
|
if sig2 == 0 {
|
|
|
|
|
t.Errorf("got %q; expected signal %q", ee, sig1)
|
|
|
|
|
} else {
|
|
|
|
|
t.Errorf("got %q; expected signal %q or %q", ee, sig1, sig2)
|
|
|
|
|
}
|
2017-05-09 14:34:16 -07:00
|
|
|
} else {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-22 18:17:43 -07:00
|
|
|
func TestOsSignal(t *testing.T) {
|
2016-03-24 21:47:02 +01:00
|
|
|
switch GOOS {
|
2016-03-22 18:17:43 -07:00
|
|
|
case "windows":
|
|
|
|
|
t.Skip("skipping signal test on Windows")
|
|
|
|
|
}
|
2023-05-22 15:19:49 -04:00
|
|
|
globalSkip(t)
|
cmd/dist: drop host test support
Host tests are used for emulated builders that use cross-compilation.
Today, this is the android-{386,amd64}-emu builders and all wasm
builders. These builders run all.bash on a linux/amd64 host to build
all packages and most tests for the emulated guest, and then run the
resulting test binaries inside the emulated guest. A small number of
test packages are “host tests”: these run on the host rather than the
guest because they invoke the Go toolchain themselves (which only
lives on the host) and run the resulting binaries in the guest.
However, this host test mechanism is barely used today, despite being
quite complex. This complexity is also causing significant friction to
implementing structured all.bash output.
As of this CL, the whole host test mechanism runs a total of 10 test
cases on a total of two builders (android-{386,amd64}-emu). There are
clearly several tests that are incorrectly being skipped, so we could
expand it to cover more test cases, but it would still apply to only
two builders. Furthermore, the two other Android builders
(android-{arm,arm64}-corellium) build the Go toolchain directly inside
Android and also have access to a C toolchain, so they are able to get
significantly better test coverage without the use of host tests. This
suggests that the android-*-emu builders could do the same. All of
these tests are cgo-related, so they don't run on the wasm hosts
anyway.
Given the incredibly low value of host tests today, they are not worth
their implementation complexity and the friction they cause. Hence,
this CL drops support for host tests. (This was also the last use of
rtSequential, so we drop support for sequential tests, too.)
Fixes #59999.
Change-Id: I3eaca853a8907abc8247709f15a0d19a872dd22d
Reviewed-on: https://go-review.googlesource.com/c/go/+/492986
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2023-05-05 13:52:31 -04:00
|
|
|
testenv.MustHaveGoBuild(t)
|
2023-04-26 12:16:26 -04:00
|
|
|
testenv.MustHaveCGO(t)
|
|
|
|
|
testenv.MustHaveBuildMode(t, "c-archive")
|
2016-03-22 18:17:43 -07:00
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
if !testWork {
|
|
|
|
|
defer func() {
|
|
|
|
|
os.Remove("libgo3.a")
|
|
|
|
|
os.Remove("libgo3.h")
|
2021-12-03 10:33:02 -05:00
|
|
|
os.Remove("testp" + exeSuffix)
|
2019-11-20 10:19:43 -05:00
|
|
|
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
|
|
|
|
|
}()
|
|
|
|
|
}
|
2016-03-22 18:17:43 -07:00
|
|
|
|
2025-02-24 10:21:01 +01:00
|
|
|
cmd := exec.Command(testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-o", "libgo3.a", "./libgo3")
|
2016-03-22 18:17:43 -07:00
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
2018-04-19 12:56:29 -07:00
|
|
|
checkLineComments(t, "libgo3.h")
|
2021-12-21 10:00:23 -08:00
|
|
|
checkArchive(t, "libgo3.a")
|
2016-03-22 18:17:43 -07:00
|
|
|
|
|
|
|
|
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main3.c", "libgo3.a")
|
2017-02-24 15:46:40 -08:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
|
}
|
2016-03-22 18:17:43 -07:00
|
|
|
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
|
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
|
|
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSigaltstack(t *testing.T) {
|
2016-03-24 21:47:02 +01:00
|
|
|
switch GOOS {
|
2016-03-22 18:17:43 -07:00
|
|
|
case "windows":
|
|
|
|
|
t.Skip("skipping signal test on Windows")
|
|
|
|
|
}
|
2023-05-22 15:19:49 -04:00
|
|
|
globalSkip(t)
|
cmd/dist: drop host test support
Host tests are used for emulated builders that use cross-compilation.
Today, this is the android-{386,amd64}-emu builders and all wasm
builders. These builders run all.bash on a linux/amd64 host to build
all packages and most tests for the emulated guest, and then run the
resulting test binaries inside the emulated guest. A small number of
test packages are “host tests”: these run on the host rather than the
guest because they invoke the Go toolchain themselves (which only
lives on the host) and run the resulting binaries in the guest.
However, this host test mechanism is barely used today, despite being
quite complex. This complexity is also causing significant friction to
implementing structured all.bash output.
As of this CL, the whole host test mechanism runs a total of 10 test
cases on a total of two builders (android-{386,amd64}-emu). There are
clearly several tests that are incorrectly being skipped, so we could
expand it to cover more test cases, but it would still apply to only
two builders. Furthermore, the two other Android builders
(android-{arm,arm64}-corellium) build the Go toolchain directly inside
Android and also have access to a C toolchain, so they are able to get
significantly better test coverage without the use of host tests. This
suggests that the android-*-emu builders could do the same. All of
these tests are cgo-related, so they don't run on the wasm hosts
anyway.
Given the incredibly low value of host tests today, they are not worth
their implementation complexity and the friction they cause. Hence,
this CL drops support for host tests. (This was also the last use of
rtSequential, so we drop support for sequential tests, too.)
Fixes #59999.
Change-Id: I3eaca853a8907abc8247709f15a0d19a872dd22d
Reviewed-on: https://go-review.googlesource.com/c/go/+/492986
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2023-05-05 13:52:31 -04:00
|
|
|
testenv.MustHaveGoBuild(t)
|
2023-04-26 12:16:26 -04:00
|
|
|
testenv.MustHaveCGO(t)
|
|
|
|
|
testenv.MustHaveBuildMode(t, "c-archive")
|
2016-03-22 18:17:43 -07:00
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
if !testWork {
|
|
|
|
|
defer func() {
|
|
|
|
|
os.Remove("libgo4.a")
|
|
|
|
|
os.Remove("libgo4.h")
|
2021-12-03 10:33:02 -05:00
|
|
|
os.Remove("testp" + exeSuffix)
|
2019-11-20 10:19:43 -05:00
|
|
|
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
|
|
|
|
|
}()
|
|
|
|
|
}
|
2016-03-22 18:17:43 -07:00
|
|
|
|
2025-02-24 10:21:01 +01:00
|
|
|
cmd := exec.Command(testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-o", "libgo4.a", "./libgo4")
|
2016-03-22 18:17:43 -07:00
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
2018-04-19 12:56:29 -07:00
|
|
|
checkLineComments(t, "libgo4.h")
|
2021-12-21 10:00:23 -08:00
|
|
|
checkArchive(t, "libgo4.a")
|
2016-03-22 18:17:43 -07:00
|
|
|
|
|
|
|
|
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main4.c", "libgo4.a")
|
2017-02-24 15:46:40 -08:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
|
}
|
2016-03-22 18:17:43 -07:00
|
|
|
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
|
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
|
|
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const testar = `#!/usr/bin/env bash
|
2018-02-13 19:00:17 -08:00
|
|
|
while [[ $1 == -* ]] >/dev/null; do
|
2016-03-22 18:17:43 -07:00
|
|
|
shift
|
|
|
|
|
done
|
|
|
|
|
echo "testar" > $1
|
|
|
|
|
echo "testar" > PWD/testar.ran
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
func TestExtar(t *testing.T) {
|
2016-03-24 21:47:02 +01:00
|
|
|
switch GOOS {
|
2016-03-22 18:17:43 -07:00
|
|
|
case "windows":
|
|
|
|
|
t.Skip("skipping signal test on Windows")
|
|
|
|
|
}
|
2017-02-24 15:46:40 -08:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
|
t.Skip("skipping -extar test when using gccgo")
|
|
|
|
|
}
|
2023-05-22 15:19:49 -04:00
|
|
|
globalSkip(t)
|
cmd/dist: drop host test support
Host tests are used for emulated builders that use cross-compilation.
Today, this is the android-{386,amd64}-emu builders and all wasm
builders. These builders run all.bash on a linux/amd64 host to build
all packages and most tests for the emulated guest, and then run the
resulting test binaries inside the emulated guest. A small number of
test packages are “host tests”: these run on the host rather than the
guest because they invoke the Go toolchain themselves (which only
lives on the host) and run the resulting binaries in the guest.
However, this host test mechanism is barely used today, despite being
quite complex. This complexity is also causing significant friction to
implementing structured all.bash output.
As of this CL, the whole host test mechanism runs a total of 10 test
cases on a total of two builders (android-{386,amd64}-emu). There are
clearly several tests that are incorrectly being skipped, so we could
expand it to cover more test cases, but it would still apply to only
two builders. Furthermore, the two other Android builders
(android-{arm,arm64}-corellium) build the Go toolchain directly inside
Android and also have access to a C toolchain, so they are able to get
significantly better test coverage without the use of host tests. This
suggests that the android-*-emu builders could do the same. All of
these tests are cgo-related, so they don't run on the wasm hosts
anyway.
Given the incredibly low value of host tests today, they are not worth
their implementation complexity and the friction they cause. Hence,
this CL drops support for host tests. (This was also the last use of
rtSequential, so we drop support for sequential tests, too.)
Fixes #59999.
Change-Id: I3eaca853a8907abc8247709f15a0d19a872dd22d
Reviewed-on: https://go-review.googlesource.com/c/go/+/492986
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2023-05-05 13:52:31 -04:00
|
|
|
testenv.MustHaveGoBuild(t)
|
2023-04-26 12:16:26 -04:00
|
|
|
testenv.MustHaveCGO(t)
|
|
|
|
|
testenv.MustHaveBuildMode(t, "c-archive")
|
|
|
|
|
testenv.MustHaveExecPath(t, "bash") // This test uses a bash script
|
2016-03-22 18:17:43 -07:00
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
if !testWork {
|
|
|
|
|
defer func() {
|
|
|
|
|
os.Remove("libgo4.a")
|
|
|
|
|
os.Remove("libgo4.h")
|
|
|
|
|
os.Remove("testar")
|
|
|
|
|
os.Remove("testar.ran")
|
|
|
|
|
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
|
|
|
|
|
}()
|
|
|
|
|
}
|
2016-03-22 18:17:43 -07:00
|
|
|
|
|
|
|
|
os.Remove("testar")
|
|
|
|
|
dir, err := os.Getwd()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
s := strings.Replace(testar, "PWD", dir, 1)
|
2021-04-03 08:10:47 +00:00
|
|
|
if err := os.WriteFile("testar", []byte(s), 0777); err != nil {
|
2016-03-22 18:17:43 -07:00
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-24 10:21:01 +01:00
|
|
|
cmd := exec.Command(testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-ldflags=-extar="+filepath.Join(dir, "testar"), "-o", "libgo4.a", "./libgo4")
|
2016-03-22 18:17:43 -07:00
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
2018-04-19 12:56:29 -07:00
|
|
|
checkLineComments(t, "libgo4.h")
|
2016-03-22 18:17:43 -07:00
|
|
|
|
|
|
|
|
if _, err := os.Stat("testar.ran"); err != nil {
|
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
|
t.Error("testar does not exist after go build")
|
|
|
|
|
} else {
|
|
|
|
|
t.Errorf("error checking testar: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-06-16 12:59:09 -07:00
|
|
|
|
|
|
|
|
func TestPIE(t *testing.T) {
|
|
|
|
|
switch GOOS {
|
2020-09-16 16:59:58 -04:00
|
|
|
case "windows", "darwin", "ios", "plan9":
|
2016-06-16 12:59:09 -07:00
|
|
|
t.Skipf("skipping PIE test on %s", GOOS)
|
|
|
|
|
}
|
2023-05-22 15:19:49 -04:00
|
|
|
globalSkip(t)
|
cmd/dist: drop host test support
Host tests are used for emulated builders that use cross-compilation.
Today, this is the android-{386,amd64}-emu builders and all wasm
builders. These builders run all.bash on a linux/amd64 host to build
all packages and most tests for the emulated guest, and then run the
resulting test binaries inside the emulated guest. A small number of
test packages are “host tests”: these run on the host rather than the
guest because they invoke the Go toolchain themselves (which only
lives on the host) and run the resulting binaries in the guest.
However, this host test mechanism is barely used today, despite being
quite complex. This complexity is also causing significant friction to
implementing structured all.bash output.
As of this CL, the whole host test mechanism runs a total of 10 test
cases on a total of two builders (android-{386,amd64}-emu). There are
clearly several tests that are incorrectly being skipped, so we could
expand it to cover more test cases, but it would still apply to only
two builders. Furthermore, the two other Android builders
(android-{arm,arm64}-corellium) build the Go toolchain directly inside
Android and also have access to a C toolchain, so they are able to get
significantly better test coverage without the use of host tests. This
suggests that the android-*-emu builders could do the same. All of
these tests are cgo-related, so they don't run on the wasm hosts
anyway.
Given the incredibly low value of host tests today, they are not worth
their implementation complexity and the friction they cause. Hence,
this CL drops support for host tests. (This was also the last use of
rtSequential, so we drop support for sequential tests, too.)
Fixes #59999.
Change-Id: I3eaca853a8907abc8247709f15a0d19a872dd22d
Reviewed-on: https://go-review.googlesource.com/c/go/+/492986
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2023-05-05 13:52:31 -04:00
|
|
|
testenv.MustHaveGoBuild(t)
|
2023-04-26 12:16:26 -04:00
|
|
|
testenv.MustHaveCGO(t)
|
|
|
|
|
testenv.MustHaveBuildMode(t, "c-archive")
|
2016-06-16 12:59:09 -07:00
|
|
|
|
2022-07-11 13:06:56 -04:00
|
|
|
libgoa := "libgo.a"
|
|
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
|
libgoa = "liblibgo.a"
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
if !testWork {
|
|
|
|
|
defer func() {
|
|
|
|
|
os.Remove("testp" + exeSuffix)
|
2022-07-11 13:06:56 -04:00
|
|
|
os.Remove(libgoa)
|
2019-11-20 10:19:43 -05:00
|
|
|
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
|
|
|
|
|
}()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generate the p.h header file.
|
|
|
|
|
//
|
|
|
|
|
// 'go install -i -buildmode=c-archive ./libgo' would do that too, but that
|
|
|
|
|
// would also attempt to install transitive standard-library dependencies to
|
|
|
|
|
// GOROOT, and we cannot assume that GOROOT is writable. (A non-root user may
|
|
|
|
|
// be running this test in a GOROOT owned by root.)
|
|
|
|
|
genHeader(t, "p.h", "./p")
|
2016-06-16 12:59:09 -07:00
|
|
|
|
2025-02-24 10:21:01 +01:00
|
|
|
cmd := exec.Command(testenv.GoToolPath(t), "build", "-buildmode=c-archive", "./libgo")
|
2016-06-16 12:59:09 -07:00
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-11 13:06:56 -04:00
|
|
|
ccArgs := append(cc, "-fPIE", "-pie", "-o", "testp"+exeSuffix, "main.c", "main_unix.c", libgoa)
|
2017-02-24 15:46:40 -08:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
|
}
|
2016-06-16 12:59:09 -07:00
|
|
|
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
|
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
binArgs := append(bin, "arg1", "arg2")
|
2017-02-24 15:46:40 -08:00
|
|
|
cmd = exec.Command(binArgs[0], binArgs[1:]...)
|
|
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
|
cmd.Env = append(os.Environ(), "GCCGO=1")
|
|
|
|
|
}
|
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
2016-06-16 12:59:09 -07:00
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-25 10:34:57 +01:00
|
|
|
if GOOS != "aix" {
|
|
|
|
|
f, err := elf.Open("testp" + exeSuffix)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal("elf.Open failed: ", err)
|
|
|
|
|
}
|
|
|
|
|
defer f.Close()
|
|
|
|
|
if hasDynTag(t, f, elf.DT_TEXTREL) {
|
|
|
|
|
t.Errorf("%s has DT_TEXTREL flag", "testp"+exeSuffix)
|
|
|
|
|
}
|
2016-06-16 12:59:09 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func hasDynTag(t *testing.T, f *elf.File, tag elf.DynTag) bool {
|
|
|
|
|
ds := f.SectionByType(elf.SHT_DYNAMIC)
|
|
|
|
|
if ds == nil {
|
|
|
|
|
t.Error("no SHT_DYNAMIC section")
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
d, err := ds.Data()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("can't read SHT_DYNAMIC contents: %v", err)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
for len(d) > 0 {
|
|
|
|
|
var t elf.DynTag
|
|
|
|
|
switch f.Class {
|
|
|
|
|
case elf.ELFCLASS32:
|
|
|
|
|
t = elf.DynTag(f.ByteOrder.Uint32(d[:4]))
|
|
|
|
|
d = d[8:]
|
|
|
|
|
case elf.ELFCLASS64:
|
|
|
|
|
t = elf.DynTag(f.ByteOrder.Uint64(d[:8]))
|
|
|
|
|
d = d[16:]
|
|
|
|
|
}
|
|
|
|
|
if t == tag {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
2016-12-06 20:54:41 -08:00
|
|
|
|
|
|
|
|
func TestSIGPROF(t *testing.T) {
|
|
|
|
|
switch GOOS {
|
|
|
|
|
case "windows", "plan9":
|
|
|
|
|
t.Skipf("skipping SIGPROF test on %s", GOOS)
|
2020-09-16 16:59:58 -04:00
|
|
|
case "darwin", "ios":
|
2017-10-08 16:53:18 +02:00
|
|
|
t.Skipf("skipping SIGPROF test on %s; see https://golang.org/issue/19320", GOOS)
|
2016-12-06 20:54:41 -08:00
|
|
|
}
|
2023-05-22 15:19:49 -04:00
|
|
|
globalSkip(t)
|
cmd/dist: drop host test support
Host tests are used for emulated builders that use cross-compilation.
Today, this is the android-{386,amd64}-emu builders and all wasm
builders. These builders run all.bash on a linux/amd64 host to build
all packages and most tests for the emulated guest, and then run the
resulting test binaries inside the emulated guest. A small number of
test packages are “host tests”: these run on the host rather than the
guest because they invoke the Go toolchain themselves (which only
lives on the host) and run the resulting binaries in the guest.
However, this host test mechanism is barely used today, despite being
quite complex. This complexity is also causing significant friction to
implementing structured all.bash output.
As of this CL, the whole host test mechanism runs a total of 10 test
cases on a total of two builders (android-{386,amd64}-emu). There are
clearly several tests that are incorrectly being skipped, so we could
expand it to cover more test cases, but it would still apply to only
two builders. Furthermore, the two other Android builders
(android-{arm,arm64}-corellium) build the Go toolchain directly inside
Android and also have access to a C toolchain, so they are able to get
significantly better test coverage without the use of host tests. This
suggests that the android-*-emu builders could do the same. All of
these tests are cgo-related, so they don't run on the wasm hosts
anyway.
Given the incredibly low value of host tests today, they are not worth
their implementation complexity and the friction they cause. Hence,
this CL drops support for host tests. (This was also the last use of
rtSequential, so we drop support for sequential tests, too.)
Fixes #59999.
Change-Id: I3eaca853a8907abc8247709f15a0d19a872dd22d
Reviewed-on: https://go-review.googlesource.com/c/go/+/492986
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2023-05-05 13:52:31 -04:00
|
|
|
testenv.MustHaveGoBuild(t)
|
2023-04-26 12:16:26 -04:00
|
|
|
testenv.MustHaveCGO(t)
|
|
|
|
|
testenv.MustHaveBuildMode(t, "c-archive")
|
2016-12-06 20:54:41 -08:00
|
|
|
|
|
|
|
|
t.Parallel()
|
|
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
if !testWork {
|
|
|
|
|
defer func() {
|
|
|
|
|
os.Remove("testp6" + exeSuffix)
|
|
|
|
|
os.Remove("libgo6.a")
|
|
|
|
|
os.Remove("libgo6.h")
|
|
|
|
|
}()
|
|
|
|
|
}
|
2016-12-06 20:54:41 -08:00
|
|
|
|
2025-02-24 10:21:01 +01:00
|
|
|
cmd := exec.Command(testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-o", "libgo6.a", "./libgo6")
|
2021-12-03 10:33:02 -05:00
|
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
|
t.Logf("%v\n%s", cmd.Args, out)
|
|
|
|
|
if err != nil {
|
2016-12-06 20:54:41 -08:00
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
2018-04-19 12:56:29 -07:00
|
|
|
checkLineComments(t, "libgo6.h")
|
2021-12-21 10:00:23 -08:00
|
|
|
checkArchive(t, "libgo6.a")
|
2016-12-06 20:54:41 -08:00
|
|
|
|
|
|
|
|
ccArgs := append(cc, "-o", "testp6"+exeSuffix, "main6.c", "libgo6.a")
|
2017-02-24 15:46:40 -08:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
|
}
|
2021-12-03 10:33:02 -05:00
|
|
|
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
|
|
|
|
t.Logf("%v\n%s", ccArgs, out)
|
|
|
|
|
if err != nil {
|
2016-12-06 20:54:41 -08:00
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
argv := cmdToRun("./testp6")
|
|
|
|
|
cmd = exec.Command(argv[0], argv[1:]...)
|
2021-12-03 10:33:02 -05:00
|
|
|
out, err = cmd.CombinedOutput()
|
|
|
|
|
t.Logf("%v\n%s", argv, out)
|
|
|
|
|
if err != nil {
|
2016-12-06 20:54:41 -08:00
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-09 14:34:16 -07:00
|
|
|
|
|
|
|
|
// TestCompileWithoutShared tests that if we compile code without the
|
|
|
|
|
// -shared option, we can put it into an archive. When we use the go
|
|
|
|
|
// tool with -buildmode=c-archive, it passes -shared to the compiler,
|
|
|
|
|
// so we override that. The go tool doesn't work this way, but Bazel
|
|
|
|
|
// will likely do it in the future. And it ought to work. This test
|
2021-04-12 19:05:01 -07:00
|
|
|
// was added because at one time it did not work on PPC Linux.
|
2017-05-09 14:34:16 -07:00
|
|
|
func TestCompileWithoutShared(t *testing.T) {
|
2023-05-22 15:19:49 -04:00
|
|
|
globalSkip(t)
|
2017-05-09 14:34:16 -07:00
|
|
|
// For simplicity, reuse the signal forwarding test.
|
|
|
|
|
checkSignalForwardingTest(t)
|
cmd/dist: drop host test support
Host tests are used for emulated builders that use cross-compilation.
Today, this is the android-{386,amd64}-emu builders and all wasm
builders. These builders run all.bash on a linux/amd64 host to build
all packages and most tests for the emulated guest, and then run the
resulting test binaries inside the emulated guest. A small number of
test packages are “host tests”: these run on the host rather than the
guest because they invoke the Go toolchain themselves (which only
lives on the host) and run the resulting binaries in the guest.
However, this host test mechanism is barely used today, despite being
quite complex. This complexity is also causing significant friction to
implementing structured all.bash output.
As of this CL, the whole host test mechanism runs a total of 10 test
cases on a total of two builders (android-{386,amd64}-emu). There are
clearly several tests that are incorrectly being skipped, so we could
expand it to cover more test cases, but it would still apply to only
two builders. Furthermore, the two other Android builders
(android-{arm,arm64}-corellium) build the Go toolchain directly inside
Android and also have access to a C toolchain, so they are able to get
significantly better test coverage without the use of host tests. This
suggests that the android-*-emu builders could do the same. All of
these tests are cgo-related, so they don't run on the wasm hosts
anyway.
Given the incredibly low value of host tests today, they are not worth
their implementation complexity and the friction they cause. Hence,
this CL drops support for host tests. (This was also the last use of
rtSequential, so we drop support for sequential tests, too.)
Fixes #59999.
Change-Id: I3eaca853a8907abc8247709f15a0d19a872dd22d
Reviewed-on: https://go-review.googlesource.com/c/go/+/492986
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2023-05-05 13:52:31 -04:00
|
|
|
testenv.MustHaveGoBuild(t)
|
2017-05-09 14:34:16 -07:00
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
if !testWork {
|
|
|
|
|
defer func() {
|
|
|
|
|
os.Remove("libgo2.a")
|
|
|
|
|
os.Remove("libgo2.h")
|
|
|
|
|
}()
|
|
|
|
|
}
|
2017-05-09 14:34:16 -07:00
|
|
|
|
2025-02-24 10:21:01 +01:00
|
|
|
cmd := exec.Command(testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-gcflags=-shared=false", "-o", "libgo2.a", "./libgo2")
|
2017-05-09 14:34:16 -07:00
|
|
|
out, err := cmd.CombinedOutput()
|
2021-12-03 10:33:02 -05:00
|
|
|
t.Logf("%v\n%s", cmd.Args, out)
|
2017-05-09 14:34:16 -07:00
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
2018-04-19 12:56:29 -07:00
|
|
|
checkLineComments(t, "libgo2.h")
|
2021-12-21 10:00:23 -08:00
|
|
|
checkArchive(t, "libgo2.a")
|
2017-05-09 14:34:16 -07:00
|
|
|
|
|
|
|
|
exe := "./testnoshared" + exeSuffix
|
2017-10-11 16:02:59 -04:00
|
|
|
|
|
|
|
|
// In some cases, -no-pie is needed here, but not accepted everywhere. First try
|
|
|
|
|
// if -no-pie is accepted. See #22126.
|
|
|
|
|
ccArgs := append(cc, "-o", exe, "-no-pie", "main5.c", "libgo2.a")
|
2017-02-24 15:46:40 -08:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
|
}
|
2017-05-09 14:34:16 -07:00
|
|
|
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
2021-12-03 10:33:02 -05:00
|
|
|
t.Logf("%v\n%s", ccArgs, out)
|
2017-10-11 16:02:59 -04:00
|
|
|
|
|
|
|
|
// If -no-pie unrecognized, try -nopie if this is possibly clang
|
|
|
|
|
if err != nil && bytes.Contains(out, []byte("unknown")) && !strings.Contains(cc[0], "gcc") {
|
|
|
|
|
ccArgs = append(cc, "-o", exe, "-nopie", "main5.c", "libgo2.a")
|
|
|
|
|
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
2021-12-03 10:33:02 -05:00
|
|
|
t.Logf("%v\n%s", ccArgs, out)
|
2017-10-11 16:02:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Don't use either -no-pie or -nopie
|
|
|
|
|
if err != nil && bytes.Contains(out, []byte("unrecognized")) {
|
2021-12-03 10:33:02 -05:00
|
|
|
ccArgs = append(cc, "-o", exe, "main5.c", "libgo2.a")
|
2017-10-11 16:02:59 -04:00
|
|
|
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
2021-12-03 10:33:02 -05:00
|
|
|
t.Logf("%v\n%s", ccArgs, out)
|
2017-10-11 16:02:59 -04:00
|
|
|
}
|
2017-05-09 14:34:16 -07:00
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
2019-11-20 10:19:43 -05:00
|
|
|
if !testWork {
|
|
|
|
|
defer os.Remove(exe)
|
|
|
|
|
}
|
2017-05-09 14:34:16 -07:00
|
|
|
|
2019-07-31 14:33:57 +02:00
|
|
|
binArgs := append(cmdToRun(exe), "1")
|
2017-05-09 14:34:16 -07:00
|
|
|
out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput()
|
2021-12-03 10:33:02 -05:00
|
|
|
t.Logf("%v\n%s", binArgs, out)
|
2022-08-19 14:43:47 -07:00
|
|
|
expectSignal(t, err, syscall.SIGSEGV, 0)
|
2019-07-31 14:33:57 +02:00
|
|
|
|
|
|
|
|
// SIGPIPE is never forwarded on darwin. See golang.org/issue/33384.
|
2020-09-16 16:59:58 -04:00
|
|
|
if runtime.GOOS != "darwin" && runtime.GOOS != "ios" {
|
2019-07-31 14:33:57 +02:00
|
|
|
binArgs := append(cmdToRun(exe), "3")
|
|
|
|
|
out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput()
|
2021-12-03 10:33:02 -05:00
|
|
|
t.Logf("%v\n%s", binArgs, out)
|
2022-08-19 14:43:47 -07:00
|
|
|
expectSignal(t, err, syscall.SIGPIPE, 0)
|
2019-07-31 14:33:57 +02:00
|
|
|
}
|
2017-05-09 14:34:16 -07:00
|
|
|
}
|
2018-01-10 17:48:37 -08:00
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
// Test that installing a second time recreates the header file.
|
2018-01-10 17:48:37 -08:00
|
|
|
func TestCachedInstall(t *testing.T) {
|
2023-05-22 15:19:49 -04:00
|
|
|
globalSkip(t)
|
cmd/dist: drop host test support
Host tests are used for emulated builders that use cross-compilation.
Today, this is the android-{386,amd64}-emu builders and all wasm
builders. These builders run all.bash on a linux/amd64 host to build
all packages and most tests for the emulated guest, and then run the
resulting test binaries inside the emulated guest. A small number of
test packages are “host tests”: these run on the host rather than the
guest because they invoke the Go toolchain themselves (which only
lives on the host) and run the resulting binaries in the guest.
However, this host test mechanism is barely used today, despite being
quite complex. This complexity is also causing significant friction to
implementing structured all.bash output.
As of this CL, the whole host test mechanism runs a total of 10 test
cases on a total of two builders (android-{386,amd64}-emu). There are
clearly several tests that are incorrectly being skipped, so we could
expand it to cover more test cases, but it would still apply to only
two builders. Furthermore, the two other Android builders
(android-{arm,arm64}-corellium) build the Go toolchain directly inside
Android and also have access to a C toolchain, so they are able to get
significantly better test coverage without the use of host tests. This
suggests that the android-*-emu builders could do the same. All of
these tests are cgo-related, so they don't run on the wasm hosts
anyway.
Given the incredibly low value of host tests today, they are not worth
their implementation complexity and the friction they cause. Hence,
this CL drops support for host tests. (This was also the last use of
rtSequential, so we drop support for sequential tests, too.)
Fixes #59999.
Change-Id: I3eaca853a8907abc8247709f15a0d19a872dd22d
Reviewed-on: https://go-review.googlesource.com/c/go/+/492986
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2023-05-05 13:52:31 -04:00
|
|
|
testenv.MustHaveGoBuild(t)
|
2023-04-26 12:16:26 -04:00
|
|
|
testenv.MustHaveCGO(t)
|
|
|
|
|
testenv.MustHaveBuildMode(t, "c-archive")
|
|
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
if !testWork {
|
|
|
|
|
defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
|
|
|
|
|
}
|
2018-01-10 17:48:37 -08:00
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
h := filepath.Join(libgodir, "libgo.h")
|
2018-01-10 17:48:37 -08:00
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
buildcmd := []string{"go", "install", "-buildmode=c-archive", "./libgo"}
|
2018-01-10 17:48:37 -08:00
|
|
|
|
|
|
|
|
cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
|
2022-07-11 13:06:56 -04:00
|
|
|
cmd.Env = append(cmd.Environ(), "GO111MODULE=off") // 'go install' only works in GOPATH mode
|
2018-01-10 17:48:37 -08:00
|
|
|
t.Log(buildcmd)
|
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
if _, err := os.Stat(h); err != nil {
|
2018-01-10 17:48:37 -08:00
|
|
|
t.Errorf("libgo.h not installed: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
if err := os.Remove(h); err != nil {
|
2018-01-10 17:48:37 -08:00
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd = exec.Command(buildcmd[0], buildcmd[1:]...)
|
2022-07-11 13:06:56 -04:00
|
|
|
cmd.Env = append(cmd.Environ(), "GO111MODULE=off")
|
2018-01-10 17:48:37 -08:00
|
|
|
t.Log(buildcmd)
|
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
|
t.Logf("%s", out)
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
if _, err := os.Stat(h); err != nil {
|
2018-01-10 17:48:37 -08:00
|
|
|
t.Errorf("libgo.h not installed in second run: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-01 17:53:53 -07:00
|
|
|
|
|
|
|
|
// Issue 35294.
|
|
|
|
|
func TestManyCalls(t *testing.T) {
|
2023-05-22 15:19:49 -04:00
|
|
|
globalSkip(t)
|
cmd/dist: drop host test support
Host tests are used for emulated builders that use cross-compilation.
Today, this is the android-{386,amd64}-emu builders and all wasm
builders. These builders run all.bash on a linux/amd64 host to build
all packages and most tests for the emulated guest, and then run the
resulting test binaries inside the emulated guest. A small number of
test packages are “host tests”: these run on the host rather than the
guest because they invoke the Go toolchain themselves (which only
lives on the host) and run the resulting binaries in the guest.
However, this host test mechanism is barely used today, despite being
quite complex. This complexity is also causing significant friction to
implementing structured all.bash output.
As of this CL, the whole host test mechanism runs a total of 10 test
cases on a total of two builders (android-{386,amd64}-emu). There are
clearly several tests that are incorrectly being skipped, so we could
expand it to cover more test cases, but it would still apply to only
two builders. Furthermore, the two other Android builders
(android-{arm,arm64}-corellium) build the Go toolchain directly inside
Android and also have access to a C toolchain, so they are able to get
significantly better test coverage without the use of host tests. This
suggests that the android-*-emu builders could do the same. All of
these tests are cgo-related, so they don't run on the wasm hosts
anyway.
Given the incredibly low value of host tests today, they are not worth
their implementation complexity and the friction they cause. Hence,
this CL drops support for host tests. (This was also the last use of
rtSequential, so we drop support for sequential tests, too.)
Fixes #59999.
Change-Id: I3eaca853a8907abc8247709f15a0d19a872dd22d
Reviewed-on: https://go-review.googlesource.com/c/go/+/492986
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2023-05-05 13:52:31 -04:00
|
|
|
testenv.MustHaveGoBuild(t)
|
2023-04-26 12:16:26 -04:00
|
|
|
testenv.MustHaveCGO(t)
|
|
|
|
|
testenv.MustHaveBuildMode(t, "c-archive")
|
|
|
|
|
|
2019-11-01 17:53:53 -07:00
|
|
|
t.Parallel()
|
|
|
|
|
|
2019-11-20 10:19:43 -05:00
|
|
|
if !testWork {
|
|
|
|
|
defer func() {
|
|
|
|
|
os.Remove("testp7" + exeSuffix)
|
|
|
|
|
os.Remove("libgo7.a")
|
|
|
|
|
os.Remove("libgo7.h")
|
|
|
|
|
}()
|
|
|
|
|
}
|
2019-11-01 17:53:53 -07:00
|
|
|
|
2025-02-24 10:21:01 +01:00
|
|
|
cmd := exec.Command(testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-o", "libgo7.a", "./libgo7")
|
2021-12-03 10:33:02 -05:00
|
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
|
t.Logf("%v\n%s", cmd.Args, out)
|
|
|
|
|
if err != nil {
|
2019-11-01 17:53:53 -07:00
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
checkLineComments(t, "libgo7.h")
|
2021-12-21 10:00:23 -08:00
|
|
|
checkArchive(t, "libgo7.a")
|
2019-11-01 17:53:53 -07:00
|
|
|
|
|
|
|
|
ccArgs := append(cc, "-o", "testp7"+exeSuffix, "main7.c", "libgo7.a")
|
|
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
|
}
|
2021-12-03 10:33:02 -05:00
|
|
|
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
|
|
|
|
t.Logf("%v\n%s", ccArgs, out)
|
|
|
|
|
if err != nil {
|
2019-11-01 17:53:53 -07:00
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
argv := cmdToRun("./testp7")
|
2024-07-17 14:34:00 -04:00
|
|
|
cmd = testenv.Command(t, argv[0], argv[1:]...)
|
2021-12-03 10:33:02 -05:00
|
|
|
sb := new(strings.Builder)
|
|
|
|
|
cmd.Stdout = sb
|
|
|
|
|
cmd.Stderr = sb
|
2019-11-01 17:53:53 -07:00
|
|
|
if err := cmd.Start(); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-03 10:33:02 -05:00
|
|
|
err = cmd.Wait()
|
|
|
|
|
t.Logf("%v\n%s", cmd.Args, sb)
|
|
|
|
|
if err != nil {
|
2019-11-01 17:53:53 -07:00
|
|
|
t.Error(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-11-02 14:12:05 -07:00
|
|
|
|
|
|
|
|
// Issue 49288.
|
|
|
|
|
func TestPreemption(t *testing.T) {
|
|
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
|
t.Skip("skipping asynchronous preemption test with gccgo")
|
|
|
|
|
}
|
2023-05-22 15:19:49 -04:00
|
|
|
globalSkip(t)
|
cmd/dist: drop host test support
Host tests are used for emulated builders that use cross-compilation.
Today, this is the android-{386,amd64}-emu builders and all wasm
builders. These builders run all.bash on a linux/amd64 host to build
all packages and most tests for the emulated guest, and then run the
resulting test binaries inside the emulated guest. A small number of
test packages are “host tests”: these run on the host rather than the
guest because they invoke the Go toolchain themselves (which only
lives on the host) and run the resulting binaries in the guest.
However, this host test mechanism is barely used today, despite being
quite complex. This complexity is also causing significant friction to
implementing structured all.bash output.
As of this CL, the whole host test mechanism runs a total of 10 test
cases on a total of two builders (android-{386,amd64}-emu). There are
clearly several tests that are incorrectly being skipped, so we could
expand it to cover more test cases, but it would still apply to only
two builders. Furthermore, the two other Android builders
(android-{arm,arm64}-corellium) build the Go toolchain directly inside
Android and also have access to a C toolchain, so they are able to get
significantly better test coverage without the use of host tests. This
suggests that the android-*-emu builders could do the same. All of
these tests are cgo-related, so they don't run on the wasm hosts
anyway.
Given the incredibly low value of host tests today, they are not worth
their implementation complexity and the friction they cause. Hence,
this CL drops support for host tests. (This was also the last use of
rtSequential, so we drop support for sequential tests, too.)
Fixes #59999.
Change-Id: I3eaca853a8907abc8247709f15a0d19a872dd22d
Reviewed-on: https://go-review.googlesource.com/c/go/+/492986
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2023-05-05 13:52:31 -04:00
|
|
|
testenv.MustHaveGoBuild(t)
|
2023-04-26 12:16:26 -04:00
|
|
|
testenv.MustHaveCGO(t)
|
|
|
|
|
testenv.MustHaveBuildMode(t, "c-archive")
|
2021-11-02 14:12:05 -07:00
|
|
|
|
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
|
|
if !testWork {
|
|
|
|
|
defer func() {
|
|
|
|
|
os.Remove("testp8" + exeSuffix)
|
|
|
|
|
os.Remove("libgo8.a")
|
|
|
|
|
os.Remove("libgo8.h")
|
|
|
|
|
}()
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-24 10:21:01 +01:00
|
|
|
cmd := exec.Command(testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-o", "libgo8.a", "./libgo8")
|
2021-12-03 10:33:02 -05:00
|
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
|
t.Logf("%v\n%s", cmd.Args, out)
|
|
|
|
|
if err != nil {
|
2021-11-02 14:12:05 -07:00
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
checkLineComments(t, "libgo8.h")
|
2021-12-21 10:00:23 -08:00
|
|
|
checkArchive(t, "libgo8.a")
|
2021-11-02 14:12:05 -07:00
|
|
|
|
|
|
|
|
ccArgs := append(cc, "-o", "testp8"+exeSuffix, "main8.c", "libgo8.a")
|
2021-12-03 10:33:02 -05:00
|
|
|
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
|
|
|
|
t.Logf("%v\n%s", ccArgs, out)
|
|
|
|
|
if err != nil {
|
2021-11-02 14:12:05 -07:00
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
argv := cmdToRun("./testp8")
|
2024-07-17 14:34:00 -04:00
|
|
|
cmd = testenv.Command(t, argv[0], argv[1:]...)
|
2021-12-03 10:33:02 -05:00
|
|
|
sb := new(strings.Builder)
|
|
|
|
|
cmd.Stdout = sb
|
|
|
|
|
cmd.Stderr = sb
|
2021-11-02 14:12:05 -07:00
|
|
|
if err := cmd.Start(); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-03 10:33:02 -05:00
|
|
|
err = cmd.Wait()
|
|
|
|
|
t.Logf("%v\n%s", cmd.Args, sb)
|
|
|
|
|
if err != nil {
|
2021-11-02 14:12:05 -07:00
|
|
|
t.Error(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
runtime/cgo: store M for C-created thread in pthread key
This reapplies CL 485500, with a fix drafted in CL 492987 incorporated.
CL 485500 is reverted due to #60004 and #60007. #60004 is fixed in
CL 492743. #60007 is fixed in CL 492987 (incorporated in this CL).
[Original CL 485500 description]
This reapplies CL 481061, with the followup fixes in CL 482975, CL 485315, and
CL 485316 incorporated.
CL 481061, by doujiang24 <doujiang24@gmail.com>, speed up C to Go
calls by binding the M to the C thread. See below for its
description.
CL 482975 is a followup fix to a C declaration in testprogcgo.
CL 485315 is a followup fix for x_cgo_getstackbound on Illumos.
CL 485316 is a followup cleanup for ppc64 assembly.
CL 479915 passed the G to _cgo_getstackbound for direct updates to
gp.stack.lo. A G can be reused on a new thread after the previous thread
exited. This could trigger the C TSAN race detector because it couldn't
see the synchronization in Go (lockextra) preventing the same G from
being used on multiple threads at the same time.
We work around this by passing the address of a stack variable to
_cgo_getstackbound rather than the G. The stack is generally unique per
thread, so TSAN won't see the same address from multiple threads. Even
if stacks are reused across threads by pthread, C TSAN should see the
synchonization in the stack allocator.
A regression test is added to misc/cgo/testsanitizer.
[Original CL 481061 description]
This reapplies CL 392854, with the followup fixes in CL 479255,
CL 479915, and CL 481057 incorporated.
CL 392854, by doujiang24 <doujiang24@gmail.com>, speed up C to Go
calls by binding the M to the C thread. See below for its
description.
CL 479255 is a followup fix for a small bug in ARM assembly code.
CL 479915 is another followup fix to address C to Go calls after
the C code uses some stack, but that CL is also buggy.
CL 481057, by Michael Knyszek, is a followup fix for a memory leak
bug of CL 479915.
[Original CL 392854 description]
In a C thread, it's necessary to acquire an extra M by using needm while invoking a Go function from C. But, needm and dropm are heavy costs due to the signal-related syscalls.
So, we change to not dropm while returning back to C, which means binding the extra M to the C thread until it exits, to avoid needm and dropm on each C to Go call.
Instead, we only dropm while the C thread exits, so the extra M won't leak.
When invoking a Go function from C:
Allocate a pthread variable using pthread_key_create, only once per shared object, and register a thread-exit-time destructor.
And store the g0 of the current m into the thread-specified value of the pthread key, only once per C thread, so that the destructor will put the extra M back onto the extra M list while the C thread exits.
When returning back to C:
Skip dropm in cgocallback, when the pthread variable has been created, so that the extra M will be reused the next time invoke a Go function from C.
This is purely a performance optimization. The old version, in which needm & dropm happen on each cgo call, is still correct too, and we have to keep the old version on systems with cgo but without pthreads, like Windows.
This optimization is significant, and the specific value depends on the OS system and CPU, but in general, it can be considered as 10x faster, for a simple Go function call from a C thread.
For the newly added BenchmarkCGoInCThread, some benchmark results:
1. it's 28x faster, from 3395 ns/op to 121 ns/op, in darwin OS & Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
2. it's 6.5x faster, from 1495 ns/op to 230 ns/op, in Linux OS & Intel(R) Xeon(R) CPU E5-2630 0 @ 2.30GHz
[CL 479915 description]
Currently, when C calls into Go the first time, we grab an M
using needm, which sets m.g0's stack bounds using the SP. We don't
know how big the stack is, so we simply assume 32K. Previously,
when the Go function returns to C, we drop the M, and the next
time C calls into Go, we put a new stack bound on the g0 based on
the current SP. After CL 392854, we don't drop the M, and the next
time C calls into Go, we reuse the same g0, without recomputing
the stack bounds. If the C code uses quite a bit of stack space
before calling into Go, the SP may be well below the 32K stack
bound we assumed, so the runtime thinks the g0 stack overflows.
This CL makes needm get a more accurate stack bound from
pthread. (In some platforms this may still be a guess as we don't
know exactly where we are in the C stack), but it is probably
better than simply assuming 32K.
[CL 492987 description]
On the first call into Go from a C thread, currently we set the g0
stack's high bound imprecisely based on the SP. With CL 485500, we
keep the M and don't recompute the stack bounds when it calls into
Go again. If the first call is made when the C thread uses some
deep stack, but a subsequent call is made with a shallower stack,
the SP may be above g0.stack.hi.
This is usually okay as we don't check usually stack.hi. One place
where we do check for stack.hi is in the signal handler, in
adjustSignalStack. In particular, C TSAN delivers signals on the
g0 stack (instead of the usual signal stack). If the SP is above
g0.stack.hi, we don't see it is on the g0 stack, and throws.
This CL makes it get an accurate stack upper bound with the
pthread API (on the platforms where it is available).
Also add some debug print for the "handler not on signal stack"
throw.
Fixes #51676.
Fixes #59294.
Fixes #59678.
Fixes #60007.
Change-Id: Ie51c8e81ade34ec81d69fd7bce1fe0039a470776
Reviewed-on: https://go-review.googlesource.com/c/go/+/495855
Run-TryBot: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Michael Pratt <mpratt@google.com>
2023-05-17 12:01:15 -04:00
|
|
|
|
runtime: update and restore g0 stack bounds at cgocallback
Currently, at a cgo callback where there is already a Go frame on
the stack (i.e. C->Go->C->Go), we require that at the inner Go
callback the SP is within the g0's stack bounds set by a previous
callback. This is to prevent that the C code switches stack while
having a Go frame on the stack, which we don't really support. But
this could also happen when we cannot get accurate stack bounds,
e.g. when pthread_getattr_np is not available. Since the stack
bounds are just estimates based on the current SP, if there are
multiple C->Go callbacks with various stack depth, it is possible
that the SP of a later callback falls out of a previous call's
estimate. This leads to runtime throw in a seemingly reasonable
program.
This CL changes it to save the old g0 stack bounds at cgocallback,
update the bounds, and restore the old bounds at return. So each
callback will get its own stack bounds based on the current SP,
and when it returns, the outer callback has the its old stack
bounds restored.
Also, at a cgo callback when there is no Go frame on the stack,
we currently always get new stack bounds. We do this because if
we can only get estimated bounds based on the SP, and the stack
depth varies a lot between two C->Go calls, the previous
estimates may be off and we fall out or nearly fall out of the
previous bounds. But this causes a performance problem: the
pthread API to get accurate stack bounds (pthread_getattr_np) is
very slow when called on the main thread. Getting the stack bounds
every time significantly slows down repeated C->Go calls on the
main thread.
This CL fixes it by "caching" the stack bounds if they are
accurate. I.e. at the second time Go calls into C, if the previous
stack bounds are accurate, and the current SP is in bounds, we can
be sure it is the same stack and we don't need to update the bounds.
This avoids the repeated calls to pthread_getattr_np. If we cannot
get the accurate bounds, we continue to update the stack bounds
based on the SP, and that operation is very cheap.
On a Linux/AMD64 machine with glibc:
name old time/op new time/op delta
CgoCallbackMainThread-8 96.4µs ± 3% 0.1µs ± 2% -99.92% (p=0.000 n=10+9)
Fixes #68285.
Fixes #68587.
Change-Id: I3422badd5ad8ff63e1a733152d05fb7a44d5d435
Reviewed-on: https://go-review.googlesource.com/c/go/+/600296
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
2024-07-22 16:23:43 -04:00
|
|
|
// Issue 59294 and 68285. Test calling Go function from C after with
|
|
|
|
|
// various stack space.
|
runtime/cgo: store M for C-created thread in pthread key
This reapplies CL 485500, with a fix drafted in CL 492987 incorporated.
CL 485500 is reverted due to #60004 and #60007. #60004 is fixed in
CL 492743. #60007 is fixed in CL 492987 (incorporated in this CL).
[Original CL 485500 description]
This reapplies CL 481061, with the followup fixes in CL 482975, CL 485315, and
CL 485316 incorporated.
CL 481061, by doujiang24 <doujiang24@gmail.com>, speed up C to Go
calls by binding the M to the C thread. See below for its
description.
CL 482975 is a followup fix to a C declaration in testprogcgo.
CL 485315 is a followup fix for x_cgo_getstackbound on Illumos.
CL 485316 is a followup cleanup for ppc64 assembly.
CL 479915 passed the G to _cgo_getstackbound for direct updates to
gp.stack.lo. A G can be reused on a new thread after the previous thread
exited. This could trigger the C TSAN race detector because it couldn't
see the synchronization in Go (lockextra) preventing the same G from
being used on multiple threads at the same time.
We work around this by passing the address of a stack variable to
_cgo_getstackbound rather than the G. The stack is generally unique per
thread, so TSAN won't see the same address from multiple threads. Even
if stacks are reused across threads by pthread, C TSAN should see the
synchonization in the stack allocator.
A regression test is added to misc/cgo/testsanitizer.
[Original CL 481061 description]
This reapplies CL 392854, with the followup fixes in CL 479255,
CL 479915, and CL 481057 incorporated.
CL 392854, by doujiang24 <doujiang24@gmail.com>, speed up C to Go
calls by binding the M to the C thread. See below for its
description.
CL 479255 is a followup fix for a small bug in ARM assembly code.
CL 479915 is another followup fix to address C to Go calls after
the C code uses some stack, but that CL is also buggy.
CL 481057, by Michael Knyszek, is a followup fix for a memory leak
bug of CL 479915.
[Original CL 392854 description]
In a C thread, it's necessary to acquire an extra M by using needm while invoking a Go function from C. But, needm and dropm are heavy costs due to the signal-related syscalls.
So, we change to not dropm while returning back to C, which means binding the extra M to the C thread until it exits, to avoid needm and dropm on each C to Go call.
Instead, we only dropm while the C thread exits, so the extra M won't leak.
When invoking a Go function from C:
Allocate a pthread variable using pthread_key_create, only once per shared object, and register a thread-exit-time destructor.
And store the g0 of the current m into the thread-specified value of the pthread key, only once per C thread, so that the destructor will put the extra M back onto the extra M list while the C thread exits.
When returning back to C:
Skip dropm in cgocallback, when the pthread variable has been created, so that the extra M will be reused the next time invoke a Go function from C.
This is purely a performance optimization. The old version, in which needm & dropm happen on each cgo call, is still correct too, and we have to keep the old version on systems with cgo but without pthreads, like Windows.
This optimization is significant, and the specific value depends on the OS system and CPU, but in general, it can be considered as 10x faster, for a simple Go function call from a C thread.
For the newly added BenchmarkCGoInCThread, some benchmark results:
1. it's 28x faster, from 3395 ns/op to 121 ns/op, in darwin OS & Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
2. it's 6.5x faster, from 1495 ns/op to 230 ns/op, in Linux OS & Intel(R) Xeon(R) CPU E5-2630 0 @ 2.30GHz
[CL 479915 description]
Currently, when C calls into Go the first time, we grab an M
using needm, which sets m.g0's stack bounds using the SP. We don't
know how big the stack is, so we simply assume 32K. Previously,
when the Go function returns to C, we drop the M, and the next
time C calls into Go, we put a new stack bound on the g0 based on
the current SP. After CL 392854, we don't drop the M, and the next
time C calls into Go, we reuse the same g0, without recomputing
the stack bounds. If the C code uses quite a bit of stack space
before calling into Go, the SP may be well below the 32K stack
bound we assumed, so the runtime thinks the g0 stack overflows.
This CL makes needm get a more accurate stack bound from
pthread. (In some platforms this may still be a guess as we don't
know exactly where we are in the C stack), but it is probably
better than simply assuming 32K.
[CL 492987 description]
On the first call into Go from a C thread, currently we set the g0
stack's high bound imprecisely based on the SP. With CL 485500, we
keep the M and don't recompute the stack bounds when it calls into
Go again. If the first call is made when the C thread uses some
deep stack, but a subsequent call is made with a shallower stack,
the SP may be above g0.stack.hi.
This is usually okay as we don't check usually stack.hi. One place
where we do check for stack.hi is in the signal handler, in
adjustSignalStack. In particular, C TSAN delivers signals on the
g0 stack (instead of the usual signal stack). If the SP is above
g0.stack.hi, we don't see it is on the g0 stack, and throws.
This CL makes it get an accurate stack upper bound with the
pthread API (on the platforms where it is available).
Also add some debug print for the "handler not on signal stack"
throw.
Fixes #51676.
Fixes #59294.
Fixes #59678.
Fixes #60007.
Change-Id: Ie51c8e81ade34ec81d69fd7bce1fe0039a470776
Reviewed-on: https://go-review.googlesource.com/c/go/+/495855
Run-TryBot: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Michael Pratt <mpratt@google.com>
2023-05-17 12:01:15 -04:00
|
|
|
func TestDeepStack(t *testing.T) {
|
2023-05-22 15:19:49 -04:00
|
|
|
globalSkip(t)
|
2023-05-18 21:46:55 -04:00
|
|
|
testenv.MustHaveGoBuild(t)
|
|
|
|
|
testenv.MustHaveCGO(t)
|
|
|
|
|
testenv.MustHaveBuildMode(t, "c-archive")
|
|
|
|
|
|
runtime/cgo: store M for C-created thread in pthread key
This reapplies CL 485500, with a fix drafted in CL 492987 incorporated.
CL 485500 is reverted due to #60004 and #60007. #60004 is fixed in
CL 492743. #60007 is fixed in CL 492987 (incorporated in this CL).
[Original CL 485500 description]
This reapplies CL 481061, with the followup fixes in CL 482975, CL 485315, and
CL 485316 incorporated.
CL 481061, by doujiang24 <doujiang24@gmail.com>, speed up C to Go
calls by binding the M to the C thread. See below for its
description.
CL 482975 is a followup fix to a C declaration in testprogcgo.
CL 485315 is a followup fix for x_cgo_getstackbound on Illumos.
CL 485316 is a followup cleanup for ppc64 assembly.
CL 479915 passed the G to _cgo_getstackbound for direct updates to
gp.stack.lo. A G can be reused on a new thread after the previous thread
exited. This could trigger the C TSAN race detector because it couldn't
see the synchronization in Go (lockextra) preventing the same G from
being used on multiple threads at the same time.
We work around this by passing the address of a stack variable to
_cgo_getstackbound rather than the G. The stack is generally unique per
thread, so TSAN won't see the same address from multiple threads. Even
if stacks are reused across threads by pthread, C TSAN should see the
synchonization in the stack allocator.
A regression test is added to misc/cgo/testsanitizer.
[Original CL 481061 description]
This reapplies CL 392854, with the followup fixes in CL 479255,
CL 479915, and CL 481057 incorporated.
CL 392854, by doujiang24 <doujiang24@gmail.com>, speed up C to Go
calls by binding the M to the C thread. See below for its
description.
CL 479255 is a followup fix for a small bug in ARM assembly code.
CL 479915 is another followup fix to address C to Go calls after
the C code uses some stack, but that CL is also buggy.
CL 481057, by Michael Knyszek, is a followup fix for a memory leak
bug of CL 479915.
[Original CL 392854 description]
In a C thread, it's necessary to acquire an extra M by using needm while invoking a Go function from C. But, needm and dropm are heavy costs due to the signal-related syscalls.
So, we change to not dropm while returning back to C, which means binding the extra M to the C thread until it exits, to avoid needm and dropm on each C to Go call.
Instead, we only dropm while the C thread exits, so the extra M won't leak.
When invoking a Go function from C:
Allocate a pthread variable using pthread_key_create, only once per shared object, and register a thread-exit-time destructor.
And store the g0 of the current m into the thread-specified value of the pthread key, only once per C thread, so that the destructor will put the extra M back onto the extra M list while the C thread exits.
When returning back to C:
Skip dropm in cgocallback, when the pthread variable has been created, so that the extra M will be reused the next time invoke a Go function from C.
This is purely a performance optimization. The old version, in which needm & dropm happen on each cgo call, is still correct too, and we have to keep the old version on systems with cgo but without pthreads, like Windows.
This optimization is significant, and the specific value depends on the OS system and CPU, but in general, it can be considered as 10x faster, for a simple Go function call from a C thread.
For the newly added BenchmarkCGoInCThread, some benchmark results:
1. it's 28x faster, from 3395 ns/op to 121 ns/op, in darwin OS & Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
2. it's 6.5x faster, from 1495 ns/op to 230 ns/op, in Linux OS & Intel(R) Xeon(R) CPU E5-2630 0 @ 2.30GHz
[CL 479915 description]
Currently, when C calls into Go the first time, we grab an M
using needm, which sets m.g0's stack bounds using the SP. We don't
know how big the stack is, so we simply assume 32K. Previously,
when the Go function returns to C, we drop the M, and the next
time C calls into Go, we put a new stack bound on the g0 based on
the current SP. After CL 392854, we don't drop the M, and the next
time C calls into Go, we reuse the same g0, without recomputing
the stack bounds. If the C code uses quite a bit of stack space
before calling into Go, the SP may be well below the 32K stack
bound we assumed, so the runtime thinks the g0 stack overflows.
This CL makes needm get a more accurate stack bound from
pthread. (In some platforms this may still be a guess as we don't
know exactly where we are in the C stack), but it is probably
better than simply assuming 32K.
[CL 492987 description]
On the first call into Go from a C thread, currently we set the g0
stack's high bound imprecisely based on the SP. With CL 485500, we
keep the M and don't recompute the stack bounds when it calls into
Go again. If the first call is made when the C thread uses some
deep stack, but a subsequent call is made with a shallower stack,
the SP may be above g0.stack.hi.
This is usually okay as we don't check usually stack.hi. One place
where we do check for stack.hi is in the signal handler, in
adjustSignalStack. In particular, C TSAN delivers signals on the
g0 stack (instead of the usual signal stack). If the SP is above
g0.stack.hi, we don't see it is on the g0 stack, and throws.
This CL makes it get an accurate stack upper bound with the
pthread API (on the platforms where it is available).
Also add some debug print for the "handler not on signal stack"
throw.
Fixes #51676.
Fixes #59294.
Fixes #59678.
Fixes #60007.
Change-Id: Ie51c8e81ade34ec81d69fd7bce1fe0039a470776
Reviewed-on: https://go-review.googlesource.com/c/go/+/495855
Run-TryBot: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Michael Pratt <mpratt@google.com>
2023-05-17 12:01:15 -04:00
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
|
|
if !testWork {
|
|
|
|
|
defer func() {
|
|
|
|
|
os.Remove("testp9" + exeSuffix)
|
|
|
|
|
os.Remove("libgo9.a")
|
|
|
|
|
os.Remove("libgo9.h")
|
|
|
|
|
}()
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-24 10:21:01 +01:00
|
|
|
cmd := exec.Command(testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-o", "libgo9.a", "./libgo9")
|
runtime/cgo: store M for C-created thread in pthread key
This reapplies CL 485500, with a fix drafted in CL 492987 incorporated.
CL 485500 is reverted due to #60004 and #60007. #60004 is fixed in
CL 492743. #60007 is fixed in CL 492987 (incorporated in this CL).
[Original CL 485500 description]
This reapplies CL 481061, with the followup fixes in CL 482975, CL 485315, and
CL 485316 incorporated.
CL 481061, by doujiang24 <doujiang24@gmail.com>, speed up C to Go
calls by binding the M to the C thread. See below for its
description.
CL 482975 is a followup fix to a C declaration in testprogcgo.
CL 485315 is a followup fix for x_cgo_getstackbound on Illumos.
CL 485316 is a followup cleanup for ppc64 assembly.
CL 479915 passed the G to _cgo_getstackbound for direct updates to
gp.stack.lo. A G can be reused on a new thread after the previous thread
exited. This could trigger the C TSAN race detector because it couldn't
see the synchronization in Go (lockextra) preventing the same G from
being used on multiple threads at the same time.
We work around this by passing the address of a stack variable to
_cgo_getstackbound rather than the G. The stack is generally unique per
thread, so TSAN won't see the same address from multiple threads. Even
if stacks are reused across threads by pthread, C TSAN should see the
synchonization in the stack allocator.
A regression test is added to misc/cgo/testsanitizer.
[Original CL 481061 description]
This reapplies CL 392854, with the followup fixes in CL 479255,
CL 479915, and CL 481057 incorporated.
CL 392854, by doujiang24 <doujiang24@gmail.com>, speed up C to Go
calls by binding the M to the C thread. See below for its
description.
CL 479255 is a followup fix for a small bug in ARM assembly code.
CL 479915 is another followup fix to address C to Go calls after
the C code uses some stack, but that CL is also buggy.
CL 481057, by Michael Knyszek, is a followup fix for a memory leak
bug of CL 479915.
[Original CL 392854 description]
In a C thread, it's necessary to acquire an extra M by using needm while invoking a Go function from C. But, needm and dropm are heavy costs due to the signal-related syscalls.
So, we change to not dropm while returning back to C, which means binding the extra M to the C thread until it exits, to avoid needm and dropm on each C to Go call.
Instead, we only dropm while the C thread exits, so the extra M won't leak.
When invoking a Go function from C:
Allocate a pthread variable using pthread_key_create, only once per shared object, and register a thread-exit-time destructor.
And store the g0 of the current m into the thread-specified value of the pthread key, only once per C thread, so that the destructor will put the extra M back onto the extra M list while the C thread exits.
When returning back to C:
Skip dropm in cgocallback, when the pthread variable has been created, so that the extra M will be reused the next time invoke a Go function from C.
This is purely a performance optimization. The old version, in which needm & dropm happen on each cgo call, is still correct too, and we have to keep the old version on systems with cgo but without pthreads, like Windows.
This optimization is significant, and the specific value depends on the OS system and CPU, but in general, it can be considered as 10x faster, for a simple Go function call from a C thread.
For the newly added BenchmarkCGoInCThread, some benchmark results:
1. it's 28x faster, from 3395 ns/op to 121 ns/op, in darwin OS & Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
2. it's 6.5x faster, from 1495 ns/op to 230 ns/op, in Linux OS & Intel(R) Xeon(R) CPU E5-2630 0 @ 2.30GHz
[CL 479915 description]
Currently, when C calls into Go the first time, we grab an M
using needm, which sets m.g0's stack bounds using the SP. We don't
know how big the stack is, so we simply assume 32K. Previously,
when the Go function returns to C, we drop the M, and the next
time C calls into Go, we put a new stack bound on the g0 based on
the current SP. After CL 392854, we don't drop the M, and the next
time C calls into Go, we reuse the same g0, without recomputing
the stack bounds. If the C code uses quite a bit of stack space
before calling into Go, the SP may be well below the 32K stack
bound we assumed, so the runtime thinks the g0 stack overflows.
This CL makes needm get a more accurate stack bound from
pthread. (In some platforms this may still be a guess as we don't
know exactly where we are in the C stack), but it is probably
better than simply assuming 32K.
[CL 492987 description]
On the first call into Go from a C thread, currently we set the g0
stack's high bound imprecisely based on the SP. With CL 485500, we
keep the M and don't recompute the stack bounds when it calls into
Go again. If the first call is made when the C thread uses some
deep stack, but a subsequent call is made with a shallower stack,
the SP may be above g0.stack.hi.
This is usually okay as we don't check usually stack.hi. One place
where we do check for stack.hi is in the signal handler, in
adjustSignalStack. In particular, C TSAN delivers signals on the
g0 stack (instead of the usual signal stack). If the SP is above
g0.stack.hi, we don't see it is on the g0 stack, and throws.
This CL makes it get an accurate stack upper bound with the
pthread API (on the platforms where it is available).
Also add some debug print for the "handler not on signal stack"
throw.
Fixes #51676.
Fixes #59294.
Fixes #59678.
Fixes #60007.
Change-Id: Ie51c8e81ade34ec81d69fd7bce1fe0039a470776
Reviewed-on: https://go-review.googlesource.com/c/go/+/495855
Run-TryBot: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Michael Pratt <mpratt@google.com>
2023-05-17 12:01:15 -04:00
|
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
|
t.Logf("%v\n%s", cmd.Args, out)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
checkLineComments(t, "libgo9.h")
|
|
|
|
|
checkArchive(t, "libgo9.a")
|
|
|
|
|
|
|
|
|
|
// build with -O0 so the C compiler won't optimize out the large stack frame
|
|
|
|
|
ccArgs := append(cc, "-O0", "-o", "testp9"+exeSuffix, "main9.c", "libgo9.a")
|
|
|
|
|
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
|
|
|
|
t.Logf("%v\n%s", ccArgs, out)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
argv := cmdToRun("./testp9")
|
|
|
|
|
cmd = exec.Command(argv[0], argv[1:]...)
|
|
|
|
|
sb := new(strings.Builder)
|
|
|
|
|
cmd.Stdout = sb
|
|
|
|
|
cmd.Stderr = sb
|
|
|
|
|
if err := cmd.Start(); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
timer := time.AfterFunc(time.Minute,
|
|
|
|
|
func() {
|
|
|
|
|
t.Error("test program timed out")
|
|
|
|
|
cmd.Process.Kill()
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
defer timer.Stop()
|
|
|
|
|
|
|
|
|
|
err = cmd.Wait()
|
|
|
|
|
t.Logf("%v\n%s", cmd.Args, sb)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Error(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-10-06 20:53:27 -04:00
|
|
|
|
runtime: update and restore g0 stack bounds at cgocallback
Currently, at a cgo callback where there is already a Go frame on
the stack (i.e. C->Go->C->Go), we require that at the inner Go
callback the SP is within the g0's stack bounds set by a previous
callback. This is to prevent that the C code switches stack while
having a Go frame on the stack, which we don't really support. But
this could also happen when we cannot get accurate stack bounds,
e.g. when pthread_getattr_np is not available. Since the stack
bounds are just estimates based on the current SP, if there are
multiple C->Go callbacks with various stack depth, it is possible
that the SP of a later callback falls out of a previous call's
estimate. This leads to runtime throw in a seemingly reasonable
program.
This CL changes it to save the old g0 stack bounds at cgocallback,
update the bounds, and restore the old bounds at return. So each
callback will get its own stack bounds based on the current SP,
and when it returns, the outer callback has the its old stack
bounds restored.
Also, at a cgo callback when there is no Go frame on the stack,
we currently always get new stack bounds. We do this because if
we can only get estimated bounds based on the SP, and the stack
depth varies a lot between two C->Go calls, the previous
estimates may be off and we fall out or nearly fall out of the
previous bounds. But this causes a performance problem: the
pthread API to get accurate stack bounds (pthread_getattr_np) is
very slow when called on the main thread. Getting the stack bounds
every time significantly slows down repeated C->Go calls on the
main thread.
This CL fixes it by "caching" the stack bounds if they are
accurate. I.e. at the second time Go calls into C, if the previous
stack bounds are accurate, and the current SP is in bounds, we can
be sure it is the same stack and we don't need to update the bounds.
This avoids the repeated calls to pthread_getattr_np. If we cannot
get the accurate bounds, we continue to update the stack bounds
based on the SP, and that operation is very cheap.
On a Linux/AMD64 machine with glibc:
name old time/op new time/op delta
CgoCallbackMainThread-8 96.4µs ± 3% 0.1µs ± 2% -99.92% (p=0.000 n=10+9)
Fixes #68285.
Fixes #68587.
Change-Id: I3422badd5ad8ff63e1a733152d05fb7a44d5d435
Reviewed-on: https://go-review.googlesource.com/c/go/+/600296
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
2024-07-22 16:23:43 -04:00
|
|
|
func BenchmarkCgoCallbackMainThread(b *testing.B) {
|
|
|
|
|
// Benchmark for calling into Go fron C main thread.
|
|
|
|
|
// See issue #68587.
|
|
|
|
|
//
|
|
|
|
|
// It uses a subprocess, which is a C binary that calls
|
|
|
|
|
// Go on the main thread b.N times. There is some overhead
|
|
|
|
|
// for launching the subprocess. It is probably fine when
|
|
|
|
|
// b.N is large.
|
|
|
|
|
|
|
|
|
|
globalSkip(b)
|
|
|
|
|
testenv.MustHaveGoBuild(b)
|
|
|
|
|
testenv.MustHaveCGO(b)
|
|
|
|
|
testenv.MustHaveBuildMode(b, "c-archive")
|
|
|
|
|
|
|
|
|
|
if !testWork {
|
|
|
|
|
defer func() {
|
|
|
|
|
os.Remove("testp10" + exeSuffix)
|
|
|
|
|
os.Remove("libgo10.a")
|
|
|
|
|
os.Remove("libgo10.h")
|
|
|
|
|
}()
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-24 10:21:01 +01:00
|
|
|
cmd := exec.Command(testenv.GoToolPath(b), "build", "-buildmode=c-archive", "-o", "libgo10.a", "./libgo10")
|
runtime: update and restore g0 stack bounds at cgocallback
Currently, at a cgo callback where there is already a Go frame on
the stack (i.e. C->Go->C->Go), we require that at the inner Go
callback the SP is within the g0's stack bounds set by a previous
callback. This is to prevent that the C code switches stack while
having a Go frame on the stack, which we don't really support. But
this could also happen when we cannot get accurate stack bounds,
e.g. when pthread_getattr_np is not available. Since the stack
bounds are just estimates based on the current SP, if there are
multiple C->Go callbacks with various stack depth, it is possible
that the SP of a later callback falls out of a previous call's
estimate. This leads to runtime throw in a seemingly reasonable
program.
This CL changes it to save the old g0 stack bounds at cgocallback,
update the bounds, and restore the old bounds at return. So each
callback will get its own stack bounds based on the current SP,
and when it returns, the outer callback has the its old stack
bounds restored.
Also, at a cgo callback when there is no Go frame on the stack,
we currently always get new stack bounds. We do this because if
we can only get estimated bounds based on the SP, and the stack
depth varies a lot between two C->Go calls, the previous
estimates may be off and we fall out or nearly fall out of the
previous bounds. But this causes a performance problem: the
pthread API to get accurate stack bounds (pthread_getattr_np) is
very slow when called on the main thread. Getting the stack bounds
every time significantly slows down repeated C->Go calls on the
main thread.
This CL fixes it by "caching" the stack bounds if they are
accurate. I.e. at the second time Go calls into C, if the previous
stack bounds are accurate, and the current SP is in bounds, we can
be sure it is the same stack and we don't need to update the bounds.
This avoids the repeated calls to pthread_getattr_np. If we cannot
get the accurate bounds, we continue to update the stack bounds
based on the SP, and that operation is very cheap.
On a Linux/AMD64 machine with glibc:
name old time/op new time/op delta
CgoCallbackMainThread-8 96.4µs ± 3% 0.1µs ± 2% -99.92% (p=0.000 n=10+9)
Fixes #68285.
Fixes #68587.
Change-Id: I3422badd5ad8ff63e1a733152d05fb7a44d5d435
Reviewed-on: https://go-review.googlesource.com/c/go/+/600296
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
2024-07-22 16:23:43 -04:00
|
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
|
b.Logf("%v\n%s", cmd.Args, out)
|
|
|
|
|
if err != nil {
|
|
|
|
|
b.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ccArgs := append(cc, "-o", "testp10"+exeSuffix, "main10.c", "libgo10.a")
|
|
|
|
|
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
|
|
|
|
b.Logf("%v\n%s", ccArgs, out)
|
|
|
|
|
if err != nil {
|
|
|
|
|
b.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
argv := cmdToRun("./testp10")
|
|
|
|
|
argv = append(argv, fmt.Sprint(b.N))
|
|
|
|
|
cmd = exec.Command(argv[0], argv[1:]...)
|
|
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
err = cmd.Run()
|
|
|
|
|
if err != nil {
|
|
|
|
|
b.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-06 20:53:27 -04:00
|
|
|
func TestSharedObject(t *testing.T) {
|
|
|
|
|
// Test that we can put a Go c-archive into a C shared object.
|
|
|
|
|
globalSkip(t)
|
|
|
|
|
testenv.MustHaveGoBuild(t)
|
|
|
|
|
testenv.MustHaveCGO(t)
|
|
|
|
|
testenv.MustHaveBuildMode(t, "c-archive")
|
|
|
|
|
|
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
|
|
if !testWork {
|
|
|
|
|
defer func() {
|
|
|
|
|
os.Remove("libgo_s.a")
|
|
|
|
|
os.Remove("libgo_s.h")
|
|
|
|
|
os.Remove("libgo_s.so")
|
|
|
|
|
}()
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-24 10:21:01 +01:00
|
|
|
cmd := exec.Command(testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-o", "libgo_s.a", "./libgo")
|
2023-10-06 20:53:27 -04:00
|
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
|
t.Logf("%v\n%s", cmd.Args, out)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ccArgs := append(cc, "-shared", "-o", "libgo_s.so", "libgo_s.a")
|
|
|
|
|
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
|
|
|
|
t.Logf("%v\n%s", ccArgs, out)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
}
|