Use Case: Graceful Termination#
Problem#
Program blocks inside a main loop, waiting for something (network packet, command on a named pipe or message queue, …)
SIGTERM
(andSIGINT
, for that matter) should initiate a clean exit ⟶ cleanup, proper database sync, …⟶ Default disposition (immediate termination at signal arrival) is inappropriate
Solution#
Set
quit
flag in signal handlerMain loop’s blocking call is interrupted (
EINTR
)Flag can be honored
sig_atomic_t
as per POSIX standard (simplyint
on Linux)
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <print>
static volatile sig_atomic_t quit = 0; // <-- special "atomic" type
static void handler(int signal)
{
if (signal == SIGTERM || signal == SIGINT)
quit = 1; // <-- communicate into main loop
}
int main()
{
struct sigaction sa = { 0 };
sa.sa_handler = handler;
int rv = sigaction(SIGTERM, &sa, nullptr);
if (rv == -1) {
perror("sigaction(SIGTERM)");
return 1;
}
rv = sigaction(SIGINT, &sa, nullptr);
if (rv == -1) {
perror("sigaction(SIGINT)");
return 1;
}
while (!quit) { // <-- graceful termination
char c;
rv = read(STDIN_FILENO, &c, 1);
if (rv == -1) {
if (errno == EINTR) // <-- restart manually
continue;
else {
perror("read");
return 1;
}
}
}
std::println("cleaning up, bye"); // <-- sync database
return 0;
}