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, err := tidExists(subTID)
94 if err != nil {
95 println("error:", err.Error())
96 return
97 }
98 if !supported || !exists {
99 goto ok
100 }
101 }
102 println("sub thread", subTID, "still running")
103 return
104 ok:
105 println("OK")
106 }
107
108 func LockOSThreadAvoidsStatePropagation() {
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 if runtime.GOMAXPROCS(-1) != 1 {
125 println("requires GOMAXPROCS=1")
126 os.Exit(1)
127 }
128
129 if err := chdir("/"); err != nil {
130 println("failed to chdir:", err.Error())
131 os.Exit(1)
132 }
133
134 cwd, err := getcwd()
135 if err != nil {
136 println("failed to get cwd:", err.Error())
137 os.Exit(1)
138 }
139 if cwd != "" && cwd != "/" {
140 println("unexpected cwd", cwd, " wanted /")
141 os.Exit(1)
142 }
143
144 ready := make(chan bool, 1)
145 go func() {
146
147 runtime.LockOSThread()
148
149
150
151
152 if err := unshareFs(); err != nil {
153 if err == errNotPermitted {
154 println("unshare not permitted")
155 os.Exit(0)
156 }
157 println("failed to unshare fs:", err.Error())
158 os.Exit(1)
159 }
160
161
162 if err := chdir(os.TempDir()); err != nil {
163 println("failed to chdir:", err.Error())
164 os.Exit(1)
165 }
166
167
168
169
170 ready <- true
171
172 }()
173 <-ready
174
175
176
177
178
179
180 done := make(chan bool)
181 go func() {
182 runtime.LockOSThread()
183
184
185
186
187 wd, err := getcwd()
188 if err != nil {
189 println("failed to get cwd:", err.Error())
190 os.Exit(1)
191 }
192 if wd != cwd {
193 println("bad state from old thread propagated after it should have died")
194 os.Exit(1)
195 }
196 <-done
197
198 runtime.UnlockOSThread()
199 }()
200 done <- true
201 runtime.UnlockOSThread()
202 println("OK")
203 }
204
205 func LockOSThreadTemplateThreadRace() {
206
207
208
209
210
211
212
213
214
215
216 runtime.GOMAXPROCS(4)
217
218 go func() {
219
220 var m runtime.MemStats
221 for {
222 runtime.ReadMemStats(&m)
223 }
224 }()
225
226
227 start := time.Now().Add(10 * time.Millisecond)
228
229 var wg sync.WaitGroup
230 wg.Add(2)
231
232 for i := 0; i < 2; i++ {
233 go func() {
234 for time.Now().Before(start) {
235 }
236
237
238
239 go func() {}()
240
241 runtime.LockOSThread()
242 runtime.Gosched()
243 wg.Done()
244 }()
245 }
246
247 wg.Wait()
248
249 println("OK")
250 }
251
View as plain text