signalfd Integration#

Additional Feature: Graceful Termination (SIGTERM, SIGINT)#

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

static volatile sig_atomic_t quit = false;

static void handler(int signal)
{
    if (signal == SIGTERM || signal == SIGINT)
        quit = 1;
}

struct Database
{
    void insert(unsigned id, const std::string& firstname, const std::string& lastname) {
        std::println("insert id={}, firstname={}, lastname={}", id, firstname, lastname);
    }
    void commit() {
        std::println("commit");
    }
    void rollback() {
        std::println("rollback");
    }
};

int main()
{
    struct sigaction sa = { 0 };
    sa.sa_handler = handler;

    int rv = sigaction(SIGTERM, &sa, nullptr);         // <-- install async handler
    if (rv == -1) {
        perror("sigaction(SIGTERM)");
        return 1;
    }
    rv = sigaction(SIGINT, &sa, nullptr);              // <-- install async handler
    if (rv == -1) {
        perror("sigaction(SIGINT)");
        return 1;
    }
    
    static const std::regex re_line("^(\\d+)\\s+(\\w+)\\s+(\\w+)\\s*$");
    Database db;

    while (!quit) {
        char line[64];
        ssize_t nread = read(STDIN_FILENO,             // <-- blocking read from fd 0
                             line, sizeof(line)-1);
        if (nread == -1) {
            if (errno == EINTR)
                continue;
            perror("read");
            return 1;
        }
        if (nread == 0)
            break;

        std::string sline(line, nread);
        std::smatch match;
        if (std::regex_search(sline, match, re_line))
            db.insert(std::stoi(match[1].str()), match[2].str(), match[3].str());
    }

    db.commit();                                       // <-- commit on the way out
                                                       //     (-> "graceful shutdown")
    return 0;
};

Additional Feature: Commit/Rollback (SIGUSR1, SIGUSR2)#

  • SIGUSR1: commit+log+debug request asynchronously (by the auditor?)

  • SIGUSR2: rollback

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

static volatile sig_atomic_t quit = false;
static volatile sig_atomic_t commit = false;
static volatile sig_atomic_t rollback = false;


static void handler(int signal)
{
    switch (signal) {
        case SIGTERM:
        case SIGINT:
            quit = true;
            break;
        case SIGUSR1:
            commit = true;
            break;
        case SIGUSR2:
            rollback = true;
            break;
        default:
            abort();                                   // <-- signal not expected
    }
}

struct Database
{
    void insert(unsigned id, const std::string& firstname, const std::string& lastname) {
        std::println("insert id={}, firstname={}, lastname={}", id, firstname, lastname);
    }
    void commit() {
        std::println("commit");
    }
    void rollback() {
        std::println("rollback");
    }
};

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;
    }
    rv = sigaction(SIGUSR1, &sa, nullptr);
    if (rv == -1) {
        perror("sigaction(SIGUSR1)");
        return 1;
    }
    rv = sigaction(SIGUSR2, &sa, nullptr);
    if (rv == -1) {
        perror("sigaction(SIGUSR2)");
        return 1;
    }
    
    static const std::regex re_line("^(\\d+)\\s+(\\w+)\\s+(\\w+)\\s*$");
    Database db;

    while (true) {                                     // <-- quit?
        char line[64];
        ssize_t nread = read(STDIN_FILENO,
                             line, sizeof(line)-1);
        if (nread == -1) {
            if (errno == EINTR) {
                if (quit)
                    break;
                else if (commit) {
                    db.commit();
                    commit = false;
                    continue;
                }
                else if (rollback) {
                    db.rollback();
                    rollback = false;
                    continue;
                }
                                                       // <-- and else?
            }
            else {
                perror("read");
                return 1;
            }
        }
        if (nread == 0)
            break;

        std::string sline(line, nread);
        std::smatch match;
        if (std::regex_search(sline, match, re_line))
            db.insert(std::stoi(match[1].str()), match[2].str(), match[3].str());
    }

    db.commit();

    return 0;
};