Source file src/runtime/os_linux.go
1
2
3
4
5 package runtime
6
7 import (
8 "runtime/internal/sys"
9 "unsafe"
10 )
11
12 type mOS struct{}
13
14
15 func futex(addr unsafe.Pointer, op int32, val uint32, ts, addr2 unsafe.Pointer, val3 uint32) int32
16
17
18
19
20
21
22
23
24
25
26 const (
27 _FUTEX_PRIVATE_FLAG = 128
28 _FUTEX_WAIT_PRIVATE = 0 | _FUTEX_PRIVATE_FLAG
29 _FUTEX_WAKE_PRIVATE = 1 | _FUTEX_PRIVATE_FLAG
30 )
31
32
33
34
35
36
37 func futexsleep(addr *uint32, val uint32, ns int64) {
38
39
40
41
42
43 if ns < 0 {
44 futex(unsafe.Pointer(addr), _FUTEX_WAIT_PRIVATE, val, nil, nil, 0)
45 return
46 }
47
48 var ts timespec
49 ts.setNsec(ns)
50 futex(unsafe.Pointer(addr), _FUTEX_WAIT_PRIVATE, val, unsafe.Pointer(&ts), nil, 0)
51 }
52
53
54
55 func futexwakeup(addr *uint32, cnt uint32) {
56 ret := futex(unsafe.Pointer(addr), _FUTEX_WAKE_PRIVATE, cnt, nil, nil, 0)
57 if ret >= 0 {
58 return
59 }
60
61
62
63
64 systemstack(func() {
65 print("futexwakeup addr=", addr, " returned ", ret, "\n")
66 })
67
68 *(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
69 }
70
71 func getproccount() int32 {
72
73
74
75
76
77
78
79 const maxCPUs = 64 * 1024
80 var buf [maxCPUs / 8]byte
81 r := sched_getaffinity(0, unsafe.Sizeof(buf), &buf[0])
82 if r < 0 {
83 return 1
84 }
85 n := int32(0)
86 for _, v := range buf[:r] {
87 for v != 0 {
88 n += int32(v & 1)
89 v >>= 1
90 }
91 }
92 if n == 0 {
93 n = 1
94 }
95 return n
96 }
97
98
99 const (
100 _CLONE_VM = 0x100
101 _CLONE_FS = 0x200
102 _CLONE_FILES = 0x400
103 _CLONE_SIGHAND = 0x800
104 _CLONE_PTRACE = 0x2000
105 _CLONE_VFORK = 0x4000
106 _CLONE_PARENT = 0x8000
107 _CLONE_THREAD = 0x10000
108 _CLONE_NEWNS = 0x20000
109 _CLONE_SYSVSEM = 0x40000
110 _CLONE_SETTLS = 0x80000
111 _CLONE_PARENT_SETTID = 0x100000
112 _CLONE_CHILD_CLEARTID = 0x200000
113 _CLONE_UNTRACED = 0x800000
114 _CLONE_CHILD_SETTID = 0x1000000
115 _CLONE_STOPPED = 0x2000000
116 _CLONE_NEWUTS = 0x4000000
117 _CLONE_NEWIPC = 0x8000000
118
119 cloneFlags = _CLONE_VM |
120 _CLONE_FS |
121 _CLONE_FILES |
122 _CLONE_SIGHAND |
123 _CLONE_SYSVSEM |
124 _CLONE_THREAD
125 )
126
127
128 func clone(flags int32, stk, mp, gp, fn unsafe.Pointer) int32
129
130
131
132 func newosproc(mp *m) {
133 stk := unsafe.Pointer(mp.g0.stack.hi)
134
137 if false {
138 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " clone=", funcPC(clone), " id=", mp.id, " ostk=", &mp, "\n")
139 }
140
141
142
143 var oset sigset
144 sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
145 ret := clone(cloneFlags, stk, unsafe.Pointer(mp), unsafe.Pointer(mp.g0), unsafe.Pointer(funcPC(mstart)))
146 sigprocmask(_SIG_SETMASK, &oset, nil)
147
148 if ret < 0 {
149 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", -ret, ")\n")
150 if ret == -_EAGAIN {
151 println("runtime: may need to increase max user processes (ulimit -u)")
152 }
153 throw("newosproc")
154 }
155 }
156
157
158
159 func newosproc0(stacksize uintptr, fn unsafe.Pointer) {
160 stack := sysAlloc(stacksize, &memstats.stacks_sys)
161 if stack == nil {
162 write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack)))
163 exit(1)
164 }
165 ret := clone(cloneFlags, unsafe.Pointer(uintptr(stack)+stacksize), nil, nil, fn)
166 if ret < 0 {
167 write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
168 exit(1)
169 }
170 }
171
172 var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n")
173 var failthreadcreate = []byte("runtime: failed to create new OS thread\n")
174
175 const (
176 _AT_NULL = 0
177 _AT_PAGESZ = 6
178 _AT_HWCAP = 16
179 _AT_RANDOM = 25
180 _AT_HWCAP2 = 26
181 )
182
183 var procAuxv = []byte("/proc/self/auxv\x00")
184
185 var addrspace_vec [1]byte
186
187 func mincore(addr unsafe.Pointer, n uintptr, dst *byte) int32
188
189 func sysargs(argc int32, argv **byte) {
190 n := argc + 1
191
192
193 for argv_index(argv, n) != nil {
194 n++
195 }
196
197
198 n++
199
200
201 auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize))
202 if sysauxv(auxv[:]) != 0 {
203 return
204 }
205
206
207
208 fd := open(&procAuxv[0], 0 , 0)
209 if fd < 0 {
210
211
212
213 const size = 256 << 10
214 p, err := mmap(nil, size, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
215 if err != 0 {
216 return
217 }
218 var n uintptr
219 for n = 4 << 10; n < size; n <<= 1 {
220 err := mincore(unsafe.Pointer(uintptr(p)+n), 1, &addrspace_vec[0])
221 if err == 0 {
222 physPageSize = n
223 break
224 }
225 }
226 if physPageSize == 0 {
227 physPageSize = size
228 }
229 munmap(p, size)
230 return
231 }
232 var buf [128]uintptr
233 n = read(fd, noescape(unsafe.Pointer(&buf[0])), int32(unsafe.Sizeof(buf)))
234 closefd(fd)
235 if n < 0 {
236 return
237 }
238
239
240 buf[len(buf)-2] = _AT_NULL
241 sysauxv(buf[:])
242 }
243
244 func sysauxv(auxv []uintptr) int {
245 var i int
246 for ; auxv[i] != _AT_NULL; i += 2 {
247 tag, val := auxv[i], auxv[i+1]
248 switch tag {
249 case _AT_RANDOM:
250
251
252 startupRandomData = (*[16]byte)(unsafe.Pointer(val))[:]
253
254 case _AT_PAGESZ:
255 physPageSize = val
256 }
257
258 archauxv(tag, val)
259 vdsoauxv(tag, val)
260 }
261 return i / 2
262 }
263
264 var sysTHPSizePath = []byte("/sys/kernel/mm/transparent_hugepage/hpage_pmd_size\x00")
265
266 func getHugePageSize() uintptr {
267 var numbuf [20]byte
268 fd := open(&sysTHPSizePath[0], 0 , 0)
269 if fd < 0 {
270 return 0
271 }
272 n := read(fd, noescape(unsafe.Pointer(&numbuf[0])), int32(len(numbuf)))
273 closefd(fd)
274 if n <= 0 {
275 return 0
276 }
277 l := n - 1
278 v, ok := atoi(slicebytetostringtmp(numbuf[:l]))
279 if !ok || v < 0 {
280 v = 0
281 }
282 if v&(v-1) != 0 {
283
284 return 0
285 }
286 return uintptr(v)
287 }
288
289 func osinit() {
290 ncpu = getproccount()
291 physHugePageSize = getHugePageSize()
292 }
293
294 var urandom_dev = []byte("/dev/urandom\x00")
295
296 func getRandomData(r []byte) {
297 if startupRandomData != nil {
298 n := copy(r, startupRandomData)
299 extendRandom(r, n)
300 return
301 }
302 fd := open(&urandom_dev[0], 0 , 0)
303 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
304 closefd(fd)
305 extendRandom(r, int(n))
306 }
307
308 func goenvs() {
309 goenvs_unix()
310 }
311
312
313
314
315
316
317 func libpreinit() {
318 initsig(true)
319 }
320
321
322
323 func mpreinit(mp *m) {
324 mp.gsignal = malg(32 * 1024)
325 mp.gsignal.m = mp
326 }
327
328 func gettid() uint32
329
330
331
332 func minit() {
333 minitSignals()
334
335
336 getg().m.procid = uint64(gettid())
337 }
338
339
340
341 func unminit() {
342 unminitSignals()
343 }
344
345
346
347
348
349 func sigreturn()
350 func sigtramp(sig uint32, info *siginfo, ctx unsafe.Pointer)
351 func cgoSigtramp()
352
353
354 func sigaltstack(new, old *stackt)
355
356
357 func setitimer(mode int32, new, old *itimerval)
358
359
360 func rtsigprocmask(how int32, new, old *sigset, size int32)
361
362
363
364 func sigprocmask(how int32, new, old *sigset) {
365 rtsigprocmask(how, new, old, int32(unsafe.Sizeof(*new)))
366 }
367
368 func raise(sig uint32)
369 func raiseproc(sig uint32)
370
371
372 func sched_getaffinity(pid, len uintptr, buf *byte) int32
373 func osyield()
374
375
376
377 func setsig(i uint32, fn uintptr) {
378 var sa sigactiont
379 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTORER | _SA_RESTART
380 sigfillset(&sa.sa_mask)
381
382
383
384 if GOARCH == "386" || GOARCH == "amd64" {
385 sa.sa_restorer = funcPC(sigreturn)
386 }
387 if fn == funcPC(sighandler) {
388 if iscgo {
389 fn = funcPC(cgoSigtramp)
390 } else {
391 fn = funcPC(sigtramp)
392 }
393 }
394 sa.sa_handler = fn
395 sigaction(i, &sa, nil)
396 }
397
398
399
400 func setsigstack(i uint32) {
401 var sa sigactiont
402 sigaction(i, nil, &sa)
403 if sa.sa_flags&_SA_ONSTACK != 0 {
404 return
405 }
406 sa.sa_flags |= _SA_ONSTACK
407 sigaction(i, &sa, nil)
408 }
409
410
411
412 func getsig(i uint32) uintptr {
413 var sa sigactiont
414 sigaction(i, nil, &sa)
415 return sa.sa_handler
416 }
417
418
419
420 func setSignalstackSP(s *stackt, sp uintptr) {
421 *(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp
422 }
423
424
425 func (c *sigctxt) fixsigcode(sig uint32) {
426 }
427
428
429
430 func sysSigaction(sig uint32, new, old *sigactiont) {
431 if rt_sigaction(uintptr(sig), new, old, unsafe.Sizeof(sigactiont{}.sa_mask)) != 0 {
432
433
434
435
436
437
438
439
440
441
442
443 if sig != 32 && sig != 33 && sig != 64 {
444
445 systemstack(func() {
446 throw("sigaction failed")
447 })
448 }
449 }
450 }
451
452
453
454 func rt_sigaction(sig uintptr, new, old *sigactiont, size uintptr) int32
455
View as plain text