runtime: copy signal code from Go 1.7 runtime
authorIan Lance Taylor <ian@gcc.gnu.org>
Thu, 10 Nov 2016 22:53:23 +0000 (22:53 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 10 Nov 2016 22:53:23 +0000 (22:53 +0000)
    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

29 files changed:
gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/parse.cc
libgo/Makefile.am
libgo/Makefile.in
libgo/go/runtime/panic.go [new file with mode: 0644]
libgo/go/runtime/runtime2.go
libgo/go/runtime/signal1_unix.go [new file with mode: 0644]
libgo/go/runtime/signal2_unix.go
libgo/go/runtime/signal_gccgo.go [new file with mode: 0644]
libgo/go/runtime/signal_sighandler.go [new file with mode: 0644]
libgo/go/runtime/signal_sigtramp.go
libgo/go/runtime/signal_unix.go [new file with mode: 0644]
libgo/go/runtime/sigpanic_unix.go [new file with mode: 0644]
libgo/go/runtime/sigqueue.go [new file with mode: 0644]
libgo/go/runtime/stubs.go
libgo/mkrsysinfo.sh
libgo/mksigtab.sh [new file with mode: 0644]
libgo/runtime/go-signal.c
libgo/runtime/panic.c
libgo/runtime/proc.c
libgo/runtime/runtime.h
libgo/runtime/signal_unix.c [deleted file]
libgo/runtime/signal_unix.h [deleted file]
libgo/runtime/sigqueue.goc [deleted file]
libgo/runtime/thread-linux.c
libgo/runtime/yield.c

index 40046113d3f45a035c1a66207c126c16ce569f7b..c25c2e486429c3be2637ff60b6942b38f74d05d4 100644 (file)
@@ -1,4 +1,4 @@
-cac897bd27885c18a16dacfe27d5efd4526455c5
+449e918b0f93d3e3339edcec21a5bc157f548e54
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index d6fa04b621551b738117423c318e5469fab7bafc..1b0434ed0983fad09f760978103f7f5bb1ea77e7 100644 (file)
@@ -3791,7 +3791,7 @@ Unary_expression::do_flatten(Gogo* gogo, Named_object*,
        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")
index a166d1c5c4e91920795cdb9dd15492ac42e0b3a6..acfab188a80c313e9ddbaeb8f74d1750354032d4 100644 (file)
@@ -394,6 +394,7 @@ void
 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())
@@ -497,7 +498,8 @@ Gogo::import_package(const std::string& filename,
                                                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;
     }
 
@@ -2179,6 +2181,14 @@ Gogo::is_thunk(const Named_object* no)
 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();
index 17d46d503fdbebe1cfaf0bfa301803da6275786e..62bbf9e11ae3aa86883bb55c5712aa4a77d10bcf 100644 (file)
@@ -301,7 +301,7 @@ class Gogo
   // 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
index b7411d14ffa4c628f8f45966a8e83aa51678fde5..34a7765418db9e71a766450bb43a62c54258af77 100644 (file)
@@ -5722,7 +5722,7 @@ Parse::import_spec(void*)
     }
 
   this->gogo_->import_package(token->string_value(), local_name,
-                             is_local_name_exported, location);
+                             is_local_name_exported, true, location);
 
   this->advance_token();
 }
index edf193a5d4090ef40ab60a852ce35799b892ca2d..b29f6c4ff5793d863d726bcb387b33e29e520e90 100644 (file)
@@ -480,14 +480,12 @@ runtime_files = \
        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
@@ -504,10 +502,6 @@ runtime1.c: $(srcdir)/runtime/runtime1.goc goc2c
        ./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 $@
@@ -572,6 +566,12 @@ s-runtime_sysinfo: $(srcdir)/mkrsysinfo.sh gen-sysinfo.go
        $(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
@@ -1038,7 +1038,7 @@ $(foreach package,$(PACKAGES),$(eval $(call PACKAGE_template,$(package))))
 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.
index 908e66042a5f86b4d27b3aab41b0caaa6f6886d6..44a6999c2064eca2d5bfc0c8f3600f0dc13cedcf 100644 (file)
@@ -203,9 +203,8 @@ am__objects_5 = go-assert.lo go-breakpoint.lo go-caller.lo \
        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) \
@@ -828,14 +827,12 @@ runtime_files = \
        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
@@ -1141,7 +1138,7 @@ CHECK_DEPS = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \
 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 = \
@@ -1525,8 +1522,6 @@ distclean-compile:
 @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@
@@ -1966,13 +1961,6 @@ runtime_c.lo: runtime/runtime_c.c
 @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
@@ -3177,10 +3165,6 @@ runtime1.c: $(srcdir)/runtime/runtime1.goc goc2c
        ./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 $@
@@ -3245,6 +3229,12 @@ s-runtime_sysinfo: $(srcdir)/mkrsysinfo.sh gen-sysinfo.go
        $(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
diff --git a/libgo/go/runtime/panic.go b/libgo/go/runtime/panic.go
new file mode 100644 (file)
index 0000000..c39107b
--- /dev/null
@@ -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
+}
index 37ade7d45b38e106af32f444281edf4f07ffe0c0..f3bbb589d1c986d03971f379aaba75e78a7b0e4d 100644 (file)
@@ -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 (file)
index 0000000..f932765
--- /dev/null
@@ -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()
+}
index b7479a71a778991a8c40678f55a54982e1669ed6..2a39eac43fa23442830cc4c6fbe6c7e165424a10 100644 (file)
@@ -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 (file)
index 0000000..0ecafcc
--- /dev/null
@@ -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 (file)
index 0000000..3cbec66
--- /dev/null
@@ -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)
+}
index f4a6ebd71c1c9b024a87ece4f5cbb320e0490d6e..67b9e6704333df70d476a066921ffaa23ab46627 100644 (file)
@@ -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 (file)
index 0000000..f59c9b9
--- /dev/null
@@ -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 (file)
index 0000000..00ad090
--- /dev/null
@@ -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 (file)
index 0000000..a6d498f
--- /dev/null
@@ -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
+}
index 755933de713db56be3ba56ab7dd12aa1a24dd240..d0641ed71503eb432c892ec8bd694f83be2a6eac 100644 (file)
@@ -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()
index 32799d6251b23ef20707e787116eb6397e969ff4..1ab4ea40f7154f967a1389253ca0b9da58086f7d 100755 (executable)
@@ -41,6 +41,11 @@ echo $timeval | \
   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.
diff --git a/libgo/mksigtab.sh b/libgo/mksigtab.sh
new file mode 100644 (file)
index 0000000..d33b7e2
--- /dev/null
@@ -0,0 +1,98 @@
+#!/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 '}'
index e3e4a1985660eb67b58c6c9d85c6d3487ad628db..9ee02a34f8fbeefdb425c69bbdb11aed8a0c7c19 100644 (file)
@@ -8,11 +8,11 @@
 #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
@@ -24,530 +24,257 @@ extern void __splitstack_getcontext(void *context[10]);
 
 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
 }
index 0dd677693af3661710bbb801fb352472a6d78c4b..78c8f5d4b5b2fe90d0ca678872ccbb686bab78b6 100644 (file)
@@ -122,9 +122,13 @@ runtime_dopanic(int32 unused __attribute__ ((unused)))
        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) {
index a9f3b837334d13b52a87adabd536be758cf1d26e..62abc9d238ba88697b97d7f052a693d777c63aea 100644 (file)
@@ -2022,7 +2022,8 @@ goexit0(G *gp)
 // 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)))
@@ -2040,11 +2041,12 @@ 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.
@@ -2067,6 +2069,9 @@ doentersyscall()
        }
 #endif
 
+       g->syscallsp = sp;
+       g->syscallpc = pc;
+
        g->atomicstatus = _Gsyscall;
 
        if(runtime_atomicload(&runtime_sched.sysmonwait)) {  // TODO: fast atomic
@@ -2118,6 +2123,9 @@ runtime_entersyscallblock(int32 dummy __attribute__ ((unused)))
        // 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();
@@ -2155,6 +2163,7 @@ runtime_exitsyscall(int32 dummy __attribute__ ((unused)))
 #endif
                gp->gcnextsp = nil;
                runtime_memclr(&gp->gcregs[0], sizeof gp->gcregs);
+               gp->syscallsp = 0;
                gp->m->locks--;
                return;
        }
@@ -2176,6 +2185,8 @@ runtime_exitsyscall(int32 dummy __attribute__ ((unused)))
        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++;
index 501f1b41ace4f89b08571a6020f1f2b60236ff83..7d22631bddc802fc7943d9e64045fab463675e1a 100644 (file)
@@ -282,10 +282,8 @@ void*      runtime_mal(uintptr);
 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");
@@ -303,8 +301,10 @@ G* runtime_malg(int32, byte**, uintptr*);
 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*);
@@ -312,8 +312,9 @@ void        runtime_mallocinit(void);
 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");
@@ -339,7 +340,8 @@ int32       runtime_round2(int32 x); // round x up to a power of 2.
 #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()
@@ -358,19 +360,20 @@ void      runtime_entersyscallblock(int32)
 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)
@@ -385,7 +388,8 @@ void        runtime_blockevent(int64, int32);
 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);
diff --git a/libgo/runtime/signal_unix.c b/libgo/runtime/signal_unix.c
deleted file mode 100644 (file)
index 2cca08c..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-// 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);
-}
diff --git a/libgo/runtime/signal_unix.h b/libgo/runtime/signal_unix.h
deleted file mode 100644 (file)
index 1c51740..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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);
-
diff --git a/libgo/runtime/sigqueue.goc b/libgo/runtime/sigqueue.goc
deleted file mode 100644 (file)
index fba1c71..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// 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);
-}
index 63a2b7551f6718e333917bde2a8b9abda38adb0c..81ad0f9c9026024b7c5f21fb4c127976d54c109e 100644 (file)
@@ -4,7 +4,6 @@
 
 #include "runtime.h"
 #include "defs.h"
-#include "signal_unix.h"
 
 // Linux futex.
 
index 442d346db7d87628c8390c74e589fbd2cf5740bf..d0aed8d22ed432c0471430d9995c5954244165ad 100644 (file)
@@ -37,6 +37,9 @@ runtime_procyield (uint32 cnt)
 
 /* Ask the OS to reschedule this thread.  */
 
+void runtime_osyield(void)
+  __attribute__ ((no_split_stack));
+
 void
 runtime_osyield (void)
 {