-cac897bd27885c18a16dacfe27d5efd4526455c5
+449e918b0f93d3e3339edcec21a5bc157f548e54
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
this->escapes_ = false;
// When compiling the runtime, the address operator does not
- // cause local variables to escapes. When escape analysis
+ // cause local variables to escape. When escape analysis
// becomes the default, this should be changed to make it an
// error if we have an address operator that escapes.
if (gogo->compiling_runtime() && gogo->package_name() == "runtime")
Gogo::import_package(const std::string& filename,
const std::string& local_name,
bool is_local_name_exported,
+ bool must_exist,
Location location)
{
if (filename.empty())
this->relative_import_path_);
if (stream == NULL)
{
- go_error_at(location, "import file %qs not found", filename.c_str());
+ if (must_exist)
+ go_error_at(location, "import file %qs not found", filename.c_str());
return;
}
void
Gogo::define_global_names()
{
+ if (this->is_main_package())
+ {
+ // Every Go program has to import the runtime package, so that
+ // it is properly initialized.
+ this->import_package("runtime", "_", false, false,
+ Linemap::predeclared_location());
+ }
+
for (Bindings::const_declarations_iterator p =
this->globals_->begin_declarations();
p != this->globals_->end_declarations();
// the declarations are added to the global scope.
void
import_package(const std::string& filename, const std::string& local_name,
- bool is_local_name_exported, Location);
+ bool is_local_name_exported, bool must_exist, Location);
// Whether we are the global binding level.
bool
}
this->gogo_->import_package(token->string_value(), local_name,
- is_local_name_exported, location);
+ is_local_name_exported, true, location);
this->advance_token();
}
runtime/print.c \
runtime/proc.c \
runtime/runtime_c.c \
- runtime/signal_unix.c \
runtime/thread.c \
$(runtime_thread_files) \
runtime/yield.c \
$(rtems_task_variable_add_file) \
malloc.c \
runtime1.c \
- sigqueue.c \
$(runtime_getncpu_file)
goc2c.$(OBJEXT): runtime/goc2c.c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
-sigqueue.c: $(srcdir)/runtime/sigqueue.goc goc2c
- ./goc2c --go-pkgpath os_signal $< > $@.tmp
- mv -f $@.tmp $@
-
%.c: $(srcdir)/runtime/%.goc goc2c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
$(SHELL) $(srcdir)/mvifdiff.sh tmp-runtime_sysinfo.go runtime_sysinfo.go
$(STAMP) $@
+sigtab.go: s-sigtab; @true
+s-sigtab: $(srcdir)/mksigtab.sh gen-sysinfo.go
+ GOOS=$(GOOS) $(SHELL) $(srcdir)/mksigtab.sh > tmp-sigtab.go
+ $(SHELL) $(srcdir)/mvifdiff.sh tmp-sigtab.go sigtab.go
+ $(STAMP) $@
+
runtime.inc: s-runtime-inc; @true
s-runtime-inc: runtime.lo Makefile
rm -f runtime.inc.tmp2
math_lo_GOCFLAGS = $(MATH_FLAG)
# Add the generated file runtime_sysinfo.go to the runtime package.
-extra_go_files_runtime = runtime_sysinfo.go
+extra_go_files_runtime = runtime_sysinfo.go sigtab.go
runtime.lo.dep: $(extra_go_files_runtime)
# Add generated files to the syscall package.
go-unwind.lo go-varargs.lo env_posix.lo heapdump.lo mcache.lo \
mcentral.lo $(am__objects_1) mfixalloc.lo mgc0.lo mheap.lo \
msize.lo panic.lo parfor.lo print.lo proc.lo runtime_c.lo \
- signal_unix.lo thread.lo $(am__objects_2) yield.lo \
- $(am__objects_3) malloc.lo runtime1.lo sigqueue.lo \
- $(am__objects_4)
+ thread.lo $(am__objects_2) yield.lo $(am__objects_3) malloc.lo \
+ runtime1.lo $(am__objects_4)
am_libgo_llgo_la_OBJECTS = $(am__objects_5)
libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS)
libgo_llgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
runtime/print.c \
runtime/proc.c \
runtime/runtime_c.c \
- runtime/signal_unix.c \
runtime/thread.c \
$(runtime_thread_files) \
runtime/yield.c \
$(rtems_task_variable_add_file) \
malloc.c \
runtime1.c \
- sigqueue.c \
$(runtime_getncpu_file)
noinst_DATA = zstdpkglist.go
math_lo_GOCFLAGS = $(MATH_FLAG)
# Add the generated file runtime_sysinfo.go to the runtime package.
-extra_go_files_runtime = runtime_sysinfo.go
+extra_go_files_runtime = runtime_sysinfo.go sigtab.go
# Add generated files to the syscall package.
extra_go_files_syscall = \
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtems-task-variable-add.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runtime1.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runtime_c.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signal_unix.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sigqueue.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread-linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread-sema.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Plo@am__quote@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o runtime_c.lo `test -f 'runtime/runtime_c.c' || echo '$(srcdir)/'`runtime/runtime_c.c
-signal_unix.lo: runtime/signal_unix.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT signal_unix.lo -MD -MP -MF $(DEPDIR)/signal_unix.Tpo -c -o signal_unix.lo `test -f 'runtime/signal_unix.c' || echo '$(srcdir)/'`runtime/signal_unix.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/signal_unix.Tpo $(DEPDIR)/signal_unix.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/signal_unix.c' object='signal_unix.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o signal_unix.lo `test -f 'runtime/signal_unix.c' || echo '$(srcdir)/'`runtime/signal_unix.c
-
thread.lo: runtime/thread.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread.lo -MD -MP -MF $(DEPDIR)/thread.Tpo -c -o thread.lo `test -f 'runtime/thread.c' || echo '$(srcdir)/'`runtime/thread.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/thread.Tpo $(DEPDIR)/thread.Plo
./goc2c $< > $@.tmp
mv -f $@.tmp $@
-sigqueue.c: $(srcdir)/runtime/sigqueue.goc goc2c
- ./goc2c --go-pkgpath os_signal $< > $@.tmp
- mv -f $@.tmp $@
-
%.c: $(srcdir)/runtime/%.goc goc2c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
$(SHELL) $(srcdir)/mvifdiff.sh tmp-runtime_sysinfo.go runtime_sysinfo.go
$(STAMP) $@
+sigtab.go: s-sigtab; @true
+s-sigtab: $(srcdir)/mksigtab.sh gen-sysinfo.go
+ GOOS=$(GOOS) $(SHELL) $(srcdir)/mksigtab.sh > tmp-sigtab.go
+ $(SHELL) $(srcdir)/mvifdiff.sh tmp-sigtab.go sigtab.go
+ $(STAMP) $@
+
runtime.inc: s-runtime-inc; @true
s-runtime-inc: runtime.lo Makefile
rm -f runtime.inc.tmp2
--- /dev/null
+// 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
+}
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
--- /dev/null
+// 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()
+}
// 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
}
}
// Only forward synchronous signals.
- c := &sigctxt{info, ctx}
+ c := sigctxt{info, ctx}
if c.sigcode() == _SI_USER || flags&_SigPanic == 0 {
return false
}
--- /dev/null
+// 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)
+}
--- /dev/null
+// 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)
+}
// 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
}
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)
--- /dev/null
+// 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
+}
--- /dev/null
+// 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))
+}
--- /dev/null
+// 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
+}
// 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.
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()
sed -e 's/type _timeval /type timeval /' \
-e 's/tv_sec *[a-zA-Z0-9_]*/tv_sec timeval_sec_t/' \
-e 's/tv_usec *[a-zA-Z0-9_]*/tv_usec timeval_usec_t/' >> ${OUT}
+echo >> ${OUT}
+echo "func (tv *timeval) set_usec(x int32) {" >> ${OUT}
+echo " tv.tv_usec = timeval_usec_t(x)" >> ${OUT}
+echo "}" >> ${OUT}
+
timespec=`grep '^type _timespec ' gen-sysinfo.go || true`
if test "$timespec" = ""; then
# IRIX 6.5 has __timespec instead.
--- /dev/null
+#!/bin/sh
+
+# 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.
+
+# Create sigtab.go from gen-sysinfo.go.
+
+# This shell scripts creates the sigtab.go file, which maps signals to
+# their dispositions. We generate a file so that we can build a
+# composite literal that only refers to signals that are defined on
+# this system.
+
+# This script simply writes to standard output.
+
+set -e
+
+echo '// Generated by mksigtab.sh. Do not edit.'
+echo
+echo 'package runtime'
+echo
+echo 'var sigtable = [...]sigTabT{'
+
+# Handle signals valid on all Unix systems.
+
+echo ' 0: {0, "SIGNONE: no trap"},'
+echo ' _SIGHUP: {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},'
+echo ' _SIGINT: {_SigNotify + _SigKill, "SIGINT: interrupt"},'
+echo ' _SIGQUIT: {_SigNotify + _SigThrow, "SIGQUIT: quit"},'
+echo ' _SIGILL: {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},'
+echo ' _SIGTRAP: {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},'
+echo ' _SIGABRT: {_SigNotify + _SigThrow, "SIGABRT: abort"},'
+echo ' _SIGBUS: {_SigPanic + _SigUnblock, "SIGBUS: bus error"},'
+echo ' _SIGFPE: {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},'
+echo ' _SIGKILL: {0, "SIGKILL: kill"},'
+echo ' _SIGUSR1: {_SigNotify, "SIGUSR1: user-defined signal 1"},'
+echo ' _SIGSEGV: {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},'
+echo ' _SIGUSR2: {_SigNotify, "SIGUSR2: user-defined signal 2"},'
+echo ' _SIGPIPE: {_SigNotify, "SIGPIPE: write to broken pipe"},'
+echo ' _SIGALRM: {_SigNotify, "SIGALRM: alarm clock"},'
+echo ' _SIGTERM: {_SigNotify + _SigKill, "SIGTERM: termination"},'
+echo ' _SIGCHLD: {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},'
+echo ' _SIGCONT: {_SigNotify + _SigDefault, "SIGCONT: continue"},'
+echo ' _SIGSTOP: {0, "SIGSTOP: stop"},'
+echo ' _SIGTSTP: {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},'
+echo ' _SIGTTIN: {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},'
+echo ' _SIGTTOU: {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},'
+echo ' _SIGURG: {_SigNotify, "SIGURG: urgent condition on socket"},'
+echo ' _SIGXCPU: {_SigNotify, "SIGXCPU: cpu limit exceeded"},'
+echo ' _SIGXFSZ: {_SigNotify, "SIGXFSZ: file size limit exceeded"},'
+echo ' _SIGVTALRM: {_SigNotify, "SIGVTALRM: virtual alarm clock"},'
+echo ' _SIGPROF: {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},'
+echo ' _SIGWINCH: {_SigNotify, "SIGWINCH: window size change"},'
+echo ' _SIGSYS: {_SigThrow, "SIGSYS: bad system call"},'
+
+# Handle signals that are not supported on all systems.
+
+checksig() {
+ if grep 'const $1 = ' gen-sysinfo.go >/dev/null 2>&1; then
+ echo " $1: $2,"
+ fi
+}
+
+checksig _SIGSTKFLT ' {_SigThrow + _SigUnblock, "SIGSTKFLT: stack fault"}'
+checksig _SIGIO ' {_SigNotify, "SIGIO: i/o now possible"}'
+checksig _SIGPWR ' {_SigNotify, "SIGPWR: power failure restart"}'
+checksig _SIGEMT ' {_SigThrow, "SIGEMT: emulate instruction executed"}'
+checksig _SIGINFO ' {_SigNotify, "SIGINFO: status request from keyboard"}'
+checksig _SIGTHR ' {_SigNotify, "SIGTHR: reserved"}'
+checksig _SIGPOLL ' {_SigNotify, "SIGPOLL: pollable event occurred"}'
+checksig _SIGWAITING '{_SigNotify, "SIGWAITING: reserved signal no longer used by"}'
+checksig _SIGLWP ' {_SigNotify, "SIGLWP: reserved signal no longer used by"}'
+checksig _SIGFREEZE ' {_SigNotify, "SIGFREEZE: special signal used by CPR"}'
+checksig _SIGTHAW ' {_SigNotify, "SIGTHAW: special signal used by CPR"}'
+checksig _SIGCANCEL ' {_SigSetStack + _SigUnblock, "SIGCANCEL: reserved signal for thread cancellation"}'
+checksig _SIGXRES ' {_SigNotify, "SIGXRES: resource control exceeded"}'
+checksig _SIGJVM1 ' {_SigNotify, "SIGJVM1: reserved signal for Java Virtual Machine"}'
+checksig _SIGJVM2 ' {_SigNotify, "SIGJVM2: reserved signal for Java Virtual Machine"}'
+
+# Special handling of signals 32 and 33 on GNU/Linux systems,
+# because they are special to glibc.
+if test "${GOOS}" = "linux"; then
+ echo ' 32: {_SigSetStack + _SigUnblock, "signal 32"}, /* SIGCANCEL; see issue 6997 */'
+ echo ' 33: {_SigSetStack + _SigUnblock, "signal 33"}, /* SIGSETXID; see issues 3871, 9400, 12498 */'
+fi
+
+nsig=`grep 'const _*NSIG = [0-9]*$' gen-sysinfo.go | sed -e 's/.* = \([0-9]*\)/\1/'`
+i=1
+while test "$i" -lt "$nsig"; do
+ if ! grep "const _SIG.* = $i" gen-sysinfo.go >/dev/null 2>&1; then
+ if test "${GOOS}" != "linux" || test "$i" -ne 32 -a "$i" -ne 33; then
+ echo " $i: {_SigNotify, \"signal $i\"},"
+ fi
+ fi
+ i=`expr "$i" + 1`
+done
+
+echo '}'
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
+#include <ucontext.h>
#include "runtime.h"
#include "go-assert.h"
#include "go-panic.h"
-#include "signal_unix.h"
#ifndef SA_RESTART
#define SA_RESTART 0
extern void __splitstack_setcontext(void *context[10]);
-#endif
-
-#define N _SigNotify
-#define K _SigKill
-#define T _SigThrow
-#define P _SigPanic
-#define D _SigDefault
+extern void *__splitstack_find_context(void *context[10], size_t *,
+ void **, void **, void **);
-/* Signal actions. This collects the sigtab tables for several
- different targets from the master library. SIGKILL and SIGSTOP are
- not listed, as we don't want to set signal handlers for them. */
-
-SigTab runtime_sigtab[] = {
-#ifdef SIGHUP
- { SIGHUP, N + K, NULL },
-#endif
-#ifdef SIGINT
- { SIGINT, N + K, NULL },
-#endif
-#ifdef SIGQUIT
- { SIGQUIT, N + T, NULL },
-#endif
-#ifdef SIGILL
- { SIGILL, T, NULL },
-#endif
-#ifdef SIGTRAP
- { SIGTRAP, T, NULL },
-#endif
-#ifdef SIGABRT
- { SIGABRT, N + T, NULL },
-#endif
-#ifdef SIGBUS
- { SIGBUS, P, NULL },
-#endif
-#ifdef SIGFPE
- { SIGFPE, P, NULL },
-#endif
-#ifdef SIGUSR1
- { SIGUSR1, N, NULL },
-#endif
-#ifdef SIGSEGV
- { SIGSEGV, P, NULL },
-#endif
-#ifdef SIGUSR2
- { SIGUSR2, N, NULL },
-#endif
-#ifdef SIGPIPE
- { SIGPIPE, N, NULL },
-#endif
-#ifdef SIGALRM
- { SIGALRM, N, NULL },
-#endif
-#ifdef SIGTERM
- { SIGTERM, N + K, NULL },
-#endif
-#ifdef SIGSTKFLT
- { SIGSTKFLT, T, NULL },
-#endif
-#ifdef SIGCHLD
- { SIGCHLD, N, NULL },
-#endif
-#ifdef SIGCONT
- { SIGCONT, N + D, NULL },
-#endif
-#ifdef SIGTSTP
- { SIGTSTP, N + D, NULL },
-#endif
-#ifdef SIGTTIN
- { SIGTTIN, N + D, NULL },
-#endif
-#ifdef SIGTTOU
- { SIGTTOU, N + D, NULL },
-#endif
-#ifdef SIGURG
- { SIGURG, N, NULL },
-#endif
-#ifdef SIGXCPU
- { SIGXCPU, N, NULL },
-#endif
-#ifdef SIGXFSZ
- { SIGXFSZ, N, NULL },
-#endif
-#ifdef SIGVTALRM
- { SIGVTALRM, N, NULL },
-#endif
-#ifdef SIGPROF
- { SIGPROF, N, NULL },
-#endif
-#ifdef SIGWINCH
- { SIGWINCH, N, NULL },
-#endif
-#ifdef SIGIO
- { SIGIO, N, NULL },
-#endif
-#ifdef SIGPWR
- { SIGPWR, N, NULL },
-#endif
-#ifdef SIGSYS
- { SIGSYS, N, NULL },
#endif
-#ifdef SIGEMT
- { SIGEMT, T, NULL },
-#endif
-#ifdef SIGINFO
- { SIGINFO, N, NULL },
-#endif
-#ifdef SIGTHR
- { SIGTHR, N, NULL },
-#endif
- { -1, 0, NULL }
-};
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
-
-/* Handle a signal, for cases where we don't panic. We can split the
- stack here. */
-
-void
-runtime_sighandler (int sig, Siginfo *info,
- void *context __attribute__ ((unused)), G *gp)
-{
- M *m;
- int i;
-
- m = runtime_m ();
-
-#ifdef SIGPROF
- if (sig == SIGPROF)
- {
- /* FIXME: Handle m == NULL by calling something like gc's
- sigprofNonGo. */
- if (m != NULL && gp != m->g0 && gp != m->gsignal)
- runtime_sigprof ();
- return;
- }
-#endif
-
- if (m == NULL)
- {
- runtime_badsignal (sig);
- return;
- }
-
- for (i = 0; runtime_sigtab[i].sig != -1; ++i)
- {
- SigTab *t;
- bool notify, crash;
-
- t = &runtime_sigtab[i];
-
- if (t->sig != sig)
- continue;
-
- notify = false;
-#ifdef SA_SIGINFO
- notify = info != NULL && info->si_code == SI_USER;
-#endif
- if (notify || (t->flags & _SigNotify) != 0)
- {
- if (__go_sigsend (sig))
- return;
- }
- if ((t->flags & _SigKill) != 0)
- runtime_exit (2);
- if ((t->flags & _SigThrow) == 0)
- return;
- runtime_startpanic ();
+// The rest of the signal handler, written in Go.
- {
- const char *name = NULL;
-
-#ifdef HAVE_STRSIGNAL
- name = strsignal (sig);
-#endif
+extern void sigtrampgo(uint32, siginfo_t *, void *)
+ __asm__(GOSYM_PREFIX "runtime.sigtrampgo");
- if (name == NULL)
- runtime_printf ("Signal %d\n", sig);
- else
- runtime_printf ("%s\n", name);
- }
+// The Go signal handler, written in C. This should be running on the
+// alternate signal stack. This is responsible for setting up the
+// split stack context so that stack guard checks will work as
+// expected.
- if (m->lockedg != NULL && m->ncgo > 0 && gp == m->g0)
- {
- runtime_printf("signal arrived during cgo execution\n");
- gp = m->lockedg;
- }
+void sigtramp(int, siginfo_t *, void *)
+ __attribute__ ((no_split_stack));
- runtime_printf ("\n");
+void sigtramp(int, siginfo_t *, void *)
+ __asm__ (GOSYM_PREFIX "runtime.sigtramp");
- if (runtime_gotraceback (&crash))
- {
- G *g;
+#ifndef USING_SPLIT_STACK
- g = runtime_g ();
- runtime_traceback (0);
- runtime_tracebackothers (g);
+// When not using split stacks, there are no stack checks, and there
+// is nothing special for this function to do.
- /* The gc library calls runtime_dumpregs here, and provides
- a function that prints the registers saved in context in
- a readable form. */
- }
-
- if (crash)
- runtime_crash ();
-
- runtime_exit (2);
- }
-
- __builtin_unreachable ();
-}
-
-/* The start of handling a signal which panics. */
-
-static void
-sig_panic_leadin (G *gp)
+void
+sigtramp(int sig, siginfo_t *info, void *context)
{
- int i;
- sigset_t clear;
-
- if (!runtime_canpanic (gp))
- runtime_throw ("unexpected signal during runtime execution");
-
- /* The signal handler blocked signals; unblock them. */
- i = sigfillset (&clear);
- __go_assert (i == 0);
- i = pthread_sigmask (SIG_UNBLOCK, &clear, NULL);
- __go_assert (i == 0);
+ sigtrampgo(sig, info, context);
}
-#ifdef SA_SIGINFO
+#else // USING_SPLIT_STACK
-/* Signal dispatch for signals which panic, on systems which support
- SA_SIGINFO. This is called on the thread stack, and as such it is
- permitted to split the stack. */
-
-static void
-sig_panic_info_handler (int sig, Siginfo *info, void *context)
+void
+sigtramp(int sig, siginfo_t *info, void *context)
{
- G *g;
-
- g = runtime_g ();
- if (g == NULL || info->si_code == SI_USER)
- {
- runtime_sighandler (sig, info, context, g);
- return;
- }
-
- g->sig = sig;
- g->sigcode0 = info->si_code;
- g->sigcode1 = (uintptr_t) info->si_addr;
-
- /* It would be nice to set g->sigpc here as the gc library does, but
- I don't know how to get it portably. */
-
- sig_panic_leadin (g);
-
- switch (sig)
- {
-#ifdef SIGBUS
- case SIGBUS:
- if ((info->si_code == BUS_ADRERR && (uintptr_t) info->si_addr < 0x1000)
- || g->paniconfault)
- runtime_panicstring ("invalid memory address or "
- "nil pointer dereference");
- runtime_printf ("unexpected fault address %p\n", info->si_addr);
- runtime_throw ("fault");
-#endif
-
-#ifdef SIGSEGV
- case SIGSEGV:
- if (((info->si_code == 0
- || info->si_code == SEGV_MAPERR
- || info->si_code == SEGV_ACCERR)
- && (uintptr_t) info->si_addr < 0x1000)
- || g->paniconfault)
- runtime_panicstring ("invalid memory address or "
- "nil pointer dereference");
- runtime_printf ("unexpected fault address %p\n", info->si_addr);
- runtime_throw ("fault");
-#endif
+ G *gp;
+ void *stack_context[10];
+ void *stack;
+ size_t stack_size;
+ void *next_segment;
+ void *next_sp;
+ void *initial_sp;
+ uintptr sp;
+ stack_t st;
+ uintptr stsp;
+
+ gp = runtime_g();
+
+ if (gp == nil) {
+ // Let the Go code handle this case.
+ // It should only call nosplit functions in this case.
+ sigtrampgo(sig, info, context);
+ return;
+ }
-#ifdef SIGFPE
- case SIGFPE:
- switch (info->si_code)
- {
- case FPE_INTDIV:
- runtime_panicstring ("integer divide by zero");
- case FPE_INTOVF:
- runtime_panicstring ("integer overflow");
+ // If this signal is one for which we will panic, we are not
+ // on the alternate signal stack. It's OK to call split-stack
+ // functions here.
+ if (sig == SIGBUS || sig == SIGFPE || sig == SIGSEGV) {
+ sigtrampgo(sig, info, context);
+ return;
}
- runtime_panicstring ("floating point error");
-#endif
- }
- /* All signals with _SigPanic should be in cases above, and this
- handler should only be invoked for those signals. */
- __builtin_unreachable ();
-}
+ // We are running on the alternate signal stack.
+
+ __splitstack_getcontext(&stack_context[0]);
+
+ stack = __splitstack_find_context(&gp->m->gsignal->stackcontext[0],
+ &stack_size, &next_segment,
+ &next_sp, &initial_sp);
+
+ // If some non-Go code called sigaltstack, adjust.
+ sp = (uintptr)(&stack_size);
+ if (sp < (uintptr)(stack) || sp >= (uintptr)(stack) + stack_size) {
+ sigaltstack(nil, &st);
+ if ((st.ss_flags & SS_DISABLE) != 0) {
+ runtime_printf("signal %d received on thread with no signal stack\n", (int32)(sig));
+ runtime_throw("non-Go code disabled sigaltstack");
+ }
+
+ stsp = (uintptr)(st.ss_sp);
+ if (sp < stsp || sp >= stsp + st.ss_size) {
+ runtime_printf("signal %d received but handler not on signal stack\n", (int32)(sig));
+ runtime_throw("non-Go code set up signal handler without SA_ONSTACK flag");
+ }
+
+ // Unfortunately __splitstack_find_context will return NULL
+ // when it is called on a context that has never been used.
+ // There isn't much we can do but assume all is well.
+ if (stack != NULL) {
+ // Here the gc runtime adjusts the gsignal
+ // stack guard to match the values returned by
+ // sigaltstack. Unfortunately we have no way
+ // to do that.
+ runtime_printf("signal %d received on unknown signal stack\n", (int32)(sig));
+ runtime_throw("non-Go code changed signal stack");
+ }
+ }
-#else /* !defined (SA_SIGINFO) */
+ // Set the split stack context so that the stack guards are
+ // checked correctly.
-static void
-sig_panic_handler (int sig)
-{
- G *g;
-
- g = runtime_g ();
- if (g == NULL)
- {
- runtime_sighandler (sig, NULL, NULL, g);
- return;
- }
-
- g->sig = sig;
- g->sigcode0 = 0;
- g->sigcode1 = 0;
-
- sig_panic_leadin (g);
-
- switch (sig)
- {
-#ifdef SIGBUS
- case SIGBUS:
- runtime_panicstring ("invalid memory address or "
- "nil pointer dereference");
-#endif
+ __splitstack_setcontext(&gp->m->gsignal->stackcontext[0]);
-#ifdef SIGSEGV
- case SIGSEGV:
- runtime_panicstring ("invalid memory address or "
- "nil pointer dereference");
-#endif
+ sigtrampgo(sig, info, context);
-#ifdef SIGFPE
- case SIGFPE:
- runtime_panicstring ("integer divide by zero or floating point error");
-#endif
- }
+ // We are going to return back to the signal trampoline and
+ // then to whatever we were doing before we got the signal.
+ // Restore the split stack context so that stack guards are
+ // checked correctly.
- /* All signals with _SigPanic should be in cases above, and this
- handler should only be invoked for those signals. */
- __builtin_unreachable ();
+ __splitstack_setcontext(&stack_context[0]);
}
-#endif /* !defined (SA_SIGINFO) */
-
-/* A signal handler used for signals which are not going to panic.
- This is called on the alternate signal stack so it may not split
- the stack. */
-
-static void
-sig_tramp_info (int, Siginfo *, void *) __attribute__ ((no_split_stack));
-
-static void
-sig_tramp_info (int sig, Siginfo *info, void *context)
-{
- G *gp;
- M *mp;
-#ifdef USING_SPLIT_STACK
- void *stack_context[10];
-#endif
-
- /* We are now running on the stack registered via sigaltstack.
- (Actually there is a small span of time between runtime_siginit
- and sigaltstack when the program starts.) */
- gp = runtime_g ();
- mp = runtime_m ();
-
- if (gp != NULL)
- {
-#ifdef USING_SPLIT_STACK
- __splitstack_getcontext (&stack_context[0]);
-#endif
- }
-
- if (gp != NULL && mp->gsignal != NULL)
- {
- /* We are running on the signal stack. Set the split stack
- context so that the stack guards are checked correctly. */
-#ifdef USING_SPLIT_STACK
- __splitstack_setcontext (&mp->gsignal->stackcontext[0]);
-#endif
- }
-
- runtime_sighandler (sig, info, context, gp);
+#endif // USING_SPLIT_STACK
- /* We are going to return back to the signal trampoline and then to
- whatever we were doing before we got the signal. Restore the
- split stack context so that stack guards are checked
- correctly. */
+// C code to manage the sigaction sa_sigaction field, which is
+// typically a union and so hard for mksysinfo.sh to handle.
- if (gp != NULL)
- {
-#ifdef USING_SPLIT_STACK
- __splitstack_setcontext (&stack_context[0]);
-#endif
- }
-}
-
-#ifndef SA_SIGINFO
+uintptr getSigactionHandler(struct sigaction*)
+ __attribute__ ((no_split_stack));
-static void sig_tramp (int sig) __attribute__ ((no_split_stack));
+uintptr getSigactionHandler(struct sigaction*)
+ __asm__ (GOSYM_PREFIX "runtime.getSigactionHandler");
-static void
-sig_tramp (int sig)
+uintptr
+getSigactionHandler(struct sigaction* sa)
{
- sig_tramp_info (sig, NULL, NULL);
+ return (uintptr)(sa->sa_sigaction);
}
-#endif
+void setSigactionHandler(struct sigaction*, uintptr)
+ __attribute__ ((no_split_stack));
+
+void setSigactionHandler(struct sigaction*, uintptr)
+ __asm__ (GOSYM_PREFIX "runtime.setSigactionHandler");
void
-runtime_setsig (int32 i, GoSighandler *fn, bool restart)
+setSigactionHandler(struct sigaction* sa, uintptr handler)
{
- struct sigaction sa;
- int r;
- SigTab *t;
-
- memset (&sa, 0, sizeof sa);
-
- r = sigfillset (&sa.sa_mask);
- __go_assert (r == 0);
-
- t = &runtime_sigtab[i];
-
- if ((t->flags & _SigPanic) == 0)
- {
-#ifdef SA_SIGINFO
- sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
- if (fn == runtime_sighandler)
- fn = (void *) sig_tramp_info;
- sa.sa_sigaction = (void *) fn;
-#else
- sa.sa_flags = SA_ONSTACK;
- if (fn == runtime_sighandler)
- fn = (void *) sig_tramp;
- sa.sa_handler = (void *) fn;
-#endif
- }
- else
- {
-#ifdef SA_SIGINFO
- sa.sa_flags = SA_SIGINFO;
- if (fn == runtime_sighandler)
- fn = (void *) sig_panic_info_handler;
- sa.sa_sigaction = (void *) fn;
-#else
- sa.sa_flags = 0;
- if (fn == runtime_sighandler)
- fn = (void *) sig_panic_handler;
- sa.sa_handler = (void *) fn;
-#endif
- }
-
- if (restart)
- sa.sa_flags |= SA_RESTART;
-
- if (sigaction (t->sig, &sa, NULL) != 0)
- __go_assert (0);
+ sa->sa_sigaction = (void*)(handler);
}
-GoSighandler*
-runtime_getsig (int32 i)
-{
- struct sigaction sa;
- int r;
- SigTab *t;
-
- memset (&sa, 0, sizeof sa);
-
- r = sigemptyset (&sa.sa_mask);
- __go_assert (r == 0);
-
- t = &runtime_sigtab[i];
-
- if (sigaction (t->sig, NULL, &sa) != 0)
- runtime_throw ("sigaction read failure");
+// C code to fetch values from the siginfo_t and ucontext_t pointers
+// passed to a signal handler.
- if ((void *) sa.sa_handler == sig_tramp_info)
- return runtime_sighandler;
-#ifdef SA_SIGINFO
- if ((void *) sa.sa_handler == sig_panic_info_handler)
- return runtime_sighandler;
-#else
- if ((void *) sa.sa_handler == sig_tramp
- || (void *) sa.sa_handler == sig_panic_handler)
- return runtime_sighandler;
-#endif
-
- return (void *) sa.sa_handler;
-}
-
-/* Used by the os package to raise SIGPIPE. */
+struct getSiginfoRet {
+ uintptr sigaddr;
+ uintptr sigpc;
+};
-void os_sigpipe (void) __asm__ (GOSYM_PREFIX "os.sigpipe");
+struct getSiginfoRet getSiginfo(siginfo_t *, void *)
+ __asm__(GOSYM_PREFIX "runtime.getSiginfo");
-void
-os_sigpipe (void)
+struct getSiginfoRet
+getSiginfo(siginfo_t *info, void *context __attribute__((unused)))
{
- struct sigaction sa;
- int i;
-
- if (__go_sigsend (SIGPIPE))
- return;
-
- memset (&sa, 0, sizeof sa);
-
- sa.sa_handler = SIG_DFL;
+ struct getSiginfoRet ret;
+ Location loc[1];
+ int32 n;
+
+ ret.sigaddr = (uintptr)(info->si_addr);
+ ret.sigpc = 0;
+
+ // There doesn't seem to be a portable way to get the PC.
+ // Use unportable code to pull it from context, and if that fails
+ // try a stack backtrace across the signal handler.
+
+#ifdef __x86_64__
+ #ifdef __linux__
+ ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.gregs[REG_RIP];
+ #endif
+#endif
+#ifdef __i386__
+ #ifdef __linux__
+ ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.gregs[REG_EIP];
+ #endif
+#endif
+
+ if (ret.sigpc == 0) {
+ // Skip getSiginfo/sighandler/sigtrampgo/sigtramp/handler.
+ n = runtime_callers(5, &loc[0], 1, false);
+ if (n > 0) {
+ ret.sigpc = loc[0].pc;
+ }
+ }
- i = sigemptyset (&sa.sa_mask);
- __go_assert (i == 0);
+ return ret;
+}
- if (sigaction (SIGPIPE, &sa, NULL) != 0)
- abort ();
+// Dump registers when crashing in a signal.
+// There is no portable way to write this,
+// so we just have some CPU/OS specific implementations.
- raise (SIGPIPE);
-}
+void dumpregs(siginfo_t *, void *)
+ __asm__(GOSYM_PREFIX "runtime.dumpregs");
void
-runtime_setprof(bool on)
+dumpregs(siginfo_t *info __attribute__((unused)), void *context __attribute__((unused)))
{
- USED(on);
+#ifdef __x86_64__
+ #ifdef __linux__
+ {
+ mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext;
+
+ runtime_printf("rax %X\n", m->gregs[REG_RAX]);
+ runtime_printf("rbx %X\n", m->gregs[REG_RBX]);
+ runtime_printf("rcx %X\n", m->gregs[REG_RCX]);
+ runtime_printf("rdx %X\n", m->gregs[REG_RDX]);
+ runtime_printf("rdi %X\n", m->gregs[REG_RDI]);
+ runtime_printf("rsi %X\n", m->gregs[REG_RSI]);
+ runtime_printf("rbp %X\n", m->gregs[REG_RBP]);
+ runtime_printf("rsp %X\n", m->gregs[REG_RSP]);
+ runtime_printf("r8 %X\n", m->gregs[REG_R8]);
+ runtime_printf("r9 %X\n", m->gregs[REG_R9]);
+ runtime_printf("r10 %X\n", m->gregs[REG_R10]);
+ runtime_printf("r11 %X\n", m->gregs[REG_R11]);
+ runtime_printf("r12 %X\n", m->gregs[REG_R12]);
+ runtime_printf("r13 %X\n", m->gregs[REG_R13]);
+ runtime_printf("r14 %X\n", m->gregs[REG_R14]);
+ runtime_printf("r15 %X\n", m->gregs[REG_R15]);
+ runtime_printf("rip %X\n", m->gregs[REG_RIP]);
+ runtime_printf("rflags %X\n", m->gregs[REG_EFL]);
+ runtime_printf("cs %X\n", m->gregs[REG_CSGSFS] & 0xffff);
+ runtime_printf("fs %X\n", (m->gregs[REG_CSGSFS] >> 16) & 0xffff);
+ runtime_printf("gs %X\n", (m->gregs[REG_CSGSFS] >> 32) & 0xffff);
+ }
+ #endif
+#endif
+
+#ifdef __i386__
+ #ifdef __linux__
+ {
+ mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext;
+
+ runtime_printf("eax %X\n", m->gregs[REG_EAX]);
+ runtime_printf("ebx %X\n", m->gregs[REG_EBX]);
+ runtime_printf("ecx %X\n", m->gregs[REG_ECX]);
+ runtime_printf("edx %X\n", m->gregs[REG_EDX]);
+ runtime_printf("edi %X\n", m->gregs[REG_EDI]);
+ runtime_printf("esi %X\n", m->gregs[REG_ESI]);
+ runtime_printf("ebp %X\n", m->gregs[REG_EBP]);
+ runtime_printf("esp %X\n", m->gregs[REG_ESP]);
+ runtime_printf("eip %X\n", m->gregs[REG_EIP]);
+ runtime_printf("eflags %X\n", m->gregs[REG_EFL]);
+ runtime_printf("cs %X\n", m->gregs[REG_CS]);
+ runtime_printf("fs %X\n", m->gregs[REG_FS]);
+ runtime_printf("gs %X\n", m->gregs[REG_GS]);
+ }
+ #endif
+#endif
}
int32 t;
g = runtime_g();
- if(g->sig != 0)
- runtime_printf("[signal %x code=%p addr=%p]\n",
+ if(g->sig != 0) {
+ runtime_printf("[signal %x code=%p addr=%p",
g->sig, (void*)g->sigcode0, (void*)g->sigcode1);
+ if (g->sigpc != 0)
+ runtime_printf(" pc=%p", g->sigpc);
+ runtime_printf("]\n");
+ }
if((t = runtime_gotraceback(&crash)) > 0){
if(g != runtime_m()->g0) {
// entersyscall is going to return immediately after.
void runtime_entersyscall(int32) __attribute__ ((no_split_stack));
-static void doentersyscall(void) __attribute__ ((no_split_stack, noinline));
+static void doentersyscall(uintptr, uintptr)
+ __attribute__ ((no_split_stack, noinline));
void
runtime_entersyscall(int32 dummy __attribute__ ((unused)))
// callee-saved registers to access the TLS variable g. We
// don't want to put the ucontext_t on the stack because it is
// large and we can not split the stack here.
- doentersyscall();
+ doentersyscall((uintptr)runtime_getcallerpc(&dummy),
+ (uintptr)runtime_getcallersp(&dummy));
}
static void
-doentersyscall()
+doentersyscall(uintptr pc, uintptr sp)
{
// Disable preemption because during this function g is in _Gsyscall status,
// but can have inconsistent g->sched, do not let GC observe it.
}
#endif
+ g->syscallsp = sp;
+ g->syscallpc = pc;
+
g->atomicstatus = _Gsyscall;
if(runtime_atomicload(&runtime_sched.sysmonwait)) { // TODO: fast atomic
// held in registers will be seen by the garbage collector.
getcontext(ucontext_arg(&g->gcregs[0]));
+ g->syscallpc = (uintptr)runtime_getcallerpc(&dummy);
+ g->syscallsp = (uintptr)runtime_getcallersp(&dummy);
+
g->atomicstatus = _Gsyscall;
p = releasep();
#endif
gp->gcnextsp = nil;
runtime_memclr(&gp->gcregs[0], sizeof gp->gcregs);
+ gp->syscallsp = 0;
gp->m->locks--;
return;
}
gp->gcnextsp = nil;
runtime_memclr(&gp->gcregs[0], sizeof gp->gcregs);
+ gp->syscallsp = 0;
+
// Note that this gp->m might be different than the earlier
// gp->m after returning from runtime_mcall.
((P*)gp->m->p)->syscalltick++;
String runtime_gostringnocopy(const byte*)
__asm__ (GOSYM_PREFIX "runtime.gostringnocopy");
void runtime_schedinit(void);
-void runtime_initsig(bool);
-void runtime_sigenable(uint32 sig);
-void runtime_sigdisable(uint32 sig);
-void runtime_sigignore(uint32 sig);
+void runtime_initsig(bool)
+ __asm__ (GOSYM_PREFIX "runtime.initsig");
int32 runtime_gotraceback(bool *crash);
void runtime_goroutineheader(G*)
__asm__ (GOSYM_PREFIX "runtime.goroutineheader");
void runtime_mpreinit(M*);
void runtime_minit(void);
void runtime_unminit(void);
-void runtime_needm(void);
-void runtime_dropm(void);
+void runtime_needm(void)
+ __asm__ (GOSYM_PREFIX "runtime.needm");
+void runtime_dropm(void)
+ __asm__ (GOSYM_PREFIX "runtime.dropm");
void runtime_signalstack(byte*, int32);
MCache* runtime_allocmcache(void);
void runtime_freemcache(MCache*);
void runtime_mprofinit(void);
#define runtime_malloc(s) __go_alloc(s)
#define runtime_free(p) __go_free(p)
-#define runtime_getcallersp(p) __builtin_frame_address(1)
-int32 runtime_mcount(void);
+#define runtime_getcallersp(p) __builtin_frame_address(0)
+int32 runtime_mcount(void)
+ __asm__ (GOSYM_PREFIX "runtime.mcount");
int32 runtime_gcount(void);
void runtime_mcall(void(*)(G*));
uint32 runtime_fastrand1(void) __asm__ (GOSYM_PREFIX "runtime.fastrand1");
#define runtime_atomicloadp(p) __atomic_load_n (p, __ATOMIC_SEQ_CST)
#define runtime_atomicstorep(p, v) __atomic_store_n (p, v, __ATOMIC_SEQ_CST)
-void runtime_setg(G*);
+void runtime_setg(G*)
+ __asm__ (GOSYM_PREFIX "runtime.setg");
void runtime_newextram(void);
#define runtime_exit(s) exit(s)
#define runtime_breakpoint() __builtin_trap()
void runtime_exitsyscall(int32)
__asm__ (GOSYM_PREFIX "runtime.exitsyscall");
G* __go_go(void (*pfn)(void*), void*);
-void siginit(void);
-bool __go_sigsend(int32 sig);
int32 runtime_callers(int32, Location*, int32, bool keep_callers);
int64 runtime_nanotime(void) // monotonic time
__asm__(GOSYM_PREFIX "runtime.nanotime");
int64 runtime_unixnanotime(void) // real time, can skip
__asm__ (GOSYM_PREFIX "runtime.unixnanotime");
void runtime_dopanic(int32) __attribute__ ((noreturn));
-void runtime_startpanic(void);
+void runtime_startpanic(void)
+ __asm__ (GOSYM_PREFIX "runtime.startpanic");
void runtime_freezetheworld(void);
void runtime_unwindstack(G*, byte*);
-void runtime_sigprof();
-void runtime_resetcpuprofiler(int32);
+void runtime_sigprof()
+ __asm__ (GOSYM_PREFIX "runtime.sigprof");
+void runtime_resetcpuprofiler(int32)
+ __asm__ (GOSYM_PREFIX "runtime.resetcpuprofiler");
void runtime_setcpuprofilerate_m(int32)
__asm__ (GOSYM_PREFIX "runtime.setcpuprofilerate_m");
void runtime_cpuprofAdd(Slice)
extern int64 runtime_blockprofilerate;
G* runtime_netpoll(bool)
__asm__ (GOSYM_PREFIX "runtime.netpoll");
-void runtime_crash(void);
+void runtime_crash(void)
+ __asm__ (GOSYM_PREFIX "runtime.crash");
void runtime_parsedebugvars(void)
__asm__(GOSYM_PREFIX "runtime.parsedebugvars");
void _rt0_go(void);
+++ /dev/null
-// 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
-
-#include <sys/time.h>
-
-#include "runtime.h"
-#include "defs.h"
-#include "signal_unix.h"
-
-extern SigTab runtime_sigtab[];
-
-void
-runtime_initsig(bool preinit)
-{
- int32 i;
- SigTab *t;
-
- // For c-archive/c-shared this is called by go-libmain.c with
- // preinit == true.
- if(runtime_isarchive && !preinit)
- return;
-
- // First call: basic setup.
- for(i = 0; runtime_sigtab[i].sig != -1; i++) {
- t = &runtime_sigtab[i];
- if((t->flags == 0) || (t->flags & _SigDefault))
- continue;
-
- t->fwdsig = runtime_getsig(i);
-
- // 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(t->sig) {
- case SIGHUP:
- case SIGINT:
- if(t->fwdsig == GO_SIG_IGN) {
- continue;
- }
- }
-
- if(runtime_isarchive && (t->flags&_SigPanic) == 0)
- continue;
-
- t->flags |= _SigHandling;
- runtime_setsig(i, runtime_sighandler, true);
- }
-}
-
-void
-runtime_sigenable(uint32 sig)
-{
- int32 i;
- SigTab *t;
-
- t = nil;
- for(i = 0; runtime_sigtab[i].sig != -1; i++) {
- if(runtime_sigtab[i].sig == (int32)sig) {
- t = &runtime_sigtab[i];
- break;
- }
- }
-
- if(t == nil)
- return;
-
- if((t->flags & _SigNotify) && !(t->flags & _SigHandling)) {
- t->flags |= _SigHandling;
- t->fwdsig = runtime_getsig(i);
- runtime_setsig(i, runtime_sighandler, true);
- }
-}
-
-void
-runtime_sigdisable(uint32 sig)
-{
- int32 i;
- SigTab *t;
-
- t = nil;
- for(i = 0; runtime_sigtab[i].sig != -1; i++) {
- if(runtime_sigtab[i].sig == (int32)sig) {
- t = &runtime_sigtab[i];
- break;
- }
- }
-
- if(t == nil)
- return;
-
- if((sig == SIGHUP || sig == SIGINT) && t->fwdsig == GO_SIG_IGN) {
- t->flags &= ~_SigHandling;
- runtime_setsig(i, t->fwdsig, true);
- }
-}
-
-void
-runtime_sigignore(uint32 sig)
-{
- int32 i;
- SigTab *t;
-
- t = nil;
- for(i = 0; runtime_sigtab[i].sig != -1; i++) {
- if(runtime_sigtab[i].sig == (int32)sig) {
- t = &runtime_sigtab[i];
- break;
- }
- }
-
- if(t == nil)
- return;
-
- if((t->flags & _SigNotify) != 0) {
- t->flags &= ~_SigHandling;
- runtime_setsig(i, GO_SIG_IGN, true);
- }
-}
-
-void
-runtime_resetcpuprofiler(int32 hz)
-{
- struct itimerval it;
-
- runtime_memclr((byte*)&it, sizeof it);
- if(hz == 0) {
- runtime_setitimer(ITIMER_PROF, &it, nil);
- } else {
- it.it_interval.tv_sec = 0;
- it.it_interval.tv_usec = 1000000 / hz;
- it.it_value = it.it_interval;
- runtime_setitimer(ITIMER_PROF, &it, nil);
- }
- runtime_m()->profilehz = hz;
-}
-
-void
-runtime_unblocksignals(void)
-{
- sigset_t sigset_none;
- sigemptyset(&sigset_none);
- pthread_sigmask(SIG_SETMASK, &sigset_none, nil);
-}
-
-void
-runtime_crash(void)
-{
- int32 i;
-
-#ifdef GOOS_darwin
- // OS X core dumps are linear dumps of the mapped memory,
- // from the first virtual byte to the last, with zeros in the gaps.
- // Because of the way we arrange the address space on 64-bit systems,
- // this means the OS X core file will be >128 GB and even on a zippy
- // workstation can take OS X well over an hour to write (uninterruptible).
- // Save users from making that mistake.
- if(sizeof(void*) == 8)
- return;
-#endif
-
- runtime_unblocksignals();
- for(i = 0; runtime_sigtab[i].sig != -1; i++)
- if(runtime_sigtab[i].sig == SIGABRT)
- break;
- runtime_setsig(i, GO_SIG_DFL, false);
- runtime_raise(SIGABRT);
-}
-
-void
-runtime_raise(int32 sig)
-{
- raise(sig);
-}
+++ /dev/null
-// 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.
-
-#include <signal.h>
-
-#define GO_SIG_DFL ((void*)SIG_DFL)
-#define GO_SIG_IGN ((void*)SIG_IGN)
-
-#ifdef SA_SIGINFO
-typedef siginfo_t Siginfo;
-#else
-typedef void *Siginfo;
-#endif
-
-typedef void GoSighandler(int32, Siginfo*, void*, G*);
-void runtime_setsig(int32, GoSighandler*, bool);
-GoSighandler* runtime_getsig(int32);
-
-void runtime_sighandler(int32 sig, Siginfo *info, void *context, G *gp);
-void runtime_raise(int32);
-
+++ /dev/null
-// 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: 0, HASWAITER and HASSIGNAL.
-// HASWAITER means that signal_recv() is blocked on sig.Note and there are no
-// new pending signals.
-// HASSIGNAL means that sig.mask *may* contain new pending signals,
-// signal_recv() can't be blocked in this state.
-// 0 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 sigsend()'s and signal_recv() execute concurrently, it can lead to
-// unnecessary rechecks of sig.mask, but must not lead to missed signals
-// nor deadlocks.
-
-package signal
-#include "config.h"
-#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
-#include "defs.h"
-
-static struct {
- Note;
- uint32 mask[(NSIG+31)/32];
- uint32 wanted[(NSIG+31)/32];
- uint32 state;
- bool inuse;
-} sig;
-
-enum {
- HASWAITER = 1,
- HASSIGNAL = 2,
-};
-
-// Called from sighandler to send a signal back out of the signal handling thread.
-bool
-__go_sigsend(int32 s)
-{
- uint32 bit, mask, old, new;
-
- if(!sig.inuse || s < 0 || (size_t)s >= 32*nelem(sig.wanted) || !(sig.wanted[s/32]&(1U<<(s&31))))
- return false;
- bit = 1 << (s&31);
- for(;;) {
- mask = sig.mask[s/32];
- if(mask & bit)
- break; // signal already in queue
- if(runtime_cas(&sig.mask[s/32], mask, mask|bit)) {
- // Added to queue.
- // Only send a wakeup if the receiver needs a kick.
- for(;;) {
- old = runtime_atomicload(&sig.state);
- if(old == HASSIGNAL)
- break;
- if(old == HASWAITER)
- new = 0;
- else // if(old == 0)
- new = HASSIGNAL;
- if(runtime_cas(&sig.state, old, new)) {
- if (old == HASWAITER)
- runtime_notewakeup(&sig);
- break;
- }
- }
- break;
- }
- }
- return true;
-}
-
-// Called to receive the next queued signal.
-// Must only be called from a single goroutine at a time.
-func signal_recv() (m uint32) {
- static uint32 recv[nelem(sig.mask)];
- uint32 i, old, new;
-
- for(;;) {
- // Serve from local copy if there are bits left.
- for(i=0; i<NSIG; i++) {
- if(recv[i/32]&(1U<<(i&31))) {
- recv[i/32] ^= 1U<<(i&31);
- m = i;
- goto done;
- }
- }
-
- // Check and update sig.state.
- for(;;) {
- old = runtime_atomicload(&sig.state);
- if(old == HASWAITER)
- runtime_throw("inconsistent state in signal_recv");
- if(old == HASSIGNAL)
- new = 0;
- else // if(old == 0)
- new = HASWAITER;
- if(runtime_cas(&sig.state, old, new)) {
- if (new == HASWAITER) {
- runtime_notetsleepg(&sig, -1);
- runtime_noteclear(&sig);
- }
- break;
- }
- }
-
- // Get a new local copy.
- for(i=0; (size_t)i<nelem(sig.mask); i++) {
- for(;;) {
- m = sig.mask[i];
- if(runtime_cas(&sig.mask[i], m, 0))
- break;
- }
- recv[i] = m;
- }
- }
-
-done:;
- // goc requires that we fall off the end of functions
- // that return values instead of using our own return
- // statements.
-}
-
-// Must only be called from a single goroutine at a time.
-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
- runtime_noteclear(&sig);
- return;
- }
-
- if(s >= nelem(sig.wanted)*32)
- return;
- sig.wanted[s/32] |= 1U<<(s&31);
- runtime_sigenable(s);
-}
-
-// Must only be called from a single goroutine at a time.
-func signal_disable(s uint32) {
- if(s >= nelem(sig.wanted)*32)
- return;
- sig.wanted[s/32] &= ~(1U<<(s&31));
- runtime_sigdisable(s);
-}
-
-// Must only be called from a single goroutine at a time.
-func signal_ignore(s uint32) {
- if (s >= nelem(sig.wanted)*32)
- return;
- sig.wanted[s/32] &= ~(1U<<(s&31));
- runtime_sigignore(s);
-}
-
-// This runs on a foreign stack, without an m or a g. No stack split.
-void
-runtime_badsignal(int sig)
-{
- __go_sigsend(sig);
-}
#include "runtime.h"
#include "defs.h"
-#include "signal_unix.h"
// Linux futex.
/* Ask the OS to reschedule this thread. */
+void runtime_osyield(void)
+ __attribute__ ((no_split_stack));
+
void
runtime_osyield (void)
{