aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/testdata/testprog/lockosthread.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/testdata/testprog/lockosthread.go')
-rw-r--r--src/runtime/testdata/testprog/lockosthread.go94
1 files changed, 94 insertions, 0 deletions
diff --git a/src/runtime/testdata/testprog/lockosthread.go b/src/runtime/testdata/testprog/lockosthread.go
new file mode 100644
index 0000000000..88c0d12e4c
--- /dev/null
+++ b/src/runtime/testdata/testprog/lockosthread.go
@@ -0,0 +1,94 @@
+// 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")
+}