Home | History | Annotate | Download | only in testprog
      1 // Copyright 2017 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 	"os"
      9 	"runtime"
     10 	"time"
     11 )
     12 
     13 var mainTID int
     14 
     15 func init() {
     16 	registerInit("LockOSThreadMain", func() {
     17 		// init is guaranteed to run on the main thread.
     18 		mainTID = gettid()
     19 	})
     20 	register("LockOSThreadMain", LockOSThreadMain)
     21 
     22 	registerInit("LockOSThreadAlt", func() {
     23 		// Lock the OS thread now so main runs on the main thread.
     24 		runtime.LockOSThread()
     25 	})
     26 	register("LockOSThreadAlt", LockOSThreadAlt)
     27 }
     28 
     29 func LockOSThreadMain() {
     30 	// gettid only works on Linux, so on other platforms this just
     31 	// checks that the runtime doesn't do anything terrible.
     32 
     33 	// This requires GOMAXPROCS=1 from the beginning to reliably
     34 	// start a goroutine on the main thread.
     35 	if runtime.GOMAXPROCS(-1) != 1 {
     36 		println("requires GOMAXPROCS=1")
     37 		os.Exit(1)
     38 	}
     39 
     40 	ready := make(chan bool, 1)
     41 	go func() {
     42 		// Because GOMAXPROCS=1, this *should* be on the main
     43 		// thread. Stay there.
     44 		runtime.LockOSThread()
     45 		if mainTID != 0 && gettid() != mainTID {
     46 			println("failed to start goroutine on main thread")
     47 			os.Exit(1)
     48 		}
     49 		// Exit with the thread locked, which should exit the
     50 		// main thread.
     51 		ready <- true
     52 	}()
     53 	<-ready
     54 	time.Sleep(1 * time.Millisecond)
     55 	// Check that this goroutine is still running on a different
     56 	// thread.
     57 	if mainTID != 0 && gettid() == mainTID {
     58 		println("goroutine migrated to locked thread")
     59 		os.Exit(1)
     60 	}
     61 	println("OK")
     62 }
     63 
     64 func LockOSThreadAlt() {
     65 	// This is running locked to the main OS thread.
     66 
     67 	var subTID int
     68 	ready := make(chan bool, 1)
     69 	go func() {
     70 		// This goroutine must be running on a new thread.
     71 		runtime.LockOSThread()
     72 		subTID = gettid()
     73 		ready <- true
     74 		// Exit with the thread locked.
     75 	}()
     76 	<-ready
     77 	runtime.UnlockOSThread()
     78 	for i := 0; i < 100; i++ {
     79 		time.Sleep(1 * time.Millisecond)
     80 		// Check that this goroutine is running on a different thread.
     81 		if subTID != 0 && gettid() == subTID {
     82 			println("locked thread reused")
     83 			os.Exit(1)
     84 		}
     85 		exists, supported := tidExists(subTID)
     86 		if !supported || !exists {
     87 			goto ok
     88 		}
     89 	}
     90 	println("sub thread", subTID, "still running")
     91 	return
     92 ok:
     93 	println("OK")
     94 }
     95