1
2
3
4
5
6
7
8 package main
9
10 import (
11 "os"
12 "runtime"
13 "sync/atomic"
14 "time"
15 "unsafe"
16 )
17
18
26 import "C"
27
28 var mainThread C.pthread_t
29
30 func init() {
31 registerInit("LockOSThreadMain", func() {
32
33 mainThread = C.pthread_self()
34 })
35 register("LockOSThreadMain", LockOSThreadMain)
36
37 registerInit("LockOSThreadAlt", func() {
38
39 runtime.LockOSThread()
40 })
41 register("LockOSThreadAlt", LockOSThreadAlt)
42 }
43
44 func LockOSThreadMain() {
45
46
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
55
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
63
64 ready <- true
65 }()
66 <-ready
67 time.Sleep(1 * time.Millisecond)
68
69
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
80
81 var subThread C.pthread_t
82 ready := make(chan bool, 1)
83 C.threadExited = 0
84 go func() {
85
86 runtime.LockOSThread()
87 subThread = C.pthread_self()
88
89
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
95 }()
96 <-ready
97 for {
98 time.Sleep(1 * time.Millisecond)
99
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 }
111
View as plain text