// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <signal.h>
#include <stdint.h>
#include <stdio.h>
+#include <string.h>
#include "p.h"
#include "libgo.h"
+static void (*oldHandler)(int, siginfo_t*, void*);
+
+static void handler(int signo, siginfo_t* info, void* ctxt) {
+ if (oldHandler) {
+ oldHandler(signo, info, ctxt);
+ }
+}
+
int main(void) {
+ struct sigaction sa;
+ struct sigaction osa;
int32_t res;
+ // Install our own signal handler.
+ memset(&sa, 0, sizeof sa);
+ sa.sa_sigaction = handler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
+ memset(&osa, 0, sizeof osa);
+ sigemptyset(&osa.sa_mask);
+ if (sigaction(SIGSEGV, &sa, &osa) < 0) {
+ perror("sigaction");
+ return 2;
+ }
+ if (osa.sa_handler == SIG_DFL || (osa.sa_flags&SA_ONSTACK) == 0) {
+ fprintf(stderr, "Go runtime did not install signal handler\n");
+ return 2;
+ }
+ oldHandler = osa.sa_sigaction;
+
if (!DidInitRun()) {
fprintf(stderr, "ERROR: buildmode=c-archive init should run\n");
return 2;
return 2;
}
+ // Make sure our signal handler is still the one in use.
+ if (sigaction(SIGSEGV, NULL, &sa) < 0) {
+ perror("sigaction check");
+ return 2;
+ }
+ if (sa.sa_sigaction != handler) {
+ fprintf(stderr, "ERROR: wrong signal handler: %p != %p\n", sa.sa_sigaction, handler);
+ return 2;
+ }
+
res = FromPkg();
if (res != 1024) {
fprintf(stderr, "ERROR: FromPkg()=%d, want 1024\n", res);
be run as part of an existing non-Go program. The non-Go code may
have already installed signal handlers when the Go code starts (that
may also happen in unusual cases when using cgo or SWIG; in that case,
-the discussion here applies).
+the discussion here applies). For -buildmode=c-archive the Go runtime
+will initialize signals at global constructor time. For
+-buildmode=c-shared the Go runtime will initialize signals when the
+shared library is loaded.
If the Go runtime sees an existing signal handler for the SIGCANCEL or
SIGSETXID signals (which are used only on GNU/Linux), it will turn on
var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n")
var failthreadcreate = []byte("runtime: failed to create new OS thread\n")
+// Called to do synchronous initialization of Go code built with
+// -buildmode=c-archive or -buildmode=c-shared.
+// None of the Go runtime is initialized.
+//go:nosplit
+//go:nowritebarrierrec
+func libpreinit() {
+ initsig(true)
+}
+
// Called to initialize a new m (including the bootstrap m).
// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
func mpreinit(mp *m) {
return 0
}
+//go:nosplit
+//go:nowritebarrierrec
func setsig(i int32, fn uintptr, restart bool) {
var sa sigactiont
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
sigaction(uint32(i), &sa, nil)
}
+//go:nosplit
+//go:nowritebarrierrec
func setsigstack(i int32) {
var osa usigactiont
sigaction(uint32(i), nil, &osa)
sigaction(uint32(i), &sa, nil)
}
+//go:nosplit
+//go:nowritebarrierrec
func getsig(i int32) uintptr {
var sa usigactiont
sigaction(uint32(i), nil, &sa)
sigaltstack(&st, nil)
}
+//go:nosplit
+//go:nowritebarrierrec
func updatesigmask(m sigmask) {
s := sigset(m[0])
sigprocmask(_SIG_SETMASK, &s, nil)
sa_mask sigset
}
+//go:nosplit
+//go:nowritebarrierrec
func setsig(i int32, fn uintptr, restart bool) {
var sa sigactiont
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
sigaction(i, &sa, nil)
}
+//go:nosplit
+//go:nowritebarrierrec
func setsigstack(i int32) {
throw("setsigstack")
}
+//go:nosplit
+//go:nowritebarrierrec
func getsig(i int32) uintptr {
var sa sigactiont
sigaction(i, nil, &sa)
sigaltstack(&st, nil)
}
+//go:nosplit
+//go:nowritebarrierrec
func updatesigmask(m sigmask) {
var mask sigset
copy(mask.__bits[:], m[:])
sa_mask sigset
}
+//go:nosplit
+//go:nowritebarrierrec
func setsig(i int32, fn uintptr, restart bool) {
var sa sigactiont
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
sigaction(i, &sa, nil)
}
+//go:nosplit
+//go:nowritebarrierrec
func setsigstack(i int32) {
throw("setsigstack")
}
+//go:nosplit
+//go:nowritebarrierrec
func getsig(i int32) uintptr {
var sa sigactiont
sigaction(i, nil, &sa)
sigaltstack(&st, nil)
}
+//go:nosplit
+//go:nowritebarrierrec
func updatesigmask(m [(_NSIG + 31) / 32]uint32) {
var mask sigset
copy(mask.__bits[:], m[:])
goenvs_unix()
}
+// Called to do synchronous initialization of Go code built with
+// -buildmode=c-archive or -buildmode=c-shared.
+// None of the Go runtime is initialized.
+//go:nosplit
+//go:nowritebarrierrec
+func libpreinit() {
+ initsig(true)
+}
+
// Called to initialize a new m (including the bootstrap m).
// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
func mpreinit(mp *m) {
func sigreturn()
func sigtramp()
+//go:nosplit
+//go:nowritebarrierrec
func setsig(i int32, fn uintptr, restart bool) {
var sa sigactiont
memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
fn = funcPC(sigtramp)
}
sa.sa_handler = fn
- // Qemu rejects rt_sigaction of SIGRTMAX (64).
- if rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask)) != 0 && i != 64 {
- throw("rt_sigaction failure")
- }
+ rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask))
}
+//go:nosplit
+//go:nowritebarrierrec
func setsigstack(i int32) {
var sa sigactiont
if rt_sigaction(uintptr(i), nil, &sa, unsafe.Sizeof(sa.sa_mask)) != 0 {
}
}
+//go:nosplit
+//go:nowritebarrierrec
func getsig(i int32) uintptr {
var sa sigactiont
sigaltstack(&st, nil)
}
+//go:nosplit
+//go:nowritebarrierrec
func updatesigmask(m sigmask) {
var mask sigset
sigcopyset(&mask, m)
goenvs_unix()
}
-func initsig() {
+func initsig(preinit bool) {
}
//go:nosplit
sa_flags int32
}
+//go:nosplit
+//go:nowritebarrierrec
func setsig(i int32, fn uintptr, restart bool) {
var sa sigactiont
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
sigaction(i, &sa, nil)
}
+//go:nosplit
+//go:nowritebarrierrec
func setsigstack(i int32) {
throw("setsigstack")
}
+//go:nosplit
+//go:nowritebarrierrec
func getsig(i int32) uintptr {
var sa sigactiont
sigaction(i, nil, &sa)
sigaltstack(&st, nil)
}
+//go:nosplit
+//go:nowritebarrierrec
func updatesigmask(m sigmask) {
var mask sigset
copy(mask.__bits[:], m[:])
sa_flags int32
}
+//go:nosplit
+//go:nowritebarrierrec
func setsig(i int32, fn uintptr, restart bool) {
var sa sigactiont
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
sigaction(i, &sa, nil)
}
+//go:nosplit
+//go:nowritebarrierrec
func setsigstack(i int32) {
throw("setsigstack")
}
+//go:nosplit
+//go:nowritebarrierrec
func getsig(i int32) uintptr {
var sa sigactiont
sigaction(i, nil, &sa)
sigaltstack(&st, nil)
}
+//go:nosplit
+//go:nowritebarrierrec
func updatesigmask(m sigmask) {
sigprocmask(_SIG_SETMASK, sigset(m[0]))
}
func goenvs() {
}
-func initsig() {
+func initsig(preinit bool) {
}
//go:nosplit
func sigtramp()
+//go:nosplit
+//go:nowritebarrierrec
func setsig(i int32, fn uintptr, restart bool) {
var sa sigactiont
sigaction(i, &sa, nil)
}
+//go:nosplit
+//go:nowritebarrierrec
func setsigstack(i int32) {
var sa sigactiont
sigaction(i, nil, &sa)
sigaction(i, &sa, nil)
}
+//go:nosplit
+//go:nowritebarrierrec
func getsig(i int32) uintptr {
var sa sigactiont
sigaction(i, nil, &sa)
sigaltstack(&st, nil)
}
+//go:nosplit
+//go:nowritebarrierrec
func updatesigmask(m sigmask) {
var mask sigset
copy(mask.__sigbits[:], m[:])
return int32(sysvicall4(&libc_pthread_create, uintptr(unsafe.Pointer(thread)), uintptr(unsafe.Pointer(attr)), uintptr(fn), uintptr(arg)))
}
+//go:nosplit
+//go:nowritebarrierrec
func raise(sig int32) /* int32 */ {
sysvicall1(&libc_raise, uintptr(sig))
}
sysvicall3(&libc_setitimer, uintptr(which), uintptr(unsafe.Pointer(value)), uintptr(unsafe.Pointer(ovalue)))
}
+//go:nosplit
+//go:nowritebarrierrec
func sigaction(sig int32, act *sigactiont, oact *sigactiont) /* int32 */ {
sysvicall3(&libc_sigaction, uintptr(sig), uintptr(unsafe.Pointer(act)), uintptr(unsafe.Pointer(oact)))
}
}
//go:nosplit
+//go:nowritebarrierrec
func sigprocmask(how int32, set *sigset, oset *sigset) /* int32 */ {
sysvicall3(&libc_sigprocmask, uintptr(how), uintptr(unsafe.Pointer(set)), uintptr(unsafe.Pointer(oset)))
}
cgoHasExtraM = true
newextram()
}
- initsig()
+ initsig(false)
}
if fn := _g_.m.mstartfn; fn != nil {
MOVL 12(BP), AX
MOVL AX, _rt0_386_darwin_lib_argv<>(SB)
+ // Synchronous initialization.
+ MOVL $runtime·libpreinit(SB), AX
+ CALL AX
+
SUBL $12, SP
// Create a new thread to do the runtime initialization and return.
MOVQ DI, _rt0_amd64_darwin_lib_argc<>(SB)
MOVQ SI, _rt0_amd64_darwin_lib_argv<>(SB)
+ // Synchronous initialization.
+ MOVQ $runtime·libpreinit(SB), AX
+ CALL AX
+
// Create a new thread to do the runtime initialization and return.
MOVQ _cgo_sys_thread_create(SB), AX
TESTQ AX, AX
MOVW R0, _rt0_arm_darwin_lib_argc<>(SB)
MOVW R1, _rt0_arm_darwin_lib_argv<>(SB)
+ // Synchronous initialization.
+ MOVW $runtime·libpreinit(SB), R3
+ CALL (R3)
+
// Create a new thread to do the runtime initialization and return.
MOVW _cgo_sys_thread_create(SB), R3
CMP $0, R3
MOVD R0, _rt0_arm64_darwin_lib_argc<>(SB)
MOVD R1, _rt0_arm64_darwin_lib_argv<>(SB)
+
+ // Synchronous initialization.
+ MOVD $runtime·libpreinit(SB), R4
+ BL (R4)
+
// Create a new thread to do the runtime initialization and return.
MOVD _cgo_sys_thread_create(SB), R4
MOVD $_rt0_arm64_darwin_lib_go(SB), R0
MOVL 12(BP), AX
MOVL AX, _rt0_386_linux_lib_argv<>(SB)
+ // Synchronous initialization.
+ MOVL $runtime·libpreinit(SB), AX
+ CALL AX
+
SUBL $8, SP
// Create a new thread to do the runtime initialization.
MOVQ DI, _rt0_amd64_linux_lib_argc<>(SB)
MOVQ SI, _rt0_amd64_linux_lib_argv<>(SB)
+ // Synchronous initialization.
+ MOVQ $runtime·libpreinit(SB), AX
+ CALL AX
+
// Create a new thread to do the runtime initialization and return.
MOVQ _cgo_sys_thread_create(SB), AX
TESTQ AX, AX
MOVW R0, _rt0_arm_linux_lib_argc<>(SB)
MOVW R1, _rt0_arm_linux_lib_argv<>(SB)
+ // Synchronous initialization.
+ MOVW $runtime·libpreinit(SB), R2
+ CALL (R2)
+
// Create a new thread to do the runtime initialization.
MOVW _cgo_sys_thread_create(SB), R2
CMP $0, R2
MOVD R0, _rt0_arm64_linux_lib_argc<>(SB)
MOVD R1, _rt0_arm64_linux_lib_argv<>(SB)
+ // Synchronous initialization.
+ MOVD $runtime·libpreinit(SB), R4
+ BL (R4)
+
// Create a new thread to do the runtime initialization and return.
MOVD _cgo_sys_thread_create(SB), R4
CMP $0, R4
maskUpdatedChan chan struct{}
)
-func initsig() {
+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("initsig")
+ 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
}
- // First call: basic setup.
for i := int32(0); i < _NSIG; i++ {
t := &sigtable[i]
if t.flags == 0 || t.flags&_SigDefault != 0 {
}
}
+//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.
<-maskUpdatedChan
if t.flags&_SigHandling == 0 {
t.flags |= _SigHandling
+ fwdSig[sig] = getsig(int32(sig))
setsig(int32(sig), funcPC(sighandler), true)
}
}
// 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{})
return false
}
fwdFn := fwdSig[sig]
+
+ if !signalsOK {
+ // The only way we can get here is if we are in a
+ // library or archive, we installed a signal handler
+ // at program startup, but the Go runtime has not yet
+ // been initialized.
+ if fwdFn == _SIG_DFL {
+ dieFromSignal(int32(sig))
+ } else {
+ sigfwd(fwdFn, sig, info, ctx)
+ }
+ return true
+ }
+
flags := sigtable[sig].flags
// If there is no handler to forward to, no need to forward.
// Following are not implemented.
-func initsig() {
+func initsig(preinit bool) {
}
func sigenable(sig uint32) {