aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/testdata
diff options
context:
space:
mode:
authorMichael Pratt <mpratt@google.com>2025-04-03 15:16:36 +0000
committerGopher Robot <gobot@golang.org>2025-04-04 06:37:49 -0700
commit8969771cc3ceed634844dd6c911f3a5439424a97 (patch)
treee8ac9af8d3f5d6c63e555bdd689b4712cc97dd53 /src/runtime/testdata
parent5eaeb7b455d0bb6a39dacb4317ea177cbe0358de (diff)
downloadgo-8969771cc3ceed634844dd6c911f3a5439424a97.tar.xz
runtime: add thread exit plus vgetrandom stress test
Add a regression test similar to the reproducer from #73141 to try to help catch future issues with vgetrandom and thread exit. Though the test isn't very precise, it just hammers thread exit. When the test reproduces #73141, it simply crashes with a SIGSEGV and no output or stack trace, which would be very unfortunate on a builder. https://go.dev/issue/49165 tracks collecting core dumps from builders, which would make this more tractable to debug. For #73141. Change-Id: I6a6a636c7d7b41e2729ff6ceb30fd7f979aa9978 Reviewed-on: https://go-review.googlesource.com/c/go/+/662636 Reviewed-by: Cherry Mui <cherryyz@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/runtime/testdata')
-rw-r--r--src/runtime/testdata/testprog/lockosthread_linux.go71
1 files changed, 71 insertions, 0 deletions
diff --git a/src/runtime/testdata/testprog/lockosthread_linux.go b/src/runtime/testdata/testprog/lockosthread_linux.go
new file mode 100644
index 0000000000..5e49b43ca2
--- /dev/null
+++ b/src/runtime/testdata/testprog/lockosthread_linux.go
@@ -0,0 +1,71 @@
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "internal/syscall/unix"
+ "runtime"
+)
+
+func init() {
+ register("LockOSThreadVgetrandom", LockOSThreadVgetrandom)
+}
+
+var sinkInt int
+
+func LockOSThreadVgetrandom() {
+ // This is a regression test for https://go.dev/issue/73141. When that
+ // reproduces, this crashes with SIGSEGV with no output or stack trace,
+ // and detail only available in a core file.
+ //
+ // Thread exit via mexit cleans up vgetrandom state. Stress test thread
+ // exit + vgetrandom to look for issues by creating lots of threads
+ // that use GetRandom and then exit.
+
+ // Launch at most 100 threads at a time.
+ const parallelism = 100
+ ch := make(chan struct{}, parallelism)
+ for range 100 {
+ ch <- struct{}{}
+ }
+
+ // Create at most 1000 threads to avoid completely exhausting the
+ // system. This test generally reproduces https://go.dev/issue/73141 in
+ // less than 500 iterations.
+ const iterations = 1000
+ for range iterations {
+ <-ch
+ go func() {
+ defer func() {
+ ch <- struct{}{}
+ }()
+
+ // Exit with LockOSThread held.
+ runtime.LockOSThread()
+
+ // Be sure to use GetRandom to initialize vgetrandom state.
+ b := make([]byte, 1)
+ _, err := unix.GetRandom(b, 0)
+ if err != nil {
+ panic(err)
+ }
+
+ // Do some busy-work. It is unclear why this is
+ // necessary to reproduce. Perhaps to introduce
+ // interesting scheduling where threads get descheduled
+ // in the middle of getting or putting vgetrandom
+ // state.
+ for range 10 * 1000 * 1000 {
+ sinkInt = 1
+ }
+ }()
+ }
+
+ // Wait for all threads to finish.
+ for range parallelism {
+ <-ch
+ }
+ println("OK")
+}