aboutsummaryrefslogtreecommitdiff
path: root/libgo/go
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2016-11-10 22:53:23 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2016-11-10 22:53:23 +0000
commit980f9a0a4b7a193707ffa5e8ef698a223561b804 (patch)
tree5a870a796677b74bf81d7659534413ed868dad5e /libgo/go
parent071af74db674f3dc462ab8a25e091b74830fda2d (diff)
downloadgcc-980f9a0a4b7a193707ffa5e8ef698a223561b804.zip
gcc-980f9a0a4b7a193707ffa5e8ef698a223561b804.tar.gz
gcc-980f9a0a4b7a193707ffa5e8ef698a223561b804.tar.bz2
runtime: copy signal code from Go 1.7 runtime
Add a little shell script to auto-generate runtime.sigtable from the known signal names. Force the main package to always import the runtime package. Otherwise some runtime package global variables may never be initialized. Set the syscallsp and syscallpc fields of g when entering a syscall, so that the runtime package knows when a g is executing a syscall. Fix runtime.funcPC to avoid dead store elimination of the interface value when the function is inlined. Reviewed-on: https://go-review.googlesource.com/33025 From-SVN: r242060
Diffstat (limited to 'libgo/go')
-rw-r--r--libgo/go/runtime/panic.go90
-rw-r--r--libgo/go/runtime/runtime2.go4
-rw-r--r--libgo/go/runtime/signal1_unix.go332
-rw-r--r--libgo/go/runtime/signal2_unix.go11
-rw-r--r--libgo/go/runtime/signal_gccgo.go145
-rw-r--r--libgo/go/runtime/signal_sighandler.go136
-rw-r--r--libgo/go/runtime/signal_sigtramp.go31
-rw-r--r--libgo/go/runtime/signal_unix.go21
-rw-r--r--libgo/go/runtime/sigpanic_unix.go48
-rw-r--r--libgo/go/runtime/sigqueue.go178
-rw-r--r--libgo/go/runtime/stubs.go32
11 files changed, 991 insertions, 37 deletions
diff --git a/libgo/go/runtime/panic.go b/libgo/go/runtime/panic.go
new file mode 100644
index 0000000..c39107b
--- /dev/null
+++ b/libgo/go/runtime/panic.go
@@ -0,0 +1,90 @@
+// Copyright 2014 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
+
+// Calling panic with one of the errors below will call errorString.Error
+// which will call mallocgc to concatenate strings. That will fail if
+// malloc is locked, causing a confusing error message. Throw a better
+// error message instead.
+func panicCheckMalloc(err error) {
+ gp := getg()
+ if gp != nil && gp.m != nil && gp.m.mallocing != 0 {
+ throw(string(err.(errorString)))
+ }
+}
+
+var indexError = error(errorString("index out of range"))
+
+func panicindex() {
+ panicCheckMalloc(indexError)
+ panic(indexError)
+}
+
+var sliceError = error(errorString("slice bounds out of range"))
+
+func panicslice() {
+ panicCheckMalloc(sliceError)
+ panic(sliceError)
+}
+
+var divideError = error(errorString("integer divide by zero"))
+
+func panicdivide() {
+ panicCheckMalloc(divideError)
+ panic(divideError)
+}
+
+var overflowError = error(errorString("integer overflow"))
+
+func panicoverflow() {
+ panicCheckMalloc(overflowError)
+ panic(overflowError)
+}
+
+var floatError = error(errorString("floating point error"))
+
+func panicfloat() {
+ panicCheckMalloc(floatError)
+ panic(floatError)
+}
+
+var memoryError = error(errorString("invalid memory address or nil pointer dereference"))
+
+func panicmem() {
+ panicCheckMalloc(memoryError)
+ panic(memoryError)
+}
+
+func throwreturn() {
+ throw("no return at end of a typed function - compiler is broken")
+}
+
+func throwinit() {
+ throw("recursive call during initialization - linker skew")
+}
+
+//go:nosplit
+func canpanic(gp *g) bool {
+ // Note that g is m->gsignal, different from gp.
+ // Note also that g->m can change at preemption, so m can go stale
+ // if this function ever makes a function call.
+ _g_ := getg()
+ _m_ := _g_.m
+
+ // Is it okay for gp to panic instead of crashing the program?
+ // Yes, as long as it is running Go code, not runtime code,
+ // and not stuck in a system call.
+ if gp == nil || gp != _m_.curg {
+ return false
+ }
+ if _m_.locks-_m_.softfloat != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 {
+ return false
+ }
+ status := readgstatus(gp)
+ if status&^_Gscan != _Grunning || gp.syscallsp != 0 {
+ return false
+ }
+ return true
+}
diff --git a/libgo/go/runtime/runtime2.go b/libgo/go/runtime/runtime2.go
index 37ade7d..f3bbb58 100644
--- a/libgo/go/runtime/runtime2.go
+++ b/libgo/go/runtime/runtime2.go
@@ -326,8 +326,8 @@ type g struct {
m *m // current m; offset known to arm liblink
// Not for gccgo: stackAlloc uintptr // stack allocation is [stack.lo,stack.lo+stackAlloc)
// Not for gccgo: sched gobuf
- // Not for gccgo: syscallsp uintptr // if status==Gsyscall, syscallsp = sched.sp to use during gc
- // Not for gccgo: syscallpc uintptr // if status==Gsyscall, syscallpc = sched.pc to use during gc
+ syscallsp uintptr // if status==Gsyscall, syscallsp = sched.sp to use during gc
+ syscallpc uintptr // if status==Gsyscall, syscallpc = sched.pc to use during gc
// Not for gccgo: stkbar []stkbar // stack barriers, from low to high (see top of mstkbar.go)
// Not for gccgo: stkbarPos uintptr // index of lowest stack barrier not hit
// Not for gccgo: stktopsp uintptr // expected sp at top of stack, to check in traceback
diff --git a/libgo/go/runtime/signal1_unix.go b/libgo/go/runtime/signal1_unix.go
new file mode 100644
index 0000000..f932765
--- /dev/null
+++ b/libgo/go/runtime/signal1_unix.go
@@ -0,0 +1,332 @@
+// Copyright 2012 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 darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package runtime
+
+import (
+ _ "unsafe" // For go:linkname.
+)
+
+// Temporary for gccgo's C code to call:
+//go:linkname initsig runtime.initsig
+//go:linkname crash runtime.crash
+//go:linkname resetcpuprofiler runtime.resetcpuprofiler
+
+//extern setitimer
+func setitimer(which int32, new *_itimerval, old *_itimerval) int32
+
+type sigTabT struct {
+ flags int32
+ name string
+}
+
+const (
+ _SIG_DFL uintptr = 0
+ _SIG_IGN uintptr = 1
+)
+
+// Stores the signal handlers registered before Go installed its own.
+// These signal handlers will be invoked in cases where Go doesn't want to
+// handle a particular signal (e.g., signal occurred on a non-Go thread).
+// See sigfwdgo() for more information on when the signals are forwarded.
+//
+// Signal forwarding is currently available only on Darwin and Linux.
+var fwdSig [_NSIG]uintptr
+
+// sigmask represents a general signal mask compatible with the GOOS
+// specific sigset types: the signal numbered x is represented by bit x-1
+// to match the representation expected by sigprocmask.
+type sigmask [(_NSIG + 31) / 32]uint32
+
+// channels for synchronizing signal mask updates with the signal mask
+// thread
+var (
+ disableSigChan chan uint32
+ enableSigChan chan uint32
+ maskUpdatedChan chan struct{}
+)
+
+func init() {
+ // _NSIG is the number of signals on this operating system.
+ // sigtable should describe what to do for all the possible signals.
+ if len(sigtable) != _NSIG {
+ print("runtime: len(sigtable)=", len(sigtable), " _NSIG=", _NSIG, "\n")
+ throw("bad sigtable len")
+ }
+}
+
+var signalsOK bool
+
+// Initialize signals.
+// Called by libpreinit so runtime may not be initialized.
+//go:nosplit
+//go:nowritebarrierrec
+func initsig(preinit bool) {
+ if !preinit {
+ // It's now OK for signal handlers to run.
+ signalsOK = true
+ }
+
+ // For c-archive/c-shared this is called by libpreinit with
+ // preinit == true.
+ if (isarchive || islibrary) && !preinit {
+ return
+ }
+
+ for i := int32(0); i < _NSIG; i++ {
+ t := &sigtable[i]
+ if t.flags == 0 || t.flags&_SigDefault != 0 {
+ continue
+ }
+ fwdSig[i] = getsig(i)
+
+ if !sigInstallGoHandler(i) {
+ // Even if we are not installing a signal handler,
+ // set SA_ONSTACK if necessary.
+ if fwdSig[i] != _SIG_DFL && fwdSig[i] != _SIG_IGN {
+ setsigstack(i)
+ }
+ continue
+ }
+
+ t.flags |= _SigHandling
+ setsig(i, funcPC(sigtramp), true)
+ }
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func sigInstallGoHandler(sig int32) bool {
+ // For some signals, we respect an inherited SIG_IGN handler
+ // rather than insist on installing our own default handler.
+ // Even these signals can be fetched using the os/signal package.
+ switch sig {
+ case _SIGHUP, _SIGINT:
+ if fwdSig[sig] == _SIG_IGN {
+ return false
+ }
+ }
+
+ t := &sigtable[sig]
+ if t.flags&_SigSetStack != 0 {
+ return false
+ }
+
+ // When built using c-archive or c-shared, only install signal
+ // handlers for synchronous signals.
+ if (isarchive || islibrary) && t.flags&_SigPanic == 0 {
+ return false
+ }
+
+ return true
+}
+
+func sigenable(sig uint32) {
+ if sig >= uint32(len(sigtable)) {
+ return
+ }
+
+ t := &sigtable[sig]
+ if t.flags&_SigNotify != 0 {
+ ensureSigM()
+ enableSigChan <- sig
+ <-maskUpdatedChan
+ if t.flags&_SigHandling == 0 {
+ t.flags |= _SigHandling
+ fwdSig[sig] = getsig(int32(sig))
+ setsig(int32(sig), funcPC(sigtramp), true)
+ }
+ }
+}
+
+func sigdisable(sig uint32) {
+ if sig >= uint32(len(sigtable)) {
+ return
+ }
+
+ t := &sigtable[sig]
+ if t.flags&_SigNotify != 0 {
+ ensureSigM()
+ disableSigChan <- sig
+ <-maskUpdatedChan
+
+ // If initsig does not install a signal handler for a
+ // signal, then to go back to the state before Notify
+ // we should remove the one we installed.
+ if !sigInstallGoHandler(int32(sig)) {
+ t.flags &^= _SigHandling
+ setsig(int32(sig), fwdSig[sig], true)
+ }
+ }
+}
+
+func sigignore(sig uint32) {
+ if sig >= uint32(len(sigtable)) {
+ return
+ }
+
+ t := &sigtable[sig]
+ if t.flags&_SigNotify != 0 {
+ t.flags &^= _SigHandling
+ setsig(int32(sig), _SIG_IGN, true)
+ }
+}
+
+func resetcpuprofiler(hz int32) {
+ var it _itimerval
+ if hz == 0 {
+ setitimer(_ITIMER_PROF, &it, nil)
+ } else {
+ it.it_interval.tv_sec = 0
+ it.it_interval.set_usec(1000000 / hz)
+ it.it_value = it.it_interval
+ setitimer(_ITIMER_PROF, &it, nil)
+ }
+ _g_ := getg()
+ _g_.m.profilehz = hz
+}
+
+func sigpipe() {
+ if sigsend(_SIGPIPE) {
+ return
+ }
+ dieFromSignal(_SIGPIPE)
+}
+
+// dieFromSignal kills the program with a signal.
+// This provides the expected exit status for the shell.
+// This is only called with fatal signals expected to kill the process.
+//go:nosplit
+//go:nowritebarrierrec
+func dieFromSignal(sig int32) {
+ setsig(sig, _SIG_DFL, false)
+ updatesigmask(sigmask{})
+ raise(sig)
+
+ // That should have killed us. On some systems, though, raise
+ // sends the signal to the whole process rather than to just
+ // the current thread, which means that the signal may not yet
+ // have been delivered. Give other threads a chance to run and
+ // pick up the signal.
+ osyield()
+ osyield()
+ osyield()
+
+ // If we are still somehow running, just exit with the wrong status.
+ exit(2)
+}
+
+// raisebadsignal is called when a signal is received on a non-Go
+// thread, and the Go program does not want to handle it (that is, the
+// program has not called os/signal.Notify for the signal).
+func raisebadsignal(sig int32, c *sigctxt) {
+ if sig == _SIGPROF {
+ // Ignore profiling signals that arrive on non-Go threads.
+ return
+ }
+
+ var handler uintptr
+ if sig >= _NSIG {
+ handler = _SIG_DFL
+ } else {
+ handler = fwdSig[sig]
+ }
+
+ // Reset the signal handler and raise the signal.
+ // We are currently running inside a signal handler, so the
+ // signal is blocked. We need to unblock it before raising the
+ // signal, or the signal we raise will be ignored until we return
+ // from the signal handler. We know that the signal was unblocked
+ // before entering the handler, or else we would not have received
+ // it. That means that we don't have to worry about blocking it
+ // again.
+ unblocksig(sig)
+ setsig(sig, handler, false)
+
+ // If we're linked into a non-Go program we want to try to
+ // avoid modifying the original context in which the signal
+ // was raised. If the handler is the default, we know it
+ // is non-recoverable, so we don't have to worry about
+ // re-installing sighandler. At this point we can just
+ // return and the signal will be re-raised and caught by
+ // the default handler with the correct context.
+ if (isarchive || islibrary) && handler == _SIG_DFL && c.sigcode() != _SI_USER {
+ return
+ }
+
+ raise(sig)
+
+ // If the signal didn't cause the program to exit, restore the
+ // Go signal handler and carry on.
+ //
+ // We may receive another instance of the signal before we
+ // restore the Go handler, but that is not so bad: we know
+ // that the Go program has been ignoring the signal.
+ setsig(sig, funcPC(sigtramp), true)
+}
+
+func crash() {
+ dieFromSignal(_SIGABRT)
+}
+
+// ensureSigM starts one global, sleeping thread to make sure at least one thread
+// is available to catch signals enabled for os/signal.
+func ensureSigM() {
+ if maskUpdatedChan != nil {
+ return
+ }
+ maskUpdatedChan = make(chan struct{})
+ disableSigChan = make(chan uint32)
+ enableSigChan = make(chan uint32)
+ go func() {
+ // Signal masks are per-thread, so make sure this goroutine stays on one
+ // thread.
+ LockOSThread()
+ defer UnlockOSThread()
+ // The sigBlocked mask contains the signals not active for os/signal,
+ // initially all signals except the essential. When signal.Notify()/Stop is called,
+ // sigenable/sigdisable in turn notify this thread to update its signal
+ // mask accordingly.
+ var sigBlocked sigmask
+ for i := range sigBlocked {
+ sigBlocked[i] = ^uint32(0)
+ }
+ for i := range sigtable {
+ if sigtable[i].flags&_SigUnblock != 0 {
+ sigBlocked[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+ }
+ }
+ updatesigmask(sigBlocked)
+ for {
+ select {
+ case sig := <-enableSigChan:
+ if b := sig - 1; sig > 0 {
+ sigBlocked[b/32] &^= (1 << (b & 31))
+ }
+ case sig := <-disableSigChan:
+ if b := sig - 1; sig > 0 {
+ sigBlocked[b/32] |= (1 << (b & 31))
+ }
+ }
+ updatesigmask(sigBlocked)
+ maskUpdatedChan <- struct{}{}
+ }
+ }()
+}
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+//go:nosplit
+//go:norace
+//go:nowritebarrierrec
+func badsignal(sig uintptr, c *sigctxt) {
+ needm()
+ if !sigsend(uint32(sig)) {
+ // A foreign thread received the signal sig, and the
+ // Go code does not want to handle it.
+ raisebadsignal(int32(sig), c)
+ }
+ dropm()
+}
diff --git a/libgo/go/runtime/signal2_unix.go b/libgo/go/runtime/signal2_unix.go
index b7479a7..2a39eac 100644
--- a/libgo/go/runtime/signal2_unix.go
+++ b/libgo/go/runtime/signal2_unix.go
@@ -2,24 +2,19 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build ignore
-
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package runtime
import "unsafe"
-//go:noescape
-func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
-
// Determines if the signal should be handled by Go and if not, forwards the
// signal to the handler that was installed before Go's. Returns whether the
// signal was forwarded.
// This is called by the signal handler, and the world may be stopped.
//go:nosplit
//go:nowritebarrierrec
-func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
+func sigfwdgo(sig uint32, info *_siginfo_t, ctx unsafe.Pointer) bool {
if sig >= uint32(len(sigtable)) {
return false
}
@@ -52,7 +47,7 @@ func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
}
// Only forward synchronous signals.
- c := &sigctxt{info, ctx}
+ c := sigctxt{info, ctx}
if c.sigcode() == _SI_USER || flags&_SigPanic == 0 {
return false
}
diff --git a/libgo/go/runtime/signal_gccgo.go b/libgo/go/runtime/signal_gccgo.go
new file mode 100644
index 0000000..0ecafcc
--- /dev/null
+++ b/libgo/go/runtime/signal_gccgo.go
@@ -0,0 +1,145 @@
+// Copyright 2016 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 darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package runtime
+
+import (
+ "unsafe"
+)
+
+// Functions for gccgo to support signal handling. In the gc runtime
+// these are written in OS-specific files and in assembler.
+
+//extern sigaction
+func sigaction(signum int32, act *_sigaction, oact *_sigaction) int32
+
+//extern sigprocmask
+func sigprocmask(how int32, set *_sigset_t, oldset *_sigset_t) int32
+
+// The argument should be simply *_sigset_t, but that fails on GNU/Linux
+// which sometimes uses _sigset_t and sometimes uses ___sigset_t.
+//extern sigfillset
+func sigfillset(set unsafe.Pointer) int32
+
+//extern sigemptyset
+func sigemptyset(set *_sigset_t) int32
+
+//extern sigaddset
+func sigaddset(set *_sigset_t, signum int32) int32
+
+//extern sigaltstack
+func sigaltstack(ss *_stack_t, oss *_stack_t) int32
+
+//extern raise
+func raise(sig int32) int32
+
+//extern getpid
+func getpid() _pid_t
+
+//extern kill
+func kill(pid _pid_t, sig int32) int32
+
+type sigctxt struct {
+ info *_siginfo_t
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
+
+//go:nosplit
+func sigblock() {
+ var set _sigset_t
+ sigfillset(unsafe.Pointer(&set))
+ sigprocmask(_SIG_SETMASK, &set, nil)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsig(i int32, fn uintptr, restart bool) {
+ var sa _sigaction
+ sa.sa_flags = _SA_SIGINFO
+
+ // For gccgo we do not set SA_ONSTACK for a signal that can
+ // cause a panic. Instead, we trust that the split stack has
+ // enough room to start the signal handler. This is because
+ // otherwise we have no good way to switch back to the
+ // original stack before panicing.
+ if sigtable[i].flags&_SigPanic == 0 {
+ sa.sa_flags |= _SA_ONSTACK
+ }
+
+ if restart {
+ sa.sa_flags |= _SA_RESTART
+ }
+ sigfillset(unsafe.Pointer(&sa.sa_mask))
+ setSigactionHandler(&sa, fn)
+ sigaction(i, &sa, nil)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsigstack(i int32) {
+ var sa _sigaction
+ sigaction(i, nil, &sa)
+ handler := getSigactionHandler(&sa)
+ if handler == 0 || handler == _SIG_DFL || handler == _SIG_IGN || sa.sa_flags&_SA_ONSTACK != 0 {
+ return
+ }
+ if sigtable[i].flags&_SigPanic != 0 {
+ return
+ }
+ sa.sa_flags |= _SA_ONSTACK
+ sigaction(i, &sa, nil)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func getsig(i int32) uintptr {
+ var sa _sigaction
+ if sigaction(i, nil, &sa) < 0 {
+ // On GNU/Linux glibc rejects attempts to call
+ // sigaction with signal 32 (SIGCANCEL) or 33 (SIGSETXID).
+ if GOOS == "linux" && (i == 32 || i == 33) {
+ return _SIG_DFL
+ }
+ throw("sigaction read failure")
+ }
+ return getSigactionHandler(&sa)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func updatesigmask(m sigmask) {
+ var mask _sigset_t
+ sigemptyset(&mask)
+ for i := int32(0); i < _NSIG; i++ {
+ if m[(i-1)/32]&(1<<((uint(i)-1)&31)) != 0 {
+ sigaddset(&mask, i)
+ }
+ }
+ sigprocmask(_SIG_SETMASK, &mask, nil)
+}
+
+func unblocksig(sig int32) {
+ var mask _sigset_t
+ sigemptyset(&mask)
+ sigaddset(&mask, sig)
+ sigprocmask(_SIG_UNBLOCK, &mask, nil)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func raiseproc(sig int32) {
+ kill(getpid(), sig)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func sigfwd(fn uintptr, sig uint32, info *_siginfo_t, ctx unsafe.Pointer) {
+ f1 := &[1]uintptr{fn}
+ f2 := *(*func(uint32, *_siginfo_t, unsafe.Pointer))(unsafe.Pointer(&f1))
+ f2(sig, info, ctx)
+}
diff --git a/libgo/go/runtime/signal_sighandler.go b/libgo/go/runtime/signal_sighandler.go
new file mode 100644
index 0000000..3cbec66
--- /dev/null
+++ b/libgo/go/runtime/signal_sighandler.go
@@ -0,0 +1,136 @@
+// Copyright 2013 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 darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package runtime
+
+import (
+ "unsafe"
+)
+
+// crashing is the number of m's we have waited for when implementing
+// GOTRACEBACK=crash when a signal is received.
+var crashing int32
+
+// sighandler is invoked when a signal occurs. The global g will be
+// set to a gsignal goroutine and we will be running on the alternate
+// signal stack. The parameter g will be the value of the global g
+// when the signal occurred. The sig, info, and ctxt parameters are
+// from the system signal handler: they are the parameters passed when
+// the SA is passed to the sigaction system call.
+//
+// The garbage collector may have stopped the world, so write barriers
+// are not allowed.
+//
+//go:nowritebarrierrec
+func sighandler(sig uint32, info *_siginfo_t, ctxt unsafe.Pointer, gp *g) {
+ _g_ := getg()
+ c := sigctxt{info, ctxt}
+
+ if sig == _SIGPROF {
+ sigprof()
+ return
+ }
+
+ sigfault, sigpc := getSiginfo(info, ctxt)
+
+ flags := int32(_SigThrow)
+ if sig < uint32(len(sigtable)) {
+ flags = sigtable[sig].flags
+ }
+ if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
+ // Emulate gc by passing arguments out of band,
+ // although we don't really have to.
+ gp.sig = sig
+ gp.sigcode0 = uintptr(c.sigcode())
+ gp.sigcode1 = sigfault
+ gp.sigpc = sigpc
+
+ setg(gp)
+
+ // All signals were blocked due to the sigaction mask;
+ // unblock them.
+ var set _sigset_t
+ sigfillset(unsafe.Pointer(&set))
+ sigprocmask(_SIG_UNBLOCK, &set, nil)
+
+ sigpanic()
+ throw("sigpanic returned")
+ }
+
+ if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
+ if sigsend(sig) {
+ return
+ }
+ }
+
+ if c.sigcode() == _SI_USER && signal_ignored(sig) {
+ return
+ }
+
+ if flags&_SigKill != 0 {
+ dieFromSignal(int32(sig))
+ }
+
+ if flags&_SigThrow == 0 {
+ return
+ }
+
+ _g_.m.throwing = 1
+ _g_.m.caughtsig.set(gp)
+
+ if crashing == 0 {
+ startpanic()
+ }
+
+ if sig < uint32(len(sigtable)) {
+ print(sigtable[sig].name, "\n")
+ } else {
+ print("Signal ", sig, "\n")
+ }
+
+ if sigpc != 0 {
+ print("PC=", hex(sigpc), " ")
+ }
+ print("m=", _g_.m.id, " sigcode=", c.sigcode(), "\n")
+ if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
+ print("signal arrived during cgo execution\n")
+ gp = _g_.m.lockedg
+ }
+ print("\n")
+
+ level, _, docrash := gotraceback()
+ if level > 0 {
+ goroutineheader(gp)
+ traceback(0)
+ if crashing == 0 {
+ tracebackothers(gp)
+ print("\n")
+ }
+ dumpregs(info, ctxt)
+ }
+
+ if docrash {
+ crashing++
+ if crashing < mcount() {
+ // There are other m's that need to dump their stacks.
+ // Relay SIGQUIT to the next m by sending it to the current process.
+ // All m's that have already received SIGQUIT have signal masks blocking
+ // receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
+ // When the last m receives the SIGQUIT, it will fall through to the call to
+ // crash below. Just in case the relaying gets botched, each m involved in
+ // the relay sleeps for 5 seconds and then does the crash/exit itself.
+ // In expected operation, the last m has received the SIGQUIT and run
+ // crash/exit and the process is gone, all long before any of the
+ // 5-second sleeps have finished.
+ print("\n-----\n\n")
+ raiseproc(_SIGQUIT)
+ usleep(5 * 1000 * 1000)
+ }
+ crash()
+ }
+
+ exit(2)
+}
diff --git a/libgo/go/runtime/signal_sigtramp.go b/libgo/go/runtime/signal_sigtramp.go
index f4a6ebd..67b9e67 100644
--- a/libgo/go/runtime/signal_sigtramp.go
+++ b/libgo/go/runtime/signal_sigtramp.go
@@ -2,19 +2,20 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build ignore
-
-// +build dragonfly linux netbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package runtime
import "unsafe"
+// For gccgo, use go:linkname so the C signal handler can call this one.
+//go:linkname sigtrampgo runtime.sigtrampgo
+
// Continuation of the (assembly) sigtramp() logic.
// This may be called with the world stopped.
//go:nosplit
//go:nowritebarrierrec
-func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
+func sigtrampgo(sig uint32, info *_siginfo_t, ctx unsafe.Pointer) {
if sigfwdgo(sig, info, ctx) {
return
}
@@ -32,28 +33,6 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
return
}
- // If some non-Go code called sigaltstack, adjust.
- sp := uintptr(unsafe.Pointer(&sig))
- if sp < g.m.gsignal.stack.lo || sp >= g.m.gsignal.stack.hi {
- var st sigaltstackt
- sigaltstack(nil, &st)
- if st.ss_flags&_SS_DISABLE != 0 {
- setg(nil)
- cgocallback(unsafe.Pointer(funcPC(noSignalStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig), 0)
- }
- stsp := uintptr(unsafe.Pointer(st.ss_sp))
- if sp < stsp || sp >= stsp+st.ss_size {
- setg(nil)
- cgocallback(unsafe.Pointer(funcPC(sigNotOnStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig), 0)
- }
- g.m.gsignal.stack.lo = stsp
- g.m.gsignal.stack.hi = stsp + st.ss_size
- g.m.gsignal.stackguard0 = stsp + _StackGuard
- g.m.gsignal.stackguard1 = stsp + _StackGuard
- g.m.gsignal.stackAlloc = st.ss_size
- g.m.gsignal.stktopsp = getcallersp(unsafe.Pointer(&sig))
- }
-
setg(g.m.gsignal)
sighandler(sig, info, ctx, g)
setg(g)
diff --git a/libgo/go/runtime/signal_unix.go b/libgo/go/runtime/signal_unix.go
new file mode 100644
index 0000000..f59c9b9
--- /dev/null
+++ b/libgo/go/runtime/signal_unix.go
@@ -0,0 +1,21 @@
+// Copyright 2012 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 darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package runtime
+
+import _ "unsafe" // for go:linkname
+
+//go:linkname os_sigpipe os.sigpipe
+func os_sigpipe() {
+ systemstack(sigpipe)
+}
+
+func signame(sig uint32) string {
+ if sig >= uint32(len(sigtable)) {
+ return ""
+ }
+ return sigtable[sig].name
+}
diff --git a/libgo/go/runtime/sigpanic_unix.go b/libgo/go/runtime/sigpanic_unix.go
new file mode 100644
index 0000000..00ad090
--- /dev/null
+++ b/libgo/go/runtime/sigpanic_unix.go
@@ -0,0 +1,48 @@
+// Copyright 2014 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 darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package runtime
+
+import _ "unsafe" // For go:linkname.
+
+// For gccgo, C code has to call sigpanic, so we have to export it.
+//go:linkname sigpanic runtime.sigpanic
+
+func sigpanic() {
+ g := getg()
+ if !canpanic(g) {
+ throw("unexpected signal during runtime execution")
+ }
+
+ switch g.sig {
+ case _SIGBUS:
+ if g.sigcode0 == _BUS_ADRERR && g.sigcode1 < 0x1000 || g.paniconfault {
+ panicmem()
+ }
+ print("unexpected fault address ", hex(g.sigcode1), "\n")
+ throw("fault")
+ case _SIGSEGV:
+ if (g.sigcode0 == 0 || g.sigcode0 == _SEGV_MAPERR || g.sigcode0 == _SEGV_ACCERR) && g.sigcode1 < 0x1000 || g.paniconfault {
+ panicmem()
+ }
+ print("unexpected fault address ", hex(g.sigcode1), "\n")
+ throw("fault")
+ case _SIGFPE:
+ switch g.sigcode0 {
+ case _FPE_INTDIV:
+ panicdivide()
+ case _FPE_INTOVF:
+ panicoverflow()
+ }
+ panicfloat()
+ }
+
+ if g.sig >= uint32(len(sigtable)) {
+ // can't happen: we looked up g.sig in sigtable to decide to call sigpanic
+ throw("unexpected signal value")
+ }
+ panic(errorString(sigtable[g.sig].name))
+}
diff --git a/libgo/go/runtime/sigqueue.go b/libgo/go/runtime/sigqueue.go
new file mode 100644
index 0000000..a6d498f
--- /dev/null
+++ b/libgo/go/runtime/sigqueue.go
@@ -0,0 +1,178 @@
+// 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.
+
+// This file implements runtime support for signal handling.
+//
+// Most synchronization primitives are not available from
+// the signal handler (it cannot block, allocate memory, or use locks)
+// so the handler communicates with a processing goroutine
+// via struct sig, below.
+//
+// sigsend is called by the signal handler to queue a new signal.
+// signal_recv is called by the Go program to receive a newly queued signal.
+// Synchronization between sigsend and signal_recv is based on the sig.state
+// variable. It can be in 3 states: sigIdle, sigReceiving and sigSending.
+// sigReceiving means that signal_recv is blocked on sig.Note and there are no
+// new pending signals.
+// sigSending means that sig.mask *may* contain new pending signals,
+// signal_recv can't be blocked in this state.
+// sigIdle means that there are no new pending signals and signal_recv is not blocked.
+// Transitions between states are done atomically with CAS.
+// When signal_recv is unblocked, it resets sig.Note and rechecks sig.mask.
+// If several sigsends and signal_recv execute concurrently, it can lead to
+// unnecessary rechecks of sig.mask, but it cannot lead to missed signals
+// nor deadlocks.
+
+// +build !plan9
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ _ "unsafe" // for go:linkname
+)
+
+var sig struct {
+ note note
+ mask [(_NSIG + 31) / 32]uint32
+ wanted [(_NSIG + 31) / 32]uint32
+ ignored [(_NSIG + 31) / 32]uint32
+ recv [(_NSIG + 31) / 32]uint32
+ state uint32
+ inuse bool
+}
+
+const (
+ sigIdle = iota
+ sigReceiving
+ sigSending
+)
+
+// Called from sighandler to send a signal back out of the signal handling thread.
+// Reports whether the signal was sent. If not, the caller typically crashes the program.
+func sigsend(s uint32) bool {
+ bit := uint32(1) << uint(s&31)
+ if !sig.inuse || s >= uint32(32*len(sig.wanted)) || sig.wanted[s/32]&bit == 0 {
+ return false
+ }
+
+ // Add signal to outgoing queue.
+ for {
+ mask := sig.mask[s/32]
+ if mask&bit != 0 {
+ return true // signal already in queue
+ }
+ if atomic.Cas(&sig.mask[s/32], mask, mask|bit) {
+ break
+ }
+ }
+
+ // Notify receiver that queue has new bit.
+Send:
+ for {
+ switch atomic.Load(&sig.state) {
+ default:
+ throw("sigsend: inconsistent state")
+ case sigIdle:
+ if atomic.Cas(&sig.state, sigIdle, sigSending) {
+ break Send
+ }
+ case sigSending:
+ // notification already pending
+ break Send
+ case sigReceiving:
+ if atomic.Cas(&sig.state, sigReceiving, sigIdle) {
+ notewakeup(&sig.note)
+ break Send
+ }
+ }
+ }
+
+ return true
+}
+
+// Called to receive the next queued signal.
+// Must only be called from a single goroutine at a time.
+//go:linkname signal_recv os_signal.signal_recv
+func signal_recv() uint32 {
+ for {
+ // Serve any signals from local copy.
+ for i := uint32(0); i < _NSIG; i++ {
+ if sig.recv[i/32]&(1<<(i&31)) != 0 {
+ sig.recv[i/32] &^= 1 << (i & 31)
+ return i
+ }
+ }
+
+ // Wait for updates to be available from signal sender.
+ Receive:
+ for {
+ switch atomic.Load(&sig.state) {
+ default:
+ throw("signal_recv: inconsistent state")
+ case sigIdle:
+ if atomic.Cas(&sig.state, sigIdle, sigReceiving) {
+ notetsleepg(&sig.note, -1)
+ noteclear(&sig.note)
+ break Receive
+ }
+ case sigSending:
+ if atomic.Cas(&sig.state, sigSending, sigIdle) {
+ break Receive
+ }
+ }
+ }
+
+ // Incorporate updates from sender into local copy.
+ for i := range sig.mask {
+ sig.recv[i] = atomic.Xchg(&sig.mask[i], 0)
+ }
+ }
+}
+
+// Must only be called from a single goroutine at a time.
+//go:linkname signal_enable os_signal.signal_enable
+func signal_enable(s uint32) {
+ if !sig.inuse {
+ // The first call to signal_enable is for us
+ // to use for initialization. It does not pass
+ // signal information in m.
+ sig.inuse = true // enable reception of signals; cannot disable
+ noteclear(&sig.note)
+ return
+ }
+
+ if s >= uint32(len(sig.wanted)*32) {
+ return
+ }
+ sig.wanted[s/32] |= 1 << (s & 31)
+ sig.ignored[s/32] &^= 1 << (s & 31)
+ sigenable(s)
+}
+
+// Must only be called from a single goroutine at a time.
+//go:linkname signal_disable os_signal.signal_disable
+func signal_disable(s uint32) {
+ if s >= uint32(len(sig.wanted)*32) {
+ return
+ }
+ sig.wanted[s/32] &^= 1 << (s & 31)
+ sigdisable(s)
+}
+
+// Must only be called from a single goroutine at a time.
+//go:linkname signal_ignore os_signal.signal_ignore
+func signal_ignore(s uint32) {
+ if s >= uint32(len(sig.wanted)*32) {
+ return
+ }
+ sig.wanted[s/32] &^= 1 << (s & 31)
+ sig.ignored[s/32] |= 1 << (s & 31)
+ sigignore(s)
+}
+
+// Checked by signal handlers.
+func signal_ignored(s uint32) bool {
+ return sig.ignored[s/32]&(1<<(s&31)) != 0
+}
diff --git a/libgo/go/runtime/stubs.go b/libgo/go/runtime/stubs.go
index 755933d..d0641ed 100644
--- a/libgo/go/runtime/stubs.go
+++ b/libgo/go/runtime/stubs.go
@@ -241,9 +241,15 @@ func newarray(*_type, int) unsafe.Pointer
// funcPC returns the entry PC of the function f.
// It assumes that f is a func value. Otherwise the behavior is undefined.
// For gccgo here unless and until we port proc.go.
+// Note that this differs from the gc implementation; the gc implementation
+// adds sys.PtrSize to the address of the interface value, but GCC's
+// alias analysis decides that that can not be a reference to the second
+// field of the interface, and in some cases it drops the initialization
+// of the second field as a dead store.
//go:nosplit
func funcPC(f interface{}) uintptr {
- return **(**uintptr)(add(unsafe.Pointer(&f), sys.PtrSize))
+ i := (*iface)(unsafe.Pointer(&f))
+ return **(**uintptr)(i.data)
}
// typedmemmove copies a typed value.
@@ -489,3 +495,27 @@ var zerobase uintptr
func getZerobase() *uintptr {
return &zerobase
}
+
+// Temporary for gccgo until we port proc.go.
+func needm()
+func dropm()
+func sigprof()
+func mcount() int32
+
+// Signal trampoline, written in C.
+func sigtramp()
+
+// The sa_handler field is generally hidden in a union, so use C accessors.
+func getSigactionHandler(*_sigaction) uintptr
+func setSigactionHandler(*_sigaction, uintptr)
+
+// Retrieve fields from the siginfo_t and ucontext_t pointers passed
+// to a signal handler using C, as they are often hidden in a union.
+// Returns and, if available, PC where signal occurred.
+func getSiginfo(*_siginfo_t, unsafe.Pointer) (sigaddr uintptr, sigpc uintptr)
+
+// Implemented in C for gccgo.
+func dumpregs(*_siginfo_t, unsafe.Pointer)
+
+// Temporary for gccgo until we port panic.go.
+func startpanic()