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