blob: 631dc20ab46acdf8bc44b7fff90688bcc828c919 [file] [log] [blame]
Dan Willemsen0c157092016-07-08 13:57:52 -07001// Copyright 2011 The Go Authors. All rights reserved.
Colin Cross7bb052a2015-02-03 12:59:37 -08002// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package runtime
6
Dan Willemsen0c157092016-07-08 13:57:52 -07007import (
8 "runtime/internal/sys"
9 "unsafe"
10)
11
12type mOS struct{}
Colin Cross7bb052a2015-02-03 12:59:37 -080013
Dan Willemsen6ff23252015-09-15 13:49:18 -070014//go:noescape
Dan Willemsenf3f2eb62018-08-28 11:28:58 -070015func thr_new(param *thrparam, size int32) int32
Dan Willemsen6ff23252015-09-15 13:49:18 -070016
17//go:noescape
18func sigaltstack(new, old *stackt)
19
20//go:noescape
Dan Willemsen6ff23252015-09-15 13:49:18 -070021func sigprocmask(how int32, new, old *sigset)
22
23//go:noescape
24func setitimer(mode int32, new, old *itimerval)
25
26//go:noescape
Colin Cross7bb052a2015-02-03 12:59:37 -080027func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
Dan Willemsen6ff23252015-09-15 13:49:18 -070028
Dan Willemsenbbdf6642017-01-13 22:57:23 -080029func raise(sig uint32)
30func raiseproc(sig uint32)
Dan Willemsen6ff23252015-09-15 13:49:18 -070031
32//go:noescape
Dan Willemsenbbdf6642017-01-13 22:57:23 -080033func sys_umtx_op(addr *uint32, mode int32, val uint32, uaddr1 uintptr, ut *umtx_time) int32
Dan Willemsen6ff23252015-09-15 13:49:18 -070034
35func osyield()
Dan Willemsen0c157092016-07-08 13:57:52 -070036
Dan Willemsenf3f2eb62018-08-28 11:28:58 -070037func kqueue() int32
38
39//go:noescape
40func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
41func closeonexec(fd int32)
42
Dan Willemsen0c157092016-07-08 13:57:52 -070043// From FreeBSD's <sys/sysctl.h>
44const (
Dan Willemsenbbdf6642017-01-13 22:57:23 -080045 _CTL_HW = 6
Dan Willemsenbbdf6642017-01-13 22:57:23 -080046 _HW_PAGESIZE = 7
Dan Willemsen0c157092016-07-08 13:57:52 -070047)
48
49var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
50
Dan Willemsenc78f7142017-07-26 13:08:14 -070051// Undocumented numbers from FreeBSD's lib/libc/gen/sysctlnametomib.c.
52const (
53 _CTL_QUERY = 0
54 _CTL_QUERY_MIB = 3
55)
56
57// sysctlnametomib fill mib with dynamically assigned sysctl entries of name,
58// return count of effected mib slots, return 0 on error.
59func sysctlnametomib(name []byte, mib *[_CTL_MAXNAME]uint32) uint32 {
60 oid := [2]uint32{_CTL_QUERY, _CTL_QUERY_MIB}
61 miblen := uintptr(_CTL_MAXNAME)
62 if sysctl(&oid[0], 2, (*byte)(unsafe.Pointer(mib)), &miblen, (*byte)(unsafe.Pointer(&name[0])), (uintptr)(len(name))) < 0 {
63 return 0
Dan Willemsen0c157092016-07-08 13:57:52 -070064 }
Dan Willemsenc78f7142017-07-26 13:08:14 -070065 miblen /= unsafe.Sizeof(uint32(0))
66 if miblen <= 0 {
67 return 0
68 }
69 return uint32(miblen)
70}
71
72const (
Dan Willemsenc78f7142017-07-26 13:08:14 -070073 _CPU_CURRENT_PID = -1 // Current process ID.
74)
75
76//go:noescape
77func cpuset_getaffinity(level int, which int, id int64, size int, mask *byte) int32
78
Dan Willemsene1b3b182018-02-27 19:36:27 -080079//go:systemstack
Dan Willemsenc78f7142017-07-26 13:08:14 -070080func getncpu() int32 {
Dan Willemsene1b3b182018-02-27 19:36:27 -080081 // Use a large buffer for the CPU mask. We're on the system
82 // stack, so this is fine, and we can't allocate memory for a
83 // dynamically-sized buffer at this point.
84 const maxCPUs = 64 * 1024
85 var mask [maxCPUs / 8]byte
Dan Willemsenc78f7142017-07-26 13:08:14 -070086 var mib [_CTL_MAXNAME]uint32
87
88 // According to FreeBSD's /usr/src/sys/kern/kern_cpuset.c,
89 // cpuset_getaffinity return ERANGE when provided buffer size exceed the limits in kernel.
90 // Querying kern.smp.maxcpus to calculate maximum buffer size.
91 // See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=200802
92
93 // Variable kern.smp.maxcpus introduced at Dec 23 2003, revision 123766,
94 // with dynamically assigned sysctl entries.
95 miblen := sysctlnametomib([]byte("kern.smp.maxcpus"), &mib)
96 if miblen == 0 {
97 return 1
98 }
99
100 // Query kern.smp.maxcpus.
101 dstsize := uintptr(4)
102 maxcpus := uint32(0)
103 if sysctl(&mib[0], miblen, (*byte)(unsafe.Pointer(&maxcpus)), &dstsize, nil, 0) != 0 {
104 return 1
105 }
106
Dan Willemsene1b3b182018-02-27 19:36:27 -0800107 maskSize := int(maxcpus+7) / 8
108 if maskSize < sys.PtrSize {
109 maskSize = sys.PtrSize
Dan Willemsenc78f7142017-07-26 13:08:14 -0700110 }
Dan Willemsene1b3b182018-02-27 19:36:27 -0800111 if maskSize > len(mask) {
112 maskSize = len(mask)
Dan Willemsenc78f7142017-07-26 13:08:14 -0700113 }
114
115 if cpuset_getaffinity(_CPU_LEVEL_WHICH, _CPU_WHICH_PID, _CPU_CURRENT_PID,
Dan Willemsene1b3b182018-02-27 19:36:27 -0800116 maskSize, (*byte)(unsafe.Pointer(&mask[0]))) != 0 {
Dan Willemsenc78f7142017-07-26 13:08:14 -0700117 return 1
118 }
119 n := int32(0)
Dan Willemsene1b3b182018-02-27 19:36:27 -0800120 for _, v := range mask[:maskSize] {
Dan Willemsenc78f7142017-07-26 13:08:14 -0700121 for v != 0 {
122 n += int32(v & 1)
123 v >>= 1
124 }
125 }
126 if n == 0 {
127 return 1
128 }
129 return n
Dan Willemsen0c157092016-07-08 13:57:52 -0700130}
131
Dan Willemsenbbdf6642017-01-13 22:57:23 -0800132func getPageSize() uintptr {
133 mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
134 out := uint32(0)
135 nout := unsafe.Sizeof(out)
136 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
137 if ret >= 0 {
138 return uintptr(out)
139 }
140 return 0
141}
142
Dan Willemsen0c157092016-07-08 13:57:52 -0700143// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
144// thus the code is largely similar. See Linux implementation
145// and lock_futex.go for comments.
146
147//go:nosplit
148func futexsleep(addr *uint32, val uint32, ns int64) {
149 systemstack(func() {
150 futexsleep1(addr, val, ns)
151 })
152}
153
154func futexsleep1(addr *uint32, val uint32, ns int64) {
Dan Willemsenbbdf6642017-01-13 22:57:23 -0800155 var utp *umtx_time
Dan Willemsen0c157092016-07-08 13:57:52 -0700156 if ns >= 0 {
Dan Willemsenbbdf6642017-01-13 22:57:23 -0800157 var ut umtx_time
158 ut._clockid = _CLOCK_MONOTONIC
159 ut._timeout.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ut._timeout.tv_nsec)))))
160 utp = &ut
Dan Willemsen0c157092016-07-08 13:57:52 -0700161 }
Dan Willemsenbbdf6642017-01-13 22:57:23 -0800162 ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, unsafe.Sizeof(*utp), utp)
Dan Willemsen0c157092016-07-08 13:57:52 -0700163 if ret >= 0 || ret == -_EINTR {
164 return
165 }
166 print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n")
167 *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
168}
169
170//go:nosplit
171func futexwakeup(addr *uint32, cnt uint32) {
Dan Willemsenbbdf6642017-01-13 22:57:23 -0800172 ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, 0, nil)
Dan Willemsen0c157092016-07-08 13:57:52 -0700173 if ret >= 0 {
174 return
175 }
176
177 systemstack(func() {
178 print("umtx_wake_addr=", addr, " ret=", ret, "\n")
179 })
180}
181
182func thr_start()
183
184// May run with m.p==nil, so write barriers are not allowed.
185//go:nowritebarrier
Dan Willemsenf3f2eb62018-08-28 11:28:58 -0700186func newosproc(mp *m) {
187 stk := unsafe.Pointer(mp.g0.stack.hi)
Dan Willemsen0c157092016-07-08 13:57:52 -0700188 if false {
189 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", funcPC(thr_start), " id=", mp.id, " ostk=", &mp, "\n")
190 }
191
Dan Willemsen0c157092016-07-08 13:57:52 -0700192 param := thrparam{
193 start_func: funcPC(thr_start),
194 arg: unsafe.Pointer(mp),
Dan Willemsenf3f2eb62018-08-28 11:28:58 -0700195 stack_base: mp.g0.stack.lo,
196 stack_size: uintptr(stk) - mp.g0.stack.lo,
Dan Willemsen0c157092016-07-08 13:57:52 -0700197 child_tid: unsafe.Pointer(&mp.procid),
198 parent_tid: nil,
199 tls_base: unsafe.Pointer(&mp.tls[0]),
200 tls_size: unsafe.Sizeof(mp.tls),
201 }
202
203 var oset sigset
204 sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
205 // TODO: Check for error.
Dan Willemsenf3f2eb62018-08-28 11:28:58 -0700206 ret := thr_new(&param, int32(unsafe.Sizeof(param)))
Dan Willemsen0c157092016-07-08 13:57:52 -0700207 sigprocmask(_SIG_SETMASK, &oset, nil)
Dan Willemsenf3f2eb62018-08-28 11:28:58 -0700208 if ret < 0 {
209 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", -ret, ")\n")
210 throw("newosproc")
211 }
212}
213
214// Version of newosproc that doesn't require a valid G.
215//go:nosplit
216func newosproc0(stacksize uintptr, fn unsafe.Pointer) {
217 stack := sysAlloc(stacksize, &memstats.stacks_sys)
218 if stack == nil {
219 write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack)))
220 exit(1)
221 }
222 // This code "knows" it's being called once from the library
223 // initialization code, and so it's using the static m0 for the
224 // tls and procid (thread) pointers. thr_new() requires the tls
225 // pointers, though the tid pointers can be nil.
226 // However, newosproc0 is currently unreachable because builds
227 // utilizing c-shared/c-archive force external linking.
228 param := thrparam{
229 start_func: funcPC(fn),
230 arg: nil,
231 stack_base: uintptr(stack), //+stacksize?
232 stack_size: stacksize,
233 child_tid: unsafe.Pointer(&m0.procid),
234 parent_tid: nil,
235 tls_base: unsafe.Pointer(&m0.tls[0]),
236 tls_size: unsafe.Sizeof(m0.tls),
237 }
238
239 var oset sigset
240 sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
241 ret := thr_new(&param, int32(unsafe.Sizeof(param)))
242 sigprocmask(_SIG_SETMASK, &oset, nil)
243 if ret < 0 {
244 write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
245 exit(1)
246 }
247}
248
249var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n")
250var failthreadcreate = []byte("runtime: failed to create new OS thread\n")
251
252// Called to do synchronous initialization of Go code built with
253// -buildmode=c-archive or -buildmode=c-shared.
254// None of the Go runtime is initialized.
255//go:nosplit
256//go:nowritebarrierrec
257func libpreinit() {
258 initsig(true)
Dan Willemsen0c157092016-07-08 13:57:52 -0700259}
260
261func osinit() {
262 ncpu = getncpu()
Dan Willemsenf3f2eb62018-08-28 11:28:58 -0700263 if physPageSize == 0 {
264 physPageSize = getPageSize()
265 }
Dan Willemsen0c157092016-07-08 13:57:52 -0700266}
267
268var urandom_dev = []byte("/dev/urandom\x00")
269
270//go:nosplit
271func getRandomData(r []byte) {
272 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
273 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
274 closefd(fd)
275 extendRandom(r, int(n))
276}
277
278func goenvs() {
279 goenvs_unix()
280}
281
282// Called to initialize a new m (including the bootstrap m).
283// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
284func mpreinit(mp *m) {
285 mp.gsignal = malg(32 * 1024)
286 mp.gsignal.m = mp
287}
288
Dan Willemsen0c157092016-07-08 13:57:52 -0700289// Called to initialize a new m (including the bootstrap m).
290// Called on the new thread, cannot allocate memory.
291func minit() {
Dan Willemsen0c157092016-07-08 13:57:52 -0700292 // m.procid is a uint64, but thr_new writes a uint32 on 32-bit systems.
293 // Fix it up. (Only matters on big-endian, but be clean anyway.)
294 if sys.PtrSize == 4 {
Dan Willemsenbbdf6642017-01-13 22:57:23 -0800295 _g_ := getg()
Dan Willemsen0c157092016-07-08 13:57:52 -0700296 _g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid)))
297 }
298
Dan Willemsenc78f7142017-07-26 13:08:14 -0700299 // On FreeBSD before about April 2017 there was a bug such
300 // that calling execve from a thread other than the main
301 // thread did not reset the signal stack. That would confuse
302 // minitSignals, which calls minitSignalStack, which checks
303 // whether there is currently a signal stack and uses it if
304 // present. To avoid this confusion, explicitly disable the
305 // signal stack on the main thread when not running in a
306 // library. This can be removed when we are confident that all
307 // FreeBSD users are running a patched kernel. See issue #15658.
308 if gp := getg(); !isarchive && !islibrary && gp.m == &m0 && gp == gp.m.g0 {
309 st := stackt{ss_flags: _SS_DISABLE}
310 sigaltstack(&st, nil)
311 }
312
Dan Willemsenbbdf6642017-01-13 22:57:23 -0800313 minitSignals()
Dan Willemsen0c157092016-07-08 13:57:52 -0700314}
315
316// Called from dropm to undo the effect of an minit.
317//go:nosplit
318func unminit() {
Dan Willemsenbbdf6642017-01-13 22:57:23 -0800319 unminitSignals()
Dan Willemsen0c157092016-07-08 13:57:52 -0700320}
321
Dan Willemsen0c157092016-07-08 13:57:52 -0700322func sigtramp()
323
324type sigactiont struct {
325 sa_handler uintptr
326 sa_flags int32
327 sa_mask sigset
328}
329
Dan Willemsenf3f2eb62018-08-28 11:28:58 -0700330// See os_freebsd2.go, os_freebsd_amd64.go for setsig function
Dan Willemsen0c157092016-07-08 13:57:52 -0700331
332//go:nosplit
333//go:nowritebarrierrec
Dan Willemsenbbdf6642017-01-13 22:57:23 -0800334func setsigstack(i uint32) {
Dan Willemsenf3f2eb62018-08-28 11:28:58 -0700335 var sa sigactiont
336 sigaction(i, nil, &sa)
337 if sa.sa_flags&_SA_ONSTACK != 0 {
338 return
339 }
340 sa.sa_flags |= _SA_ONSTACK
341 sigaction(i, &sa, nil)
Dan Willemsen0c157092016-07-08 13:57:52 -0700342}
343
344//go:nosplit
345//go:nowritebarrierrec
Dan Willemsenbbdf6642017-01-13 22:57:23 -0800346func getsig(i uint32) uintptr {
Dan Willemsen0c157092016-07-08 13:57:52 -0700347 var sa sigactiont
348 sigaction(i, nil, &sa)
Dan Willemsen0c157092016-07-08 13:57:52 -0700349 return sa.sa_handler
350}
351
Dan Willemsenbbdf6642017-01-13 22:57:23 -0800352// setSignaltstackSP sets the ss_sp field of a stackt.
Dan Willemsen0c157092016-07-08 13:57:52 -0700353//go:nosplit
Dan Willemsenbbdf6642017-01-13 22:57:23 -0800354func setSignalstackSP(s *stackt, sp uintptr) {
355 s.ss_sp = sp
Dan Willemsen0c157092016-07-08 13:57:52 -0700356}
357
358//go:nosplit
359//go:nowritebarrierrec
Dan Willemsenbbdf6642017-01-13 22:57:23 -0800360func sigaddset(mask *sigset, i int) {
361 mask.__bits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
Dan Willemsen0c157092016-07-08 13:57:52 -0700362}
363
Dan Willemsenbbdf6642017-01-13 22:57:23 -0800364func sigdelset(mask *sigset, i int) {
365 mask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
366}
367
368func (c *sigctxt) fixsigcode(sig uint32) {
Dan Willemsen0c157092016-07-08 13:57:52 -0700369}
Dan Willemsenf3f2eb62018-08-28 11:28:58 -0700370
371func sysargs(argc int32, argv **byte) {
372 n := argc + 1
373
374 // skip over argv, envp to get to auxv
375 for argv_index(argv, n) != nil {
376 n++
377 }
378
379 // skip NULL separator
380 n++
381
382 // now argv+n is auxv
383 auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize))
384 sysauxv(auxv[:])
385}
386
387const (
388 _AT_NULL = 0 // Terminates the vector
389 _AT_PAGESZ = 6 // Page size in bytes
390 _AT_TIMEKEEP = 22 // Pointer to timehands.
391 _AT_HWCAP = 25 // CPU feature flags
392)
393
394func sysauxv(auxv []uintptr) {
395 for i := 0; auxv[i] != _AT_NULL; i += 2 {
396 tag, val := auxv[i], auxv[i+1]
397 switch tag {
398 // _AT_NCPUS from auxv shouldn't be used due to golang.org/issue/15206
399 case _AT_PAGESZ:
400 physPageSize = val
401 case _AT_TIMEKEEP:
402 timekeepSharedPage = (*vdsoTimekeep)(unsafe.Pointer(val))
403 }
404
405 archauxv(tag, val)
406 }
407}
408
409// sysSigaction calls the sigaction system call.
410//go:nosplit
411func sysSigaction(sig uint32, new, old *sigactiont) {
412 // Use system stack to avoid split stack overflow on amd64
413 if asmSigaction(uintptr(sig), new, old) != 0 {
414 systemstack(func() {
415 throw("sigaction failed")
416 })
417 }
418}
419
420// asmSigaction is implemented in assembly.
421//go:noescape
422func asmSigaction(sig uintptr, new, old *sigactiont) int32