By default go sets its own signal handlers:
runtime.mstart0()->runtime.mstart1()runtime.mstart1()->runtime.mstartm0()runtime.mstartm0()->runtime.initsig()runtime.initsig()->runtime.setsig(i, abi.FuncPCABIInternal(sighandler))
Another way to confirm this:
Dockerfile:
FROM alpine:3.20
COPY a.go .
RUN apk add go strace \
&& GO111MODULE=off go build \
&& strace ./_ 2>&1 | grep -E 'sigaction.*TERM|hello'a.go:
package main
import "fmt"
func main() {
fmt.Printf("hello world")
}$ docker build .
rt_sigaction(SIGTERM, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGTERM, {sa_handler=0x463de0, sa_mask=~[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_RESTART|SA_SIGINFO, sa_restorer=0x463f20}, NULL, 8) = 0
write(1, "hello world", 11hello world) = 11
To inspect the code with a debugger:
$ docker run --rm -it alpine:3.20
/ # apk add go
/ # go install github.com/go-delve/delve/cmd/dlv@latest
/ # GO111MODULE=off ~/go/bin/dlv debug
Type 'help' for list of commands.
(dlv) b initsig
Breakpoint 1 set at 0x44f464 for runtime.initsig() .usr/lib/go/src/runtime/signal_unix.go:114
(dlv) c
> [Breakpoint 1] runtime.initsig() .usr/lib/go/src/runtime/signal_unix.go:114 (hits total:1) (PC: 0x44f464)
Warning: debugging optimized function
109: // Initialize signals.
110: // Called by libpreinit so runtime may not be initialized.
111: //
112: //go:nosplit
113: //go:nowritebarrierrec
=> 114: func initsig(preinit bool) {
115: if !preinit {
116: // It's now OK for signal handlers to run.
117: signalsOK = true
118: }
119:
(dlv)
The table that defines what to do with each signal.