aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/testdata/testprognet/signalexec.go
diff options
context:
space:
mode:
authorMichael Anthony Knyszek <mknyszek@google.com>2025-07-09 15:50:06 +0000
committerMichael Knyszek <mknyszek@google.com>2025-07-09 13:34:08 -0700
commit8131635e5a9c7ae2fd2c083bed9e841d27226500 (patch)
tree393d115b7bf91237e227828c5f5f9c44dda0ecd7 /src/runtime/testdata/testprognet/signalexec.go
parent67c1704444ba9661699a80d0ea0a2df20b4107e2 (diff)
downloadgo-8131635e5a9c7ae2fd2c083bed9e841d27226500.tar.xz
runtime: run TestSignalDuringExec in its own process group
TestSignalDuringExec sends a SIGWINCH to the whole process group. However, it may execute concurrently with other copies of the runtime tests, especially through `go tool dist`, and gdb version <12.1 has a bug in non-interactive mode where recieving a SIGWINCH causes a crash. This change modifies SignalDuringExec in the testprog to first fork itself into a new process group. To avoid issues with Ctrl+C and the new process group hanging, the new process blocks on a pipe that is passed down to it. This pipe is automatically closed when its parent exits, which should ensure that the subprocess also exits. Fixes #58932. Change-Id: I3906afa28cf8b15d22ae612d071bce7f30fc3e6c Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest-noswissmap,gotip-linux-amd64-longtest-aliastypeparams,gotip-linux-amd64-longtest,gotip-linux-386-longtest Reviewed-on: https://go-review.googlesource.com/c/go/+/686875 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/runtime/testdata/testprognet/signalexec.go')
-rw-r--r--src/runtime/testdata/testprognet/signalexec.go43
1 files changed, 43 insertions, 0 deletions
diff --git a/src/runtime/testdata/testprognet/signalexec.go b/src/runtime/testdata/testprognet/signalexec.go
index 62ebce7176..7e7591e8f7 100644
--- a/src/runtime/testdata/testprognet/signalexec.go
+++ b/src/runtime/testdata/testprognet/signalexec.go
@@ -13,9 +13,11 @@ package main
import (
"fmt"
+ "io"
"os"
"os/exec"
"os/signal"
+ "runtime"
"sync"
"syscall"
"time"
@@ -23,10 +25,51 @@ import (
func init() {
register("SignalDuringExec", SignalDuringExec)
+ register("SignalDuringExecPgrp", SignalDuringExecPgrp)
register("Nop", Nop)
}
func SignalDuringExec() {
+ // Re-launch ourselves in a new process group.
+ cmd := exec.Command(os.Args[0], "SignalDuringExecPgrp")
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ Setpgid: true,
+ }
+
+ // Start the new process with an extra pipe. It will
+ // exit if the pipe is closed.
+ rp, wp, err := os.Pipe()
+ if err != nil {
+ fmt.Printf("Failed to create pipe: %v", err)
+ return
+ }
+ cmd.ExtraFiles = []*os.File{rp}
+
+ // Run the command.
+ if err := cmd.Run(); err != nil {
+ fmt.Printf("Run failed: %v", err)
+ }
+
+ // We don't actually need to write to the pipe, it just
+ // needs to get closed, which will happen on process
+ // exit.
+ runtime.KeepAlive(wp)
+}
+
+func SignalDuringExecPgrp() {
+ // Grab fd 3 which is a pipe we need to read on.
+ f := os.NewFile(3, "pipe")
+ go func() {
+ // Nothing will ever get written to the pipe, so we'll
+ // just block on it. If it closes, ReadAll will return
+ // one way or another, at which point we'll exit.
+ io.ReadAll(f)
+ os.Exit(1)
+ }()
+
+ // This is just for SignalDuringExec.
pgrp := syscall.Getpgrp()
const tries = 10