Synchronous Signal Handling#

Waiting (Blocking) For Signals#

  • sigwait() (and friends) synchronously wait for a signal

  • ⟶ No async delivery, no async-signal-safety concerns

  • ⟶ All fine

  • Use case: in a multithreaded program, it is probably best to dedicate one thread to signal handling, using sigwait() or similar.

Example: Self-Pipe Trick, Revisited#

#include <unistd.h>
#include <signal.h>
#include <print>

int main()
{
    std::println("PID={}", getpid());

    sigset_t interest;
    sigemptyset(&interest);
    sigaddset(&interest, SIGTERM);
    sigaddset(&interest, SIGINT);
    sigaddset(&interest, SIGUSR1);
    sigaddset(&interest, SIGUSR2);

    int rv = sigprocmask(SIG_BLOCK, &interest,         // <-- inhibit async delivery
                         nullptr);
    if (rv == -1) {
        perror("sigprocmask");
        return 1;
    }

    bool quit = false;
    while (!quit) {
        int signal;
        rv = sigwait(&interest, &signal);              // <-- read directly from kernel
        if (rv == -1) {
            perror("sigwait");
            return 1;
        }

        switch (signal) {                              // <-- same logic as in self-pipe
            case SIGTERM:
            case SIGINT:
                std::println("terminating");
                quit = true;
                break;
            case SIGUSR1:
                std::println("doing this");
                break;
            case SIGUSR2:
                std::println("doing that");
                break;
        }
    }
    return 0;
}