1
0
mirror of https://github.com/golang/go synced 2024-10-03 14:21:22 -06:00
go/src/runtime/os1_openbsd.go
Matthew Dempsky 5324cf2d45 runtime: change sigset_all and sigset_none into constants on OpenBSD
OpenBSD's sigprocmask system call passes the signal mask by value
rather than reference, so vars are unnecessary.  Additionally,
declaring "var sigset_all = ^sigset_none" means sigset_all won't be
initialized until runtime_init is called, but the first call to
newosproc happens before then.

I've witnessed Go processes on OpenBSD crash from receiving SIGWINCH
on the newly created OS thread before it finished initializing.

Change-Id: I16995e7e466d5e7e50bcaa7d9490173789a0b4cc
Reviewed-on: https://go-review.googlesource.com/6440
Reviewed-by: Mikio Hara <mikioh.mikioh@gmail.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2015-03-02 08:30:39 +00:00

224 lines
4.7 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
_EAGAIN = 35
_EWOULDBLOCK = _EAGAIN
_ENOTSUP = 91
// From OpenBSD's sys/time.h
_CLOCK_REALTIME = 0
_CLOCK_VIRTUAL = 1
_CLOCK_PROF = 2
_CLOCK_MONOTONIC = 3
)
const (
sigset_none = uint32(0)
sigset_all = ^uint32(0)
)
// From OpenBSD'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)
// 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
}
//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(int64(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 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) {
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")
})
}
}
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
param := tforkt{
tf_tcb: unsafe.Pointer(&mp.tls[0]),
tf_tid: (*int32)(unsafe.Pointer(&mp.procid)),
tf_stack: uintptr(stk),
}
oset := sigprocmask(_SIG_SETMASK, sigset_all)
ret := tfork(&param, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
sigprocmask(_SIG_SETMASK, oset)
if ret < 0 {
print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
if ret == -_ENOTSUP {
print("runtime: is kern.rthreads disabled?\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)))
close(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() {
_g_ := getg()
// m.procid is a uint64, but tfork writes an int32. Fix it up.
_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
// Initialize signal handling
signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
sigprocmask(_SIG_SETMASK, sigset_none)
}
// Called from dropm to undo the effect of an minit.
func unminit() {
signalstack(nil, 0)
}
func memlimit() uintptr {
return 0
}
func sigtramp()
type sigactiont struct {
sa_sigaction uintptr
sa_mask uint32
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(p *byte, n int32) {
var st stackt
st.ss_sp = uintptr(unsafe.Pointer(p))
st.ss_size = uintptr(n)
st.ss_flags = 0
if p == nil {
st.ss_flags = _SS_DISABLE
}
sigaltstack(&st, nil)
}
func unblocksignals() {
sigprocmask(_SIG_SETMASK, sigset_none)
}