internal/outcome/shim: EOF as exit request fallback
All checks were successful
Test / Create distribution (push) Successful in 35s
Test / Sandbox (push) Successful in 55s
Test / Sandbox (race detector) (push) Successful in 53s
Test / Hpkg (push) Successful in 53s
Test / Hakurei (race detector) (push) Successful in 1m1s
Test / Hakurei (push) Successful in 1m3s
Test / Flake checks (push) Successful in 1m34s

In some cases the signal might be delivered before the signal handler is installed, and synchronising against such a case is too expensive. Instead, use the pipe being closed as a fallback to the regular exit request. This change also moves installation of the signal handler early.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2025-11-02 04:41:26 +09:00
parent 2ba599b399
commit 6931ad95c3
5 changed files with 86 additions and 46 deletions

View File

@@ -96,11 +96,37 @@ func shimEntrypoint(k syscallDispatcher) {
k.fatalf("cannot set SUID_DUMP_DISABLE: %v", err)
}
// the Go runtime does not expose siginfo_t so SIGCONT is handled in C to check si_pid
ppid := k.getppid()
var signalPipe io.ReadCloser
if r, wKeepAlive, err := k.setupContSignal(ppid); err != nil {
switch {
case errors.As(err, new(*os.SyscallError)): // returned by os.Pipe
k.fatal(err.Error())
return
case errors.As(err, new(syscall.Errno)): // returned by hakurei_shim_setup_cont_signal
k.fatalf("cannot install SIGCONT handler: %v", err)
return
default: // unreachable
k.fatalf("cannot set up exit request: %v", err)
return
}
} else {
defer wKeepAlive()
signalPipe = r
}
var (
state outcomeState
closeSetup func() error
)
if f, err := k.receive(shimEnv, &state, nil); err != nil {
if errors.Is(err, io.EOF) {
// fallback exit request: signal handler not yet installed
k.exit(hst.ExitRequest)
}
if errors.Is(err, syscall.EBADF) {
k.fatal("invalid config descriptor")
}
@@ -119,25 +145,8 @@ func shimEntrypoint(k syscallDispatcher) {
}
}
// the Go runtime does not expose siginfo_t so SIGCONT is handled in C to check si_pid
var signalPipe io.ReadCloser
if r, wKeepAlive, err := k.setupContSignal(state.Shim.PrivPID); err != nil {
switch {
case errors.As(err, new(*os.SyscallError)): // returned by os.Pipe
k.fatal(err.Error())
return
case errors.As(err, new(syscall.Errno)): // returned by hakurei_shim_setup_cont_signal
k.fatalf("cannot install SIGCONT handler: %v", err)
return
default: // unreachable
k.fatalf("cannot set up exit request: %v", err)
return
}
} else {
defer wKeepAlive()
signalPipe = r
if state.Shim.PrivPID != ppid {
k.fatalf("unexpectedly reparented from %d to %d", state.Shim.PrivPID, ppid)
}
// pdeath_signal delivery is checked as if the dying process called kill(2), see kernel/exit.c