1
2
3
4
5 package main
6
7 import (
8 "os"
9 "runtime"
10 "sync"
11 "time"
12 )
13
14 var mainTID int
15
16 func init() {
17 registerInit("LockOSThreadMain", func() {
18
19 mainTID = gettid()
20 })
21 register("LockOSThreadMain", LockOSThreadMain)
22
23 registerInit("LockOSThreadAlt", func() {
24
25 runtime.LockOSThread()
26 })
27 register("LockOSThreadAlt", LockOSThreadAlt)
28
29 registerInit("LockOSThreadAvoidsStatePropagation", func() {
30
31 runtime.LockOSThread()
32 })
33 register("LockOSThreadAvoidsStatePropagation", LockOSThreadAvoidsStatePropagation)
34 register("LockOSThreadTemplateThreadRace", LockOSThreadTemplateThreadRace)
35 }
36
37 func LockOSThreadMain() {
38
39
40
41
42
43 if runtime.GOMAXPROCS(-1) != 1 {
44 println("requires GOMAXPROCS=1")
45 os.Exit(1)
46 }
47
48 ready := make(chan bool, 1)
49 go func() {
50
51
52 runtime.LockOSThread()
53 if mainTID != 0 && gettid() != mainTID {
54 println("failed to start goroutine on main thread")
55 os.Exit(1)
56 }
57
58
59 ready <- true
60 }()
61 <-ready
62 time.Sleep(1 * time.Millisecond)
63
64
65 if mainTID != 0 && gettid() == mainTID {
66 println("goroutine migrated to locked thread")
67 os.Exit(1)
68 }
69 println("OK")
70 }
71
72 func LockOSThreadAlt() {
73
74
75 var subTID int
76 ready := make(chan bool, 1)
77 go func() {
78
79 runtime.LockOSThread()
80 subTID = gettid()
81 ready <- true
82
83 }()
84 <-ready
85 runtime.UnlockOSThread()
86 for i := 0; i < 100; i++ {
87 time.Sleep(1 * time.Millisecond)
88
89 if subTID != 0 && gettid() == subTID {
90 println("locked thread reused")
91 os.Exit(1)
92 }
93 exists, supported := tidExists(subTID)
94 if !supported || !exists {
95 goto ok
96 }
97 }
98 println("sub thread", subTID, "still running")
99 return
100 ok:
101 println("OK")
102 }
103
104 func LockOSThreadAvoidsStatePropagation() {
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120 if runtime.GOMAXPROCS(-1) != 1 {
121 println("requires GOMAXPROCS=1")
122 os.Exit(1)
123 }
124
125 if err := chdir("/"); err != nil {
126 println("failed to chdir:", err.Error())
127 os.Exit(1)
128 }
129
130 cwd, err := getcwd()
131 if err != nil {
132 println("failed to get cwd:", err.Error())
133 os.Exit(1)
134 }
135 if cwd != "" && cwd != "/" {
136 println("unexpected cwd", cwd, " wanted /")
137 os.Exit(1)
138 }
139
140 ready := make(chan bool, 1)
141 go func() {
142
143 runtime.LockOSThread()
144
145
146
147
148 if err := unshareFs(); err != nil {
149 if err == errNotPermitted {
150 println("unshare not permitted")
151 os.Exit(0)
152 }
153 println("failed to unshare fs:", err.Error())
154 os.Exit(1)
155 }
156
157
158 if err := chdir("/tmp"); err != nil {
159 println("failed to chdir:", err.Error())
160 os.Exit(1)
161 }
162
163
164
165
166 ready <- true
167
168 }()
169 <-ready
170
171
172
173
174
175
176 done := make(chan bool)
177 go func() {
178 runtime.LockOSThread()
179
180
181
182
183 wd, err := getcwd()
184 if err != nil {
185 println("failed to get cwd:", err.Error())
186 os.Exit(1)
187 }
188 if wd != cwd {
189 println("bad state from old thread propagated after it should have died")
190 os.Exit(1)
191 }
192 <-done
193
194 runtime.UnlockOSThread()
195 }()
196 done <- true
197 runtime.UnlockOSThread()
198 println("OK")
199 }
200
201 func LockOSThreadTemplateThreadRace() {
202
203
204
205
206
207
208
209
210
211
212 runtime.GOMAXPROCS(4)
213
214 go func() {
215
216 var m runtime.MemStats
217 for {
218 runtime.ReadMemStats(&m)
219 }
220 }()
221
222
223 start := time.Now().Add(10 * time.Millisecond)
224
225 var wg sync.WaitGroup
226 wg.Add(2)
227
228 for i := 0; i < 2; i++ {
229 go func() {
230 for time.Now().Before(start) {
231 }
232
233
234
235 go func() {}()
236
237 runtime.LockOSThread()
238 runtime.Gosched()
239 wg.Done()
240 }()
241 }
242
243 wg.Wait()
244
245 println("OK")
246 }
247
View as plain text