]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/os_freebsd.go
cmd/compile/internal/inline: score call sites exposed by inlines
[gostls13.git] / src / runtime / os_freebsd.go
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package runtime
6
7 import (
8         "internal/abi"
9         "internal/goarch"
10         "unsafe"
11 )
12
13 type mOS struct{}
14
15 //go:noescape
16 func thr_new(param *thrparam, size int32) int32
17
18 //go:noescape
19 func sigaltstack(new, old *stackt)
20
21 //go:noescape
22 func sigprocmask(how int32, new, old *sigset)
23
24 //go:noescape
25 func setitimer(mode int32, new, old *itimerval)
26
27 //go:noescape
28 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
29
30 func raiseproc(sig uint32)
31
32 func thr_self() thread
33 func thr_kill(tid thread, sig int)
34
35 //go:noescape
36 func sys_umtx_op(addr *uint32, mode int32, val uint32, uaddr1 uintptr, ut *umtx_time) int32
37
38 func osyield()
39
40 //go:nosplit
41 func osyield_no_g() {
42         osyield()
43 }
44
45 func kqueue() int32
46
47 //go:noescape
48 func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
49
50 func pipe2(flags int32) (r, w int32, errno int32)
51 func fcntl(fd, cmd, arg int32) (ret int32, errno int32)
52
53 func issetugid() int32
54
55 // From FreeBSD's <sys/sysctl.h>
56 const (
57         _CTL_HW      = 6
58         _HW_PAGESIZE = 7
59 )
60
61 var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
62
63 // Undocumented numbers from FreeBSD's lib/libc/gen/sysctlnametomib.c.
64 const (
65         _CTL_QUERY     = 0
66         _CTL_QUERY_MIB = 3
67 )
68
69 // sysctlnametomib fill mib with dynamically assigned sysctl entries of name,
70 // return count of effected mib slots, return 0 on error.
71 func sysctlnametomib(name []byte, mib *[_CTL_MAXNAME]uint32) uint32 {
72         oid := [2]uint32{_CTL_QUERY, _CTL_QUERY_MIB}
73         miblen := uintptr(_CTL_MAXNAME)
74         if sysctl(&oid[0], 2, (*byte)(unsafe.Pointer(mib)), &miblen, (*byte)(unsafe.Pointer(&name[0])), (uintptr)(len(name))) < 0 {
75                 return 0
76         }
77         miblen /= unsafe.Sizeof(uint32(0))
78         if miblen <= 0 {
79                 return 0
80         }
81         return uint32(miblen)
82 }
83
84 const (
85         _CPU_CURRENT_PID = -1 // Current process ID.
86 )
87
88 //go:noescape
89 func cpuset_getaffinity(level int, which int, id int64, size int, mask *byte) int32
90
91 //go:systemstack
92 func getncpu() int32 {
93         // Use a large buffer for the CPU mask. We're on the system
94         // stack, so this is fine, and we can't allocate memory for a
95         // dynamically-sized buffer at this point.
96         const maxCPUs = 64 * 1024
97         var mask [maxCPUs / 8]byte
98         var mib [_CTL_MAXNAME]uint32
99
100         // According to FreeBSD's /usr/src/sys/kern/kern_cpuset.c,
101         // cpuset_getaffinity return ERANGE when provided buffer size exceed the limits in kernel.
102         // Querying kern.smp.maxcpus to calculate maximum buffer size.
103         // See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=200802
104
105         // Variable kern.smp.maxcpus introduced at Dec 23 2003, revision 123766,
106         // with dynamically assigned sysctl entries.
107         miblen := sysctlnametomib([]byte("kern.smp.maxcpus"), &mib)
108         if miblen == 0 {
109                 return 1
110         }
111
112         // Query kern.smp.maxcpus.
113         dstsize := uintptr(4)
114         maxcpus := uint32(0)
115         if sysctl(&mib[0], miblen, (*byte)(unsafe.Pointer(&maxcpus)), &dstsize, nil, 0) != 0 {
116                 return 1
117         }
118
119         maskSize := int(maxcpus+7) / 8
120         if maskSize < goarch.PtrSize {
121                 maskSize = goarch.PtrSize
122         }
123         if maskSize > len(mask) {
124                 maskSize = len(mask)
125         }
126
127         if cpuset_getaffinity(_CPU_LEVEL_WHICH, _CPU_WHICH_PID, _CPU_CURRENT_PID,
128                 maskSize, (*byte)(unsafe.Pointer(&mask[0]))) != 0 {
129                 return 1
130         }
131         n := int32(0)
132         for _, v := range mask[:maskSize] {
133                 for v != 0 {
134                         n += int32(v & 1)
135                         v >>= 1
136                 }
137         }
138         if n == 0 {
139                 return 1
140         }
141         return n
142 }
143
144 func getPageSize() uintptr {
145         mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
146         out := uint32(0)
147         nout := unsafe.Sizeof(out)
148         ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
149         if ret >= 0 {
150                 return uintptr(out)
151         }
152         return 0
153 }
154
155 // FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
156 // thus the code is largely similar. See Linux implementation
157 // and lock_futex.go for comments.
158
159 //go:nosplit
160 func futexsleep(addr *uint32, val uint32, ns int64) {
161         systemstack(func() {
162                 futexsleep1(addr, val, ns)
163         })
164 }
165
166 func futexsleep1(addr *uint32, val uint32, ns int64) {
167         var utp *umtx_time
168         if ns >= 0 {
169                 var ut umtx_time
170                 ut._clockid = _CLOCK_MONOTONIC
171                 ut._timeout.setNsec(ns)
172                 utp = &ut
173         }
174         ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, unsafe.Sizeof(*utp), utp)
175         if ret >= 0 || ret == -_EINTR || ret == -_ETIMEDOUT {
176                 return
177         }
178         print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n")
179         *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
180 }
181
182 //go:nosplit
183 func futexwakeup(addr *uint32, cnt uint32) {
184         ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, 0, nil)
185         if ret >= 0 {
186                 return
187         }
188
189         systemstack(func() {
190                 print("umtx_wake_addr=", addr, " ret=", ret, "\n")
191         })
192 }
193
194 func thr_start()
195
196 // May run with m.p==nil, so write barriers are not allowed.
197 //
198 //go:nowritebarrier
199 func newosproc(mp *m) {
200         stk := unsafe.Pointer(mp.g0.stack.hi)
201         if false {
202                 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", abi.FuncPCABI0(thr_start), " id=", mp.id, " ostk=", &mp, "\n")
203         }
204
205         param := thrparam{
206                 start_func: abi.FuncPCABI0(thr_start),
207                 arg:        unsafe.Pointer(mp),
208                 stack_base: mp.g0.stack.lo,
209                 stack_size: uintptr(stk) - mp.g0.stack.lo,
210                 child_tid:  nil, // minit will record tid
211                 parent_tid: nil,
212                 tls_base:   unsafe.Pointer(&mp.tls[0]),
213                 tls_size:   unsafe.Sizeof(mp.tls),
214         }
215
216         var oset sigset
217         sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
218         ret := retryOnEAGAIN(func() int32 {
219                 errno := thr_new(&param, int32(unsafe.Sizeof(param)))
220                 // thr_new returns negative errno
221                 return -errno
222         })
223         sigprocmask(_SIG_SETMASK, &oset, nil)
224         if ret != 0 {
225                 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", ret, ")\n")
226                 throw("newosproc")
227         }
228 }
229
230 // Version of newosproc that doesn't require a valid G.
231 //
232 //go:nosplit
233 func newosproc0(stacksize uintptr, fn unsafe.Pointer) {
234         stack := sysAlloc(stacksize, &memstats.stacks_sys)
235         if stack == nil {
236                 writeErrStr(failallocatestack)
237                 exit(1)
238         }
239         // This code "knows" it's being called once from the library
240         // initialization code, and so it's using the static m0 for the
241         // tls and procid (thread) pointers. thr_new() requires the tls
242         // pointers, though the tid pointers can be nil.
243         // However, newosproc0 is currently unreachable because builds
244         // utilizing c-shared/c-archive force external linking.
245         param := thrparam{
246                 start_func: uintptr(fn),
247                 arg:        nil,
248                 stack_base: uintptr(stack), //+stacksize?
249                 stack_size: stacksize,
250                 child_tid:  nil, // minit will record tid
251                 parent_tid: nil,
252                 tls_base:   unsafe.Pointer(&m0.tls[0]),
253                 tls_size:   unsafe.Sizeof(m0.tls),
254         }
255
256         var oset sigset
257         sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
258         ret := thr_new(&param, int32(unsafe.Sizeof(param)))
259         sigprocmask(_SIG_SETMASK, &oset, nil)
260         if ret < 0 {
261                 writeErrStr(failthreadcreate)
262                 exit(1)
263         }
264 }
265
266 // Called to do synchronous initialization of Go code built with
267 // -buildmode=c-archive or -buildmode=c-shared.
268 // None of the Go runtime is initialized.
269 //
270 //go:nosplit
271 //go:nowritebarrierrec
272 func libpreinit() {
273         initsig(true)
274 }
275
276 func osinit() {
277         ncpu = getncpu()
278         if physPageSize == 0 {
279                 physPageSize = getPageSize()
280         }
281 }
282
283 var urandom_dev = []byte("/dev/urandom\x00")
284
285 //go:nosplit
286 func getRandomData(r []byte) {
287         fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
288         n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
289         closefd(fd)
290         extendRandom(r, int(n))
291 }
292
293 func goenvs() {
294         goenvs_unix()
295 }
296
297 // Called to initialize a new m (including the bootstrap m).
298 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
299 func mpreinit(mp *m) {
300         mp.gsignal = malg(32 * 1024)
301         mp.gsignal.m = mp
302 }
303
304 // Called to initialize a new m (including the bootstrap m).
305 // Called on the new thread, cannot allocate memory.
306 func minit() {
307         getg().m.procid = uint64(thr_self())
308
309         // On FreeBSD before about April 2017 there was a bug such
310         // that calling execve from a thread other than the main
311         // thread did not reset the signal stack. That would confuse
312         // minitSignals, which calls minitSignalStack, which checks
313         // whether there is currently a signal stack and uses it if
314         // present. To avoid this confusion, explicitly disable the
315         // signal stack on the main thread when not running in a
316         // library. This can be removed when we are confident that all
317         // FreeBSD users are running a patched kernel. See issue #15658.
318         if gp := getg(); !isarchive && !islibrary && gp.m == &m0 && gp == gp.m.g0 {
319                 st := stackt{ss_flags: _SS_DISABLE}
320                 sigaltstack(&st, nil)
321         }
322
323         minitSignals()
324 }
325
326 // Called from dropm to undo the effect of an minit.
327 //
328 //go:nosplit
329 func unminit() {
330         unminitSignals()
331         getg().m.procid = 0
332 }
333
334 // Called from exitm, but not from drop, to undo the effect of thread-owned
335 // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
336 func mdestroy(mp *m) {
337 }
338
339 func sigtramp()
340
341 type sigactiont struct {
342         sa_handler uintptr
343         sa_flags   int32
344         sa_mask    sigset
345 }
346
347 // See os_freebsd2.go, os_freebsd_amd64.go for setsig function
348
349 //go:nosplit
350 //go:nowritebarrierrec
351 func setsigstack(i uint32) {
352         var sa sigactiont
353         sigaction(i, nil, &sa)
354         if sa.sa_flags&_SA_ONSTACK != 0 {
355                 return
356         }
357         sa.sa_flags |= _SA_ONSTACK
358         sigaction(i, &sa, nil)
359 }
360
361 //go:nosplit
362 //go:nowritebarrierrec
363 func getsig(i uint32) uintptr {
364         var sa sigactiont
365         sigaction(i, nil, &sa)
366         return sa.sa_handler
367 }
368
369 // setSignalstackSP sets the ss_sp field of a stackt.
370 //
371 //go:nosplit
372 func setSignalstackSP(s *stackt, sp uintptr) {
373         s.ss_sp = sp
374 }
375
376 //go:nosplit
377 //go:nowritebarrierrec
378 func sigaddset(mask *sigset, i int) {
379         mask.__bits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
380 }
381
382 func sigdelset(mask *sigset, i int) {
383         mask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
384 }
385
386 //go:nosplit
387 func (c *sigctxt) fixsigcode(sig uint32) {
388 }
389
390 func setProcessCPUProfiler(hz int32) {
391         setProcessCPUProfilerTimer(hz)
392 }
393
394 func setThreadCPUProfiler(hz int32) {
395         setThreadCPUProfilerHz(hz)
396 }
397
398 //go:nosplit
399 func validSIGPROF(mp *m, c *sigctxt) bool {
400         return true
401 }
402
403 func sysargs(argc int32, argv **byte) {
404         n := argc + 1
405
406         // skip over argv, envp to get to auxv
407         for argv_index(argv, n) != nil {
408                 n++
409         }
410
411         // skip NULL separator
412         n++
413
414         // now argv+n is auxv
415         auxvp := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*goarch.PtrSize))
416         pairs := sysauxv(auxvp[:])
417         auxv = auxvp[: pairs*2 : pairs*2]
418 }
419
420 const (
421         _AT_NULL     = 0  // Terminates the vector
422         _AT_PAGESZ   = 6  // Page size in bytes
423         _AT_PLATFORM = 15 // string identifying platform
424         _AT_TIMEKEEP = 22 // Pointer to timehands.
425         _AT_HWCAP    = 25 // CPU feature flags
426         _AT_HWCAP2   = 26 // CPU feature flags 2
427 )
428
429 func sysauxv(auxv []uintptr) (pairs int) {
430         var i int
431         for i = 0; auxv[i] != _AT_NULL; i += 2 {
432                 tag, val := auxv[i], auxv[i+1]
433                 switch tag {
434                 // _AT_NCPUS from auxv shouldn't be used due to golang.org/issue/15206
435                 case _AT_PAGESZ:
436                         physPageSize = val
437                 case _AT_TIMEKEEP:
438                         timekeepSharedPage = (*vdsoTimekeep)(unsafe.Pointer(val))
439                 }
440
441                 archauxv(tag, val)
442         }
443         return i / 2
444 }
445
446 // sysSigaction calls the sigaction system call.
447 //
448 //go:nosplit
449 func sysSigaction(sig uint32, new, old *sigactiont) {
450         // Use system stack to avoid split stack overflow on amd64
451         if asmSigaction(uintptr(sig), new, old) != 0 {
452                 systemstack(func() {
453                         throw("sigaction failed")
454                 })
455         }
456 }
457
458 // asmSigaction is implemented in assembly.
459 //
460 //go:noescape
461 func asmSigaction(sig uintptr, new, old *sigactiont) int32
462
463 // raise sends a signal to the calling thread.
464 //
465 // It must be nosplit because it is used by the signal handler before
466 // it definitely has a Go stack.
467 //
468 //go:nosplit
469 func raise(sig uint32) {
470         thr_kill(thr_self(), int(sig))
471 }
472
473 func signalM(mp *m, sig int) {
474         thr_kill(thread(mp.procid), sig)
475 }
476
477 // sigPerThreadSyscall is only used on linux, so we assign a bogus signal
478 // number.
479 const sigPerThreadSyscall = 1 << 31
480
481 //go:nosplit
482 func runPerThreadSyscall() {
483         throw("runPerThreadSyscall only valid on linux")
484 }