// Copyright 2017 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 (
"os"
"runtime"
"time"
)
var mainTID int
func init() {
registerInit("LockOSThreadMain", func() {
// init is guaranteed to run on the main thread.
mainTID = gettid()
})
register("LockOSThreadMain", LockOSThreadMain)
registerInit("LockOSThreadAlt", func() {
// Lock the OS thread now so main runs on the main thread.
runtime.LockOSThread()
})
register("LockOSThreadAlt", LockOSThreadAlt)
}
func LockOSThreadMain() {
// gettid only works on Linux, so on other platforms this just
// checks that the runtime doesn't do anything terrible.
// This requires GOMAXPROCS=1 from the beginning to reliably
// start a goroutine on the main thread.
if runtime.GOMAXPROCS(-1) != 1 {
println("requires GOMAXPROCS=1")
os.Exit(1)
}
ready := make(chan bool, 1)
go func() {
// Because GOMAXPROCS=1, this *should* be on the main
// thread. Stay there.
runtime.LockOSThread()
if mainTID != 0 && gettid() != mainTID {
println("failed to start goroutine on main thread")
os.Exit(1)
}
// Exit with the thread locked, which should exit the
// main thread.
ready <- true
}()
<-ready
time.Sleep(1 * time.Millisecond)
// Check that this goroutine is still running on a different
// thread.
if mainTID != 0 && gettid() == mainTID {
println("goroutine migrated to locked thread")
os.Exit(1)
}
println("OK")
}
func LockOSThreadAlt() {
// This is running locked to the main OS thread.
var subTID int
ready := make(chan bool, 1)
go func() {
// This goroutine must be running on a new thread.
runtime.LockOSThread()
subTID = gettid()
ready <- true
// Exit with the thread locked.
}()
<-ready
runtime.UnlockOSThread()
for i := 0; i < 100; i++ {
time.Sleep(1 * time.Millisecond)
// Check that this goroutine is running on a different thread.
if subTID != 0 && gettid() == subTID {
println("locked thread reused")
os.Exit(1)
}
exists, supported := tidExists(subTID)
if !supported || !exists {
goto ok
}
}
println("sub thread", subTID, "still running")
return
ok:
println("OK")
}