// 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") }