From 8455f3a3d5f2879e8574882978e7646db1ebabb5 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 6 Apr 2016 04:38:00 +0000 Subject: [PATCH] os: consolidate os{1,2}_*.go files Change-Id: I463ca59f486b2842f67f151a55f530ee10663830 Reviewed-on: https://go-review.googlesource.com/21568 Run-TryBot: Brad Fitzpatrick Reviewed-by: Dave Cheney Reviewed-by: Minux Ma TryBot-Result: Gobot Gobot --- src/runtime/os1_dragonfly.go | 270 ----------------- src/runtime/os1_linux_generic.go | 28 -- src/runtime/os1_linux_mips64x.go | 26 -- src/runtime/os1_netbsd.go | 275 ----------------- src/runtime/os2_dragonfly.go | 15 - src/runtime/os2_linux_mips64x.go | 25 -- src/runtime/os2_netbsd.go | 18 -- src/runtime/os_dragonfly.go | 273 +++++++++++++++++ ...2_linux_generic.go => os_linux_generic.go} | 18 ++ src/runtime/os_linux_mips64x.go | 37 ++- src/runtime/os_netbsd.go | 283 +++++++++++++++++- .../{os1_netbsd_386.go => os_netbsd_386.go} | 0 ...os1_netbsd_amd64.go => os_netbsd_amd64.go} | 0 13 files changed, 609 insertions(+), 659 deletions(-) delete mode 100644 src/runtime/os1_dragonfly.go delete mode 100644 src/runtime/os1_linux_generic.go delete mode 100644 src/runtime/os1_linux_mips64x.go delete mode 100644 src/runtime/os1_netbsd.go delete mode 100644 src/runtime/os2_dragonfly.go delete mode 100644 src/runtime/os2_linux_mips64x.go delete mode 100644 src/runtime/os2_netbsd.go rename src/runtime/{os2_linux_generic.go => os_linux_generic.go} (63%) rename src/runtime/{os1_netbsd_386.go => os_netbsd_386.go} (100%) rename src/runtime/{os1_netbsd_amd64.go => os_netbsd_amd64.go} (100%) diff --git a/src/runtime/os1_dragonfly.go b/src/runtime/os1_dragonfly.go deleted file mode 100644 index d7044ae4b0..0000000000 --- a/src/runtime/os1_dragonfly.go +++ /dev/null @@ -1,270 +0,0 @@ -// 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" - -// From DragonFly's -const ( - _CTL_HW = 6 - _HW_NCPU = 3 -) - -var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}} - -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 futexsleep(addr *uint32, val uint32, ns int64) { - systemstack(func() { - futexsleep1(addr, val, ns) - }) -} - -func futexsleep1(addr *uint32, val uint32, ns int64) { - var timeout int32 - if ns >= 0 { - // The timeout is specified in microseconds - ensure that we - // do not end up dividing to zero, which would put us to sleep - // indefinitely... - timeout = timediv(ns, 1000, nil) - if timeout == 0 { - timeout = 1 - } - } - - // sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout - // expires or EBUSY if the mutex value does not match. - ret := sys_umtx_sleep(addr, int32(val), timeout) - if ret >= 0 || ret == -_EINTR || ret == -_EAGAIN || ret == -_EBUSY { - return - } - - print("umtx_sleep addr=", addr, " val=", val, " ret=", ret, "\n") - *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005 -} - -//go:nosplit -func futexwakeup(addr *uint32, cnt uint32) { - ret := sys_umtx_wakeup(addr, int32(cnt)) - if ret >= 0 { - return - } - - systemstack(func() { - print("umtx_wake_addr=", addr, " ret=", ret, "\n") - *(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006 - }) -} - -func lwp_start(uintptr) - -// 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, " lwp_start=", funcPC(lwp_start), " id=", mp.id, " ostk=", &mp, "\n") - } - - var oset sigset - sigprocmask(_SIG_SETMASK, &sigset_all, &oset) - - params := lwpparams{ - start_func: funcPC(lwp_start), - arg: unsafe.Pointer(mp), - stack: uintptr(stk), - tid1: unsafe.Pointer(&mp.procid), - tid2: nil, - } - - lwp_create(¶ms) - sigprocmask(_SIG_SETMASK, &oset, nil) -} - -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 -} - -//go:nosplit -func msigsave(mp *m) { - sigprocmask(_SIG_SETMASK, nil, &mp.sigmask) -} - -//go:nosplit -func msigrestore(sigmask sigset) { - sigprocmask(_SIG_SETMASK, &sigmask, nil) -} - -//go:nosplit -func sigblock() { - sigprocmask(_SIG_SETMASK, &sigset_all, nil) -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, cannot allocate memory. -func minit() { - _g_ := getg() - - // m.procid is a uint64, but lwp_start writes an int32. Fix it up. - _g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid))) - - // Initialize signal handling. - - // On DragonFly a thread created by pthread_create inherits - // the signal stack of the creating thread. We always create - // a new signal stack here, to avoid having two Go threads - // using the same signal stack. This breaks the case of a - // thread created in C that calls sigaltstack and then calls a - // Go function, because we will lose track of the C code's - // sigaltstack, but it's the best we can do. - signalstack(&_g_.m.gsignal.stack) - _g_.m.newSigstack = true - - // restore signal mask from m.sigmask and unblock essential signals - nmask := _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. -//go:nosplit -func unminit() { - if getg().m.newSigstack { - signalstack(nil) - } -} - -func memlimit() uintptr { - /* - TODO: Convert to Go when something actually uses the result. - - Rlimit rl; - extern byte runtime·text[], runtime·end[]; - uintptr used; - - if(runtime·getrlimit(RLIMIT_AS, &rl) != 0) - return 0; - if(rl.rlim_cur >= 0x7fffffff) - return 0; - - // Estimate our VM footprint excluding the heap. - // Not an exact science: use size of binary plus - // some room for thread stacks. - used = runtime·end - runtime·text + (64<<20); - if(used >= rl.rlim_cur) - return 0; - - // If there's not at least 16 MB left, we're probably - // not going to be able to do much. Treat as no limit. - rl.rlim_cur -= used; - if(rl.rlim_cur < (16<<20)) - return 0; - - return rl.rlim_cur - used; - */ - return 0 -} - -func sigtramp() - -type sigactiont struct { - sa_sigaction uintptr - sa_flags int32 - sa_mask sigset -} - -//go:nosplit -//go:nowritebarrierrec -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) -} - -//go:nosplit -//go:nowritebarrierrec -func setsigstack(i int32) { - throw("setsigstack") -} - -//go:nosplit -//go:nowritebarrierrec -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 -} - -//go:nosplit -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) -} - -//go:nosplit -//go:nowritebarrierrec -func updatesigmask(m sigmask) { - var mask sigset - copy(mask.__bits[:], m[:]) - sigprocmask(_SIG_SETMASK, &mask, nil) -} - -func unblocksig(sig int32) { - var mask sigset - mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31) - sigprocmask(_SIG_UNBLOCK, &mask, nil) -} diff --git a/src/runtime/os1_linux_generic.go b/src/runtime/os1_linux_generic.go deleted file mode 100644 index 50d6d6afb4..0000000000 --- a/src/runtime/os1_linux_generic.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2009 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. - -// +build !mips64 -// +build !mips64le -// +build !s390x -// +build linux - -package runtime - -var sigset_all = sigset{^uint32(0), ^uint32(0)} - -func sigaddset(mask *sigset, i int) { - (*mask)[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31) -} - -func sigdelset(mask *sigset, i int) { - (*mask)[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31) -} - -func sigfillset(mask *uint64) { - *mask = ^uint64(0) -} - -func sigcopyset(mask *sigset, m sigmask) { - copy((*mask)[:], m[:]) -} diff --git a/src/runtime/os1_linux_mips64x.go b/src/runtime/os1_linux_mips64x.go deleted file mode 100644 index 701e979102..0000000000 --- a/src/runtime/os1_linux_mips64x.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2015 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. - -// +build mips64 mips64le -// +build linux - -package runtime - -var sigset_all = sigset{^uint64(0), ^uint64(0)} - -func sigaddset(mask *sigset, i int) { - (*mask)[(i-1)/64] |= 1 << ((uint32(i) - 1) & 63) -} - -func sigdelset(mask *sigset, i int) { - (*mask)[(i-1)/64] &^= 1 << ((uint32(i) - 1) & 63) -} - -func sigfillset(mask *[2]uint64) { - (*mask)[0], (*mask)[1] = ^uint64(0), ^uint64(0) -} - -func sigcopyset(mask *sigset, m sigmask) { - (*mask)[0] = uint64(m[0]) | uint64(m[1])<<32 -} diff --git a/src/runtime/os1_netbsd.go b/src/runtime/os1_netbsd.go deleted file mode 100644 index 3c3b64186d..0000000000 --- a/src/runtime/os1_netbsd.go +++ /dev/null @@ -1,275 +0,0 @@ -// 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" -) - -const ( - _ESRCH = 3 - _ETIMEDOUT = 60 - - // From NetBSD's - _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 -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(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(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 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) { - atomic.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, " ostk=", &mp, "\n") - } - - 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(netbsdMstart)) - - 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") - } -} - -// netbsdMStart is the function call that starts executing a newly -// created thread. On NetBSD, a new thread inherits the signal stack -// of the creating thread. That confuses minit, so we remove that -// signal stack here before calling the regular mstart. It's a bit -// baroque to remove a signal stack here only to add one in minit, but -// it's a simple change that keeps NetBSD working like other OS's. -// At this point all signals are blocked, so there is no race. -//go:nosplit -func netbsdMstart() { - signalstack(nil) - mstart() -} - -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 -} - -//go:nosplit -func msigsave(mp *m) { - sigprocmask(_SIG_SETMASK, nil, &mp.sigmask) -} - -//go:nosplit -func msigrestore(sigmask sigset) { - sigprocmask(_SIG_SETMASK, &sigmask, nil) -} - -//go:nosplit -func sigblock() { - sigprocmask(_SIG_SETMASK, &sigset_all, nil) -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, cannot allocate memory. -func minit() { - _g_ := getg() - _g_.m.procid = uint64(lwp_self()) - - // Initialize signal handling. - - // On NetBSD a thread created by pthread_create inherits the - // signal stack of the creating thread. We always create a - // new signal stack here, to avoid having two Go threads using - // the same signal stack. This breaks the case of a thread - // created in C that calls sigaltstack and then calls a Go - // function, because we will lose track of the C code's - // sigaltstack, but it's the best we can do. - signalstack(&_g_.m.gsignal.stack) - _g_.m.newSigstack = true - - // restore signal mask from m.sigmask and unblock essential signals - nmask := _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. -//go:nosplit -func unminit() { - if getg().m.newSigstack { - signalstack(nil) - } -} - -func memlimit() uintptr { - return 0 -} - -func sigtramp() - -type sigactiont struct { - sa_sigaction uintptr - sa_mask sigset - sa_flags int32 -} - -//go:nosplit -//go:nowritebarrierrec -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) -} - -//go:nosplit -//go:nowritebarrierrec -func setsigstack(i int32) { - throw("setsigstack") -} - -//go:nosplit -//go:nowritebarrierrec -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 -} - -//go:nosplit -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) -} - -//go:nosplit -//go:nowritebarrierrec -func updatesigmask(m sigmask) { - var mask sigset - copy(mask.__bits[:], m[:]) - sigprocmask(_SIG_SETMASK, &mask, nil) -} - -func unblocksig(sig int32) { - var mask sigset - mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31) - sigprocmask(_SIG_UNBLOCK, &mask, nil) -} diff --git a/src/runtime/os2_dragonfly.go b/src/runtime/os2_dragonfly.go deleted file mode 100644 index 6ea2da0393..0000000000 --- a/src/runtime/os2_dragonfly.go +++ /dev/null @@ -1,15 +0,0 @@ -// 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 - -const ( - _NSIG = 33 - _SI_USER = 0 - _SS_DISABLE = 4 - _RLIMIT_AS = 10 - _SIG_BLOCK = 1 - _SIG_UNBLOCK = 2 - _SIG_SETMASK = 3 -) diff --git a/src/runtime/os2_linux_mips64x.go b/src/runtime/os2_linux_mips64x.go deleted file mode 100644 index 9a6a92a87d..0000000000 --- a/src/runtime/os2_linux_mips64x.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015 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. - -// +build linux -// +build mips64 mips64le - -package runtime - -const ( - _SS_DISABLE = 2 - _NSIG = 65 - _SI_USER = 0 - _SIG_BLOCK = 1 - _SIG_UNBLOCK = 2 - _SIG_SETMASK = 3 - _RLIMIT_AS = 6 -) - -type sigset [2]uint64 - -type rlimit struct { - rlim_cur uintptr - rlim_max uintptr -} diff --git a/src/runtime/os2_netbsd.go b/src/runtime/os2_netbsd.go deleted file mode 100644 index 405dd5e727..0000000000 --- a/src/runtime/os2_netbsd.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2010 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 - -const ( - _SS_DISABLE = 4 - _SIG_BLOCK = 1 - _SIG_UNBLOCK = 2 - _SIG_SETMASK = 3 - _NSIG = 33 - _SI_USER = 0 - - // From NetBSD's - _UC_SIGMASK = 0x01 - _UC_CPU = 0x04 -) diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go index c3833a397a..78a150eee5 100644 --- a/src/runtime/os_dragonfly.go +++ b/src/runtime/os_dragonfly.go @@ -6,6 +6,16 @@ package runtime import "unsafe" +const ( + _NSIG = 33 + _SI_USER = 0 + _SS_DISABLE = 4 + _RLIMIT_AS = 10 + _SIG_BLOCK = 1 + _SIG_UNBLOCK = 2 + _SIG_SETMASK = 3 +) + type mOS struct{} //go:noescape @@ -41,3 +51,266 @@ func sys_umtx_wakeup(addr *uint32, val int32) int32 func osyield() const stackSystem = 0 + +// From DragonFly's +const ( + _CTL_HW = 6 + _HW_NCPU = 3 +) + +var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}} + +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 futexsleep(addr *uint32, val uint32, ns int64) { + systemstack(func() { + futexsleep1(addr, val, ns) + }) +} + +func futexsleep1(addr *uint32, val uint32, ns int64) { + var timeout int32 + if ns >= 0 { + // The timeout is specified in microseconds - ensure that we + // do not end up dividing to zero, which would put us to sleep + // indefinitely... + timeout = timediv(ns, 1000, nil) + if timeout == 0 { + timeout = 1 + } + } + + // sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout + // expires or EBUSY if the mutex value does not match. + ret := sys_umtx_sleep(addr, int32(val), timeout) + if ret >= 0 || ret == -_EINTR || ret == -_EAGAIN || ret == -_EBUSY { + return + } + + print("umtx_sleep addr=", addr, " val=", val, " ret=", ret, "\n") + *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005 +} + +//go:nosplit +func futexwakeup(addr *uint32, cnt uint32) { + ret := sys_umtx_wakeup(addr, int32(cnt)) + if ret >= 0 { + return + } + + systemstack(func() { + print("umtx_wake_addr=", addr, " ret=", ret, "\n") + *(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006 + }) +} + +func lwp_start(uintptr) + +// 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, " lwp_start=", funcPC(lwp_start), " id=", mp.id, " ostk=", &mp, "\n") + } + + var oset sigset + sigprocmask(_SIG_SETMASK, &sigset_all, &oset) + + params := lwpparams{ + start_func: funcPC(lwp_start), + arg: unsafe.Pointer(mp), + stack: uintptr(stk), + tid1: unsafe.Pointer(&mp.procid), + tid2: nil, + } + + lwp_create(¶ms) + sigprocmask(_SIG_SETMASK, &oset, nil) +} + +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 +} + +//go:nosplit +func msigsave(mp *m) { + sigprocmask(_SIG_SETMASK, nil, &mp.sigmask) +} + +//go:nosplit +func msigrestore(sigmask sigset) { + sigprocmask(_SIG_SETMASK, &sigmask, nil) +} + +//go:nosplit +func sigblock() { + sigprocmask(_SIG_SETMASK, &sigset_all, nil) +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, cannot allocate memory. +func minit() { + _g_ := getg() + + // m.procid is a uint64, but lwp_start writes an int32. Fix it up. + _g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid))) + + // Initialize signal handling. + + // On DragonFly a thread created by pthread_create inherits + // the signal stack of the creating thread. We always create + // a new signal stack here, to avoid having two Go threads + // using the same signal stack. This breaks the case of a + // thread created in C that calls sigaltstack and then calls a + // Go function, because we will lose track of the C code's + // sigaltstack, but it's the best we can do. + signalstack(&_g_.m.gsignal.stack) + _g_.m.newSigstack = true + + // restore signal mask from m.sigmask and unblock essential signals + nmask := _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. +//go:nosplit +func unminit() { + if getg().m.newSigstack { + signalstack(nil) + } +} + +func memlimit() uintptr { + /* + TODO: Convert to Go when something actually uses the result. + + Rlimit rl; + extern byte runtime·text[], runtime·end[]; + uintptr used; + + if(runtime·getrlimit(RLIMIT_AS, &rl) != 0) + return 0; + if(rl.rlim_cur >= 0x7fffffff) + return 0; + + // Estimate our VM footprint excluding the heap. + // Not an exact science: use size of binary plus + // some room for thread stacks. + used = runtime·end - runtime·text + (64<<20); + if(used >= rl.rlim_cur) + return 0; + + // If there's not at least 16 MB left, we're probably + // not going to be able to do much. Treat as no limit. + rl.rlim_cur -= used; + if(rl.rlim_cur < (16<<20)) + return 0; + + return rl.rlim_cur - used; + */ + return 0 +} + +func sigtramp() + +type sigactiont struct { + sa_sigaction uintptr + sa_flags int32 + sa_mask sigset +} + +//go:nosplit +//go:nowritebarrierrec +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) +} + +//go:nosplit +//go:nowritebarrierrec +func setsigstack(i int32) { + throw("setsigstack") +} + +//go:nosplit +//go:nowritebarrierrec +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 +} + +//go:nosplit +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) +} + +//go:nosplit +//go:nowritebarrierrec +func updatesigmask(m sigmask) { + var mask sigset + copy(mask.__bits[:], m[:]) + sigprocmask(_SIG_SETMASK, &mask, nil) +} + +func unblocksig(sig int32) { + var mask sigset + mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31) + sigprocmask(_SIG_UNBLOCK, &mask, nil) +} diff --git a/src/runtime/os2_linux_generic.go b/src/runtime/os_linux_generic.go similarity index 63% rename from src/runtime/os2_linux_generic.go rename to src/runtime/os_linux_generic.go index f1a2dd5130..a16d140776 100644 --- a/src/runtime/os2_linux_generic.go +++ b/src/runtime/os_linux_generic.go @@ -28,3 +28,21 @@ type rlimit struct { rlim_cur uintptr rlim_max uintptr } + +var sigset_all = sigset{^uint32(0), ^uint32(0)} + +func sigaddset(mask *sigset, i int) { + (*mask)[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31) +} + +func sigdelset(mask *sigset, i int) { + (*mask)[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31) +} + +func sigfillset(mask *uint64) { + *mask = ^uint64(0) +} + +func sigcopyset(mask *sigset, m sigmask) { + copy((*mask)[:], m[:]) +} diff --git a/src/runtime/os_linux_mips64x.go b/src/runtime/os_linux_mips64x.go index 4d2e9e8a20..92b5c82af7 100644 --- a/src/runtime/os_linux_mips64x.go +++ b/src/runtime/os_linux_mips64x.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build mips64 mips64le // +build linux +// +build mips64 mips64le package runtime @@ -16,3 +16,38 @@ func cputicks() int64 { // randomNumber provides better seeding of fastrand1. return nanotime() + int64(randomNumber) } + +const ( + _SS_DISABLE = 2 + _NSIG = 65 + _SI_USER = 0 + _SIG_BLOCK = 1 + _SIG_UNBLOCK = 2 + _SIG_SETMASK = 3 + _RLIMIT_AS = 6 +) + +type sigset [2]uint64 + +type rlimit struct { + rlim_cur uintptr + rlim_max uintptr +} + +var sigset_all = sigset{^uint64(0), ^uint64(0)} + +func sigaddset(mask *sigset, i int) { + (*mask)[(i-1)/64] |= 1 << ((uint32(i) - 1) & 63) +} + +func sigdelset(mask *sigset, i int) { + (*mask)[(i-1)/64] &^= 1 << ((uint32(i) - 1) & 63) +} + +func sigfillset(mask *[2]uint64) { + (*mask)[0], (*mask)[1] = ^uint64(0), ^uint64(0) +} + +func sigcopyset(mask *sigset, m sigmask) { + (*mask)[0] = uint64(m[0]) | uint64(m[1])<<32 +} diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go index 0fba16d4f4..41f34f7132 100644 --- a/src/runtime/os_netbsd.go +++ b/src/runtime/os_netbsd.go @@ -4,7 +4,23 @@ package runtime -import "unsafe" +import ( + "runtime/internal/atomic" + "unsafe" +) + +const ( + _SS_DISABLE = 4 + _SIG_BLOCK = 1 + _SIG_UNBLOCK = 2 + _SIG_SETMASK = 3 + _NSIG = 33 + _SI_USER = 0 + + // From NetBSD's + _UC_SIGMASK = 0x01 + _UC_CPU = 0x04 +) type mOS struct { waitsemacount uint32 @@ -45,3 +61,268 @@ func lwp_unpark(lwp int32, hint unsafe.Pointer) int32 func lwp_self() int32 func osyield() + +const ( + _ESRCH = 3 + _ETIMEDOUT = 60 + + // From NetBSD's + _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 +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(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(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 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) { + atomic.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, " ostk=", &mp, "\n") + } + + 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(netbsdMstart)) + + 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") + } +} + +// netbsdMStart is the function call that starts executing a newly +// created thread. On NetBSD, a new thread inherits the signal stack +// of the creating thread. That confuses minit, so we remove that +// signal stack here before calling the regular mstart. It's a bit +// baroque to remove a signal stack here only to add one in minit, but +// it's a simple change that keeps NetBSD working like other OS's. +// At this point all signals are blocked, so there is no race. +//go:nosplit +func netbsdMstart() { + signalstack(nil) + mstart() +} + +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 +} + +//go:nosplit +func msigsave(mp *m) { + sigprocmask(_SIG_SETMASK, nil, &mp.sigmask) +} + +//go:nosplit +func msigrestore(sigmask sigset) { + sigprocmask(_SIG_SETMASK, &sigmask, nil) +} + +//go:nosplit +func sigblock() { + sigprocmask(_SIG_SETMASK, &sigset_all, nil) +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, cannot allocate memory. +func minit() { + _g_ := getg() + _g_.m.procid = uint64(lwp_self()) + + // Initialize signal handling. + + // On NetBSD a thread created by pthread_create inherits the + // signal stack of the creating thread. We always create a + // new signal stack here, to avoid having two Go threads using + // the same signal stack. This breaks the case of a thread + // created in C that calls sigaltstack and then calls a Go + // function, because we will lose track of the C code's + // sigaltstack, but it's the best we can do. + signalstack(&_g_.m.gsignal.stack) + _g_.m.newSigstack = true + + // restore signal mask from m.sigmask and unblock essential signals + nmask := _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. +//go:nosplit +func unminit() { + if getg().m.newSigstack { + signalstack(nil) + } +} + +func memlimit() uintptr { + return 0 +} + +func sigtramp() + +type sigactiont struct { + sa_sigaction uintptr + sa_mask sigset + sa_flags int32 +} + +//go:nosplit +//go:nowritebarrierrec +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) +} + +//go:nosplit +//go:nowritebarrierrec +func setsigstack(i int32) { + throw("setsigstack") +} + +//go:nosplit +//go:nowritebarrierrec +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 +} + +//go:nosplit +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) +} + +//go:nosplit +//go:nowritebarrierrec +func updatesigmask(m sigmask) { + var mask sigset + copy(mask.__bits[:], m[:]) + sigprocmask(_SIG_SETMASK, &mask, nil) +} + +func unblocksig(sig int32) { + var mask sigset + mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31) + sigprocmask(_SIG_UNBLOCK, &mask, nil) +} diff --git a/src/runtime/os1_netbsd_386.go b/src/runtime/os_netbsd_386.go similarity index 100% rename from src/runtime/os1_netbsd_386.go rename to src/runtime/os_netbsd_386.go diff --git a/src/runtime/os1_netbsd_amd64.go b/src/runtime/os_netbsd_amd64.go similarity index 100% rename from src/runtime/os1_netbsd_amd64.go rename to src/runtime/os_netbsd_amd64.go