STTNet 0.7.0

Chapter 17: Linux Signals and Graceful Shutdown

This chapter lists common Linux signals and their numbers and describes the boundary between asynchronous delivery and safe cleanup.

1. Why synchronous waiting is safer

Only a small set of functions are async-signal-safe. C++ destruction, locks, logging, allocation, and OpenSSL cleanup are unsafe in an asynchronous signal handler. STTNet blocks termination signals before creating threads and waits for them synchronously in the main thread.

2. Common Linux signal numbers

SignalLinux numberMeaning and policy
SIGHUP1Terminal hangup / commonly reload; not handled automatically
SIGINT2Ctrl-C; waited by waitForTerminationSignal()
SIGQUIT3Quit and possibly core dump; not a normal shutdown request
SIGABRT6abort(); default fatal behavior remains active
SIGKILL9Immediate termination; cannot be caught or cleaned up
SIGSEGV11Invalid memory access; retain default behavior and core dump
SIGPIPE13Write to closed pipe/socket; ignored by setExceptionHandling()
SIGTERM15Standard termination request; waited synchronously
SIGCHLD17Child state change; relevant to process management
SIGSTOP19Forced stop; cannot be caught
Number note: These are common values on STTNet's Linux target. Code uses symbolic constants such as SIGTERM; numeric values remain documentation only.

3. Complete shutdown model

using stt::system::ServerSetting;

ServerSetting::setExceptionHandling();

// Block SIGINT (2) and SIGTERM (15) before any framework thread exists.
if(!ServerSetting::blockTerminationSignals())
    return 1;

stt::network::HttpServer server;
server.setGracefulShutdownTimeout(5000);
if(!server.startListen(8083))
    return 2;

// Wait in normal C++ thread context.
const int signalNumber = ServerSetting::waitForTerminationSignal();
if(signalNumber < 0)
    return 3;

return server.close() ? 0 : 4;

4. SIGTERM versus SIGKILL

SIGTERM (15) requests an orderly shutdown. SIGKILL (9) immediately terminates the process without destructors, log flushing, or cleanup. A typical supervisor sends SIGTERM and uses SIGKILL only after the shutdown grace period expires.

5. Shutdown flow

  1. setExceptionHandling() and blockTerminationSignals() run in the main thread.
  2. Logger, server, Reactor, and Worker objects are created.
  3. The listener starts.
  4. waitForTerminationSignal() performs the synchronous wait.
  5. server.close() runs after SIGINT or SIGTERM is received.
Server destruction, logging, and locking run in normal thread context rather than an asynchronous signal handler.

Complete signal shutdown demo →