github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/src/runtime/testdata/testprogcgo/lockosthread.go (about) 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 // +build !plan9,!windows 6 7 package main 8 9 import ( 10 "os" 11 "runtime" 12 "sync/atomic" 13 "time" 14 "unsafe" 15 ) 16 17 /* 18 #include <pthread.h> 19 #include <stdint.h> 20 21 extern uint32_t threadExited; 22 23 void setExited(void *x); 24 */ 25 import "C" 26 27 var mainThread C.pthread_t 28 29 func init() { 30 registerInit("LockOSThreadMain", func() { 31 // init is guaranteed to run on the main thread. 32 mainThread = C.pthread_self() 33 }) 34 register("LockOSThreadMain", LockOSThreadMain) 35 36 registerInit("LockOSThreadAlt", func() { 37 // Lock the OS thread now so main runs on the main thread. 38 runtime.LockOSThread() 39 }) 40 register("LockOSThreadAlt", LockOSThreadAlt) 41 } 42 43 func LockOSThreadMain() { 44 // This requires GOMAXPROCS=1 from the beginning to reliably 45 // start a goroutine on the main thread. 46 if runtime.GOMAXPROCS(-1) != 1 { 47 println("requires GOMAXPROCS=1") 48 os.Exit(1) 49 } 50 51 ready := make(chan bool, 1) 52 go func() { 53 // Because GOMAXPROCS=1, this *should* be on the main 54 // thread. Stay there. 55 runtime.LockOSThread() 56 self := C.pthread_self() 57 if C.pthread_equal(mainThread, self) == 0 { 58 println("failed to start goroutine on main thread") 59 os.Exit(1) 60 } 61 // Exit with the thread locked, which should exit the 62 // main thread. 63 ready <- true 64 }() 65 <-ready 66 time.Sleep(1 * time.Millisecond) 67 // Check that this goroutine is still running on a different 68 // thread. 69 self := C.pthread_self() 70 if C.pthread_equal(mainThread, self) != 0 { 71 println("goroutine migrated to locked thread") 72 os.Exit(1) 73 } 74 println("OK") 75 } 76 77 func LockOSThreadAlt() { 78 // This is running locked to the main OS thread. 79 80 var subThread C.pthread_t 81 ready := make(chan bool, 1) 82 C.threadExited = 0 83 go func() { 84 // This goroutine must be running on a new thread. 85 runtime.LockOSThread() 86 subThread = C.pthread_self() 87 // Register a pthread destructor so we can tell this 88 // thread has exited. 89 var key C.pthread_key_t 90 C.pthread_key_create(&key, (*[0]byte)(unsafe.Pointer(C.setExited))) 91 C.pthread_setspecific(key, unsafe.Pointer(new(int))) 92 ready <- true 93 // Exit with the thread locked. 94 }() 95 <-ready 96 for i := 0; i < 100; i++ { 97 time.Sleep(1 * time.Millisecond) 98 // Check that this goroutine is running on a different thread. 99 self := C.pthread_self() 100 if C.pthread_equal(subThread, self) != 0 { 101 println("locked thread reused") 102 os.Exit(1) 103 } 104 if atomic.LoadUint32((*uint32)(&C.threadExited)) != 0 { 105 println("OK") 106 return 107 } 108 } 109 println("sub thread still running") 110 os.Exit(1) 111 }