1
0
mirror of https://github.com/golang/go synced 2024-11-20 06:34:40 -07:00
go/src/runtime/os1_netbsd.go
Austin Clements c02b8911d8 runtime: clean up signalstack API
Currently signalstack takes a lower limit and a length and all calls
hard-code the passed length. Change the API to take a *stack and
compute the lower limit and length from the passed stack.

This will make it easier for the runtime to steal some space from the
top of the stack since it eliminates the hard-coded stack sizes.

Change-Id: I7d2a9f45894b221f4e521628c2165530bbc57d53
Reviewed-on: https://go-review.googlesource.com/10311
Reviewed-by: Rick Hudson <rlh@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2015-06-02 19:57:42 +00:00

233 lines
5.0 KiB
Go

// 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 "unsafe"
const (
_ESRCH = 3
_ETIMEDOUT = 60
// From NetBSD's <sys/time.h>
_CLOCK_REALTIME = 0
_CLOCK_VIRTUAL = 1
_CLOCK_PROF = 2
_CLOCK_MONOTONIC = 3
)
var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
// From NetBSD's <sys/sysctl.h>
const (
_CTL_HW = 6
_HW_NCPU = 3
)
func getncpu() int32 {
mib := [2]uint32{_CTL_HW, _HW_NCPU}
out := uint32(0)
nout := unsafe.Sizeof(out)
ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
if ret >= 0 {
return int32(out)
}
return 1
}
//go:nosplit
func semacreate() uintptr {
return 1
}
//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(timediv(ns, 1000000000, &nsec))
ts.set_nsec(nsec)
tsp = &ts
}
for {
v := atomicload(&_g_.m.waitsemacount)
if v > 0 {
if cas(&_g_.m.waitsemacount, v, v-1) {
return 0 // semaphore acquired
}
continue
}
// Sleep until unparked by semawakeup or timeout.
ret := lwp_park(tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil)
if ret == _ETIMEDOUT {
return -1
}
}
}
//go:nosplit
func semawakeup(mp *m) {
xadd(&mp.waitsemacount, 1)
// From NetBSD's _lwp_unpark(2) manual:
// "If the target LWP is not currently waiting, it will return
// immediately upon the next call to _lwp_park()."
ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount))
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, "/", int32(mp.tls[0]), " ostk=", &mp, "\n")
}
mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
var uc ucontextt
getcontext(unsafe.Pointer(&uc))
uc.uc_flags = _UC_SIGMASK | _UC_CPU
uc.uc_link = nil
uc.uc_sigmask = sigset_all
lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, funcPC(mstart))
ret := lwp_create(unsafe.Pointer(&uc), 0, unsafe.Pointer(&mp.procid))
if ret < 0 {
print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
throw("runtime.newosproc")
}
}
func osinit() {
ncpu = getncpu()
}
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
}
func msigsave(mp *m) {
smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
throw("insufficient storage for signal mask")
}
sigprocmask(_SIG_SETMASK, nil, smask)
}
// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory.
func minit() {
_g_ := getg()
_g_.m.procid = uint64(lwp_self())
// Initialize signal handling
signalstack(&_g_.m.gsignal.stack)
// restore signal mask from m.sigmask and unblock essential signals
nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
for i := range sigtable {
if sigtable[i].flags&_SigUnblock != 0 {
nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
}
}
sigprocmask(_SIG_SETMASK, &nmask, nil)
}
// Called from dropm to undo the effect of an minit.
func unminit() {
_g_ := getg()
smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
sigprocmask(_SIG_SETMASK, smask, nil)
signalstack(nil)
}
func memlimit() uintptr {
return 0
}
func sigtramp()
type sigactiont struct {
sa_sigaction uintptr
sa_mask sigset
sa_flags int32
}
func setsig(i int32, fn uintptr, restart bool) {
var sa sigactiont
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
if restart {
sa.sa_flags |= _SA_RESTART
}
sa.sa_mask = sigset_all
if fn == funcPC(sighandler) {
fn = funcPC(sigtramp)
}
sa.sa_sigaction = fn
sigaction(i, &sa, nil)
}
func setsigstack(i int32) {
throw("setsigstack")
}
func getsig(i int32) uintptr {
var sa sigactiont
sigaction(i, nil, &sa)
if sa.sa_sigaction == funcPC(sigtramp) {
return funcPC(sighandler)
}
return sa.sa_sigaction
}
func signalstack(s *stack) {
var st sigaltstackt
if s == nil {
st.ss_flags = _SS_DISABLE
} else {
st.ss_sp = s.lo
st.ss_size = s.hi - s.lo
st.ss_flags = 0
}
sigaltstack(&st, nil)
}
func updatesigmask(m sigmask) {
var mask sigset
copy(mask.__bits[:], m[:])
sigprocmask(_SIG_SETMASK, &mask, nil)
}