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  

View as plain text