blob: 070a9e042cc686732139de384f12f29719005fa5 [file] [edit]
// Copyright 2026 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 (
"fmt"
"os"
"runtime"
)
func init() {
registerInit("LockOSThreadExitAIX", func() {
// Lock the OS thread now so main runs on the main thread.
runtime.LockOSThread()
})
register("LockOSThreadExitAIX", LockOSThreadExitAIX)
}
// LockOSThreadExitAIX is like LockOSThreadAlt, but AIX has no thread ID
// to check without cgo. Instead, record the threads that exist while n
// goroutines are locked to their threads, and wait for n of them to
// exit. No other thread exits in this program.
func LockOSThreadExitAIX() {
const n = 10
ready := make(chan bool)
done := make(chan bool)
for range n {
go func() {
runtime.LockOSThread()
ready <- true
<-done
}()
}
for range n {
<-ready
}
threads := lwps()
close(done)
runtime.UnlockOSThread()
// If the threads never exit, this loops until the test times out.
for exited(threads) < n {
runtime.Gosched()
}
println("OK")
}
// lwps returns the IDs of the kernel threads in the process.
func lwps() map[string]bool {
entries, err := os.ReadDir(fmt.Sprintf("/proc/%d/lwp", os.Getpid()))
if err != nil {
panic(err)
}
ids := make(map[string]bool)
for _, e := range entries {
ids[e.Name()] = true
}
return ids
}
// exited returns how many of the given threads have exited.
func exited(threads map[string]bool) int {
now := lwps()
n := 0
for id := range threads {
if !now[id] {
n++
}
}
return n
}