aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/testdata/testprog/lockosthread_linux.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/testdata/testprog/lockosthread_linux.go')
-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")
+}