Source file src/runtime/testdata/testprog/lockosthread_linux.go
1 // Copyright 2025 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "internal/syscall/unix" 9 "runtime" 10 ) 11 12 func init() { 13 register("LockOSThreadVgetrandom", LockOSThreadVgetrandom) 14 } 15 16 var sinkInt int 17 18 func LockOSThreadVgetrandom() { 19 // This is a regression test for https://go.dev/issue/73141. When that 20 // reproduces, this crashes with SIGSEGV with no output or stack trace, 21 // and detail only available in a core file. 22 // 23 // Thread exit via mexit cleans up vgetrandom state. Stress test thread 24 // exit + vgetrandom to look for issues by creating lots of threads 25 // that use GetRandom and then exit. 26 27 // Launch at most 100 threads at a time. 28 const parallelism = 100 29 ch := make(chan struct{}, parallelism) 30 for range 100 { 31 ch <- struct{}{} 32 } 33 34 // Create at most 1000 threads to avoid completely exhausting the 35 // system. This test generally reproduces https://go.dev/issue/73141 in 36 // less than 500 iterations. 37 const iterations = 1000 38 for range iterations { 39 <-ch 40 go func() { 41 defer func() { 42 ch <- struct{}{} 43 }() 44 45 // Exit with LockOSThread held. 46 runtime.LockOSThread() 47 48 // Be sure to use GetRandom to initialize vgetrandom state. 49 b := make([]byte, 1) 50 _, err := unix.GetRandom(b, 0) 51 if err != nil { 52 panic(err) 53 } 54 55 // Do some busy-work. It is unclear why this is 56 // necessary to reproduce. Perhaps to introduce 57 // interesting scheduling where threads get descheduled 58 // in the middle of getting or putting vgetrandom 59 // state. 60 for range 10 * 1000 * 1000 { 61 sinkInt = 1 62 } 63 }() 64 } 65 66 // Wait for all threads to finish. 67 for range parallelism { 68 <-ch 69 } 70 println("OK") 71 } 72