|  | // Copyright 2011 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package runtime | 
|  |  | 
|  | import ( | 
|  | "runtime/internal/atomic" | 
|  | "unsafe" | 
|  | ) | 
|  |  | 
|  | type mOS struct { | 
|  | waitsemacount uint32 | 
|  | } | 
|  |  | 
|  | //go:noescape | 
|  | func setitimer(mode int32, new, old *itimerval) | 
|  |  | 
|  | //go:noescape | 
|  | func sigaction(sig uint32, new, old *sigactiont) | 
|  |  | 
|  | //go:noescape | 
|  | func sigaltstack(new, old *stackt) | 
|  |  | 
|  | //go:noescape | 
|  | func obsdsigprocmask(how int32, new sigset) sigset | 
|  |  | 
|  | //go:nosplit | 
|  | //go:nowritebarrierrec | 
|  | func sigprocmask(how int32, new, old *sigset) { | 
|  | n := sigset(0) | 
|  | if new != nil { | 
|  | n = *new | 
|  | } | 
|  | r := obsdsigprocmask(how, n) | 
|  | if old != nil { | 
|  | *old = r | 
|  | } | 
|  | } | 
|  |  | 
|  | //go:noescape | 
|  | func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 | 
|  |  | 
|  | func raise(sig uint32) | 
|  | func raiseproc(sig uint32) | 
|  |  | 
|  | //go:noescape | 
|  | func tfork(param *tforkt, psize uintptr, mm *m, gg *g, fn uintptr) int32 | 
|  |  | 
|  | //go:noescape | 
|  | func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32 | 
|  |  | 
|  | //go:noescape | 
|  | func thrwakeup(ident uintptr, n int32) int32 | 
|  |  | 
|  | func osyield() | 
|  |  | 
|  | const ( | 
|  | _ESRCH       = 3 | 
|  | _EAGAIN      = 35 | 
|  | _EWOULDBLOCK = _EAGAIN | 
|  | _ENOTSUP     = 91 | 
|  |  | 
|  | // From OpenBSD's sys/time.h | 
|  | _CLOCK_REALTIME  = 0 | 
|  | _CLOCK_VIRTUAL   = 1 | 
|  | _CLOCK_PROF      = 2 | 
|  | _CLOCK_MONOTONIC = 3 | 
|  | ) | 
|  |  | 
|  | type sigset uint32 | 
|  |  | 
|  | var sigset_all = ^sigset(0) | 
|  |  | 
|  | // From OpenBSD's <sys/sysctl.h> | 
|  | const ( | 
|  | _CTL_HW      = 6 | 
|  | _HW_NCPU     = 3 | 
|  | _HW_PAGESIZE = 7 | 
|  | ) | 
|  |  | 
|  | func getncpu() int32 { | 
|  | mib := [2]uint32{_CTL_HW, _HW_NCPU} | 
|  | out := uint32(0) | 
|  | nout := unsafe.Sizeof(out) | 
|  |  | 
|  | // Fetch hw.ncpu via sysctl. | 
|  | ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) | 
|  | if ret >= 0 { | 
|  | return int32(out) | 
|  | } | 
|  | return 1 | 
|  | } | 
|  |  | 
|  | func getPageSize() uintptr { | 
|  | mib := [2]uint32{_CTL_HW, _HW_PAGESIZE} | 
|  | out := uint32(0) | 
|  | nout := unsafe.Sizeof(out) | 
|  | ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) | 
|  | if ret >= 0 { | 
|  | return uintptr(out) | 
|  | } | 
|  | return 0 | 
|  | } | 
|  |  | 
|  | //go:nosplit | 
|  | func semacreate(mp *m) { | 
|  | } | 
|  |  | 
|  | //go:nosplit | 
|  | func semasleep(ns int64) int32 { | 
|  | _g_ := getg() | 
|  |  | 
|  | // Compute sleep deadline. | 
|  | var tsp *timespec | 
|  | if ns >= 0 { | 
|  | var ts timespec | 
|  | var nsec int32 | 
|  | ns += nanotime() | 
|  | ts.set_sec(int64(timediv(ns, 1000000000, &nsec))) | 
|  | ts.set_nsec(nsec) | 
|  | tsp = &ts | 
|  | } | 
|  |  | 
|  | for { | 
|  | v := atomic.Load(&_g_.m.waitsemacount) | 
|  | if v > 0 { | 
|  | if atomic.Cas(&_g_.m.waitsemacount, v, v-1) { | 
|  | return 0 // semaphore acquired | 
|  | } | 
|  | continue | 
|  | } | 
|  |  | 
|  | // Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0. | 
|  | // | 
|  | // From OpenBSD's __thrsleep(2) manual: | 
|  | // "The abort argument, if not NULL, points to an int that will | 
|  | // be examined [...] immediately before blocking. If that int | 
|  | // is non-zero then __thrsleep() will immediately return EINTR | 
|  | // without blocking." | 
|  | ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount) | 
|  | if ret == _EWOULDBLOCK { | 
|  | return -1 | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | //go:nosplit | 
|  | func semawakeup(mp *m) { | 
|  | atomic.Xadd(&mp.waitsemacount, 1) | 
|  | ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1) | 
|  | if ret != 0 && ret != _ESRCH { | 
|  | // semawakeup can be called on signal stack. | 
|  | systemstack(func() { | 
|  | print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n") | 
|  | }) | 
|  | } | 
|  | } | 
|  |  | 
|  | // May run with m.p==nil, so write barriers are not allowed. | 
|  | //go:nowritebarrier | 
|  | func newosproc(mp *m, stk unsafe.Pointer) { | 
|  | if false { | 
|  | print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n") | 
|  | } | 
|  |  | 
|  | param := tforkt{ | 
|  | tf_tcb:   unsafe.Pointer(&mp.tls[0]), | 
|  | tf_tid:   (*int32)(unsafe.Pointer(&mp.procid)), | 
|  | tf_stack: uintptr(stk), | 
|  | } | 
|  |  | 
|  | var oset sigset | 
|  | sigprocmask(_SIG_SETMASK, &sigset_all, &oset) | 
|  | ret := tfork(¶m, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart)) | 
|  | sigprocmask(_SIG_SETMASK, &oset, nil) | 
|  |  | 
|  | if ret < 0 { | 
|  | print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n") | 
|  | if ret == -_EAGAIN { | 
|  | println("runtime: may need to increase max user processes (ulimit -p)") | 
|  | } | 
|  | throw("runtime.newosproc") | 
|  | } | 
|  | } | 
|  |  | 
|  | func osinit() { | 
|  | ncpu = getncpu() | 
|  | physPageSize = getPageSize() | 
|  | } | 
|  |  | 
|  | var urandom_dev = []byte("/dev/urandom\x00") | 
|  |  | 
|  | //go:nosplit | 
|  | func getRandomData(r []byte) { | 
|  | fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) | 
|  | n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) | 
|  | closefd(fd) | 
|  | extendRandom(r, int(n)) | 
|  | } | 
|  |  | 
|  | func goenvs() { | 
|  | goenvs_unix() | 
|  | } | 
|  |  | 
|  | // Called to initialize a new m (including the bootstrap m). | 
|  | // Called on the parent thread (main thread in case of bootstrap), can allocate memory. | 
|  | func mpreinit(mp *m) { | 
|  | mp.gsignal = malg(32 * 1024) | 
|  | mp.gsignal.m = mp | 
|  | } | 
|  |  | 
|  | // Called to initialize a new m (including the bootstrap m). | 
|  | // Called on the new thread, can not allocate memory. | 
|  | func minit() { | 
|  | // m.procid is a uint64, but tfork writes an int32. Fix it up. | 
|  | _g_ := getg() | 
|  | _g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid))) | 
|  |  | 
|  | minitSignals() | 
|  | } | 
|  |  | 
|  | // Called from dropm to undo the effect of an minit. | 
|  | //go:nosplit | 
|  | func unminit() { | 
|  | unminitSignals() | 
|  | } | 
|  |  | 
|  | func memlimit() uintptr { | 
|  | return 0 | 
|  | } | 
|  |  | 
|  | func sigtramp() | 
|  |  | 
|  | type sigactiont struct { | 
|  | sa_sigaction uintptr | 
|  | sa_mask      uint32 | 
|  | sa_flags     int32 | 
|  | } | 
|  |  | 
|  | //go:nosplit | 
|  | //go:nowritebarrierrec | 
|  | func setsig(i uint32, fn uintptr) { | 
|  | var sa sigactiont | 
|  | sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART | 
|  | sa.sa_mask = uint32(sigset_all) | 
|  | if fn == funcPC(sighandler) { | 
|  | fn = funcPC(sigtramp) | 
|  | } | 
|  | sa.sa_sigaction = fn | 
|  | sigaction(i, &sa, nil) | 
|  | } | 
|  |  | 
|  | //go:nosplit | 
|  | //go:nowritebarrierrec | 
|  | func setsigstack(i uint32) { | 
|  | throw("setsigstack") | 
|  | } | 
|  |  | 
|  | //go:nosplit | 
|  | //go:nowritebarrierrec | 
|  | func getsig(i uint32) uintptr { | 
|  | var sa sigactiont | 
|  | sigaction(i, nil, &sa) | 
|  | return sa.sa_sigaction | 
|  | } | 
|  |  | 
|  | // setSignaltstackSP sets the ss_sp field of a stackt. | 
|  | //go:nosplit | 
|  | func setSignalstackSP(s *stackt, sp uintptr) { | 
|  | s.ss_sp = sp | 
|  | } | 
|  |  | 
|  | //go:nosplit | 
|  | //go:nowritebarrierrec | 
|  | func sigaddset(mask *sigset, i int) { | 
|  | *mask |= 1 << (uint32(i) - 1) | 
|  | } | 
|  |  | 
|  | func sigdelset(mask *sigset, i int) { | 
|  | *mask &^= 1 << (uint32(i) - 1) | 
|  | } | 
|  |  | 
|  | func (c *sigctxt) fixsigcode(sig uint32) { | 
|  | } |