systemd m'a tuer

Top Page

Reply to this message
Author: Edgar Bonet
Date:  
To: guilde
Subject: systemd m'a tuer
Bonjour la Guilde !

J'ai une question sur la façon dont systemd tue les processus lors d'un
shutdown, et sur la façon de contrôler ça.

Pour le contexte : je travaille sur un code de simulation pour des
calculs lourds qui peuvent durer plusieurs jours. La machine qui héberge
le processus sera dans un rack muni d'un système de climatisation qui
n'est pas super-fiable. La personne responsable de ce rack a prévu
d'installer un petit démon qui surveille la température de la machine
et, en cas de surchauffe, fait un « poweroff ». J'aimerais faire en
sorte que, dans un telle situation, mon programme sauvegarde sur disque
l'état du calcul avant de se terminer.

Mon idée était que, lors de l'arrêt du système, systemd devait envoyer
SIGTERM à tous les processus, puis leur laisser un petit répit, puis
envoyer SIGKILL à ceux qui seraient encore là. Je n'aurais donc qu'à
intercepter SIGTERM pour savoir quand il faut sauvegarder l'état et se
terminer proprement. J'ai écrit le petit programme ci-joint pour tester
cette idée et... ça ne marche pas ! Je lance le programme en arrière
plan et :

- si je lui envoie moi même SIGTERM (avec kill), il enregistre bien le
message dans le fichier de sortie avant de quitter

- si au lieu de ça je fais « sudo poweroff », il n'y a rien dans le
fichier de sortie.

Testé sur une Ubuntu 20.04. J'imagine donc que systemd n'a pas la
gentillesse d'envoyer SIGTERM avant de tuer tous les processus. :-(

Est-ce que j'ai pas compris quelque chose ? La séquence (SIGTERM, répit,
SIGKILL) n'est-elle pas depuis longtemps la façon standard de tout
arrêter sur un système Unix ? Est-ce que ce comportement est
configurable ? Tout ce que j'ai trouvé dans mes recherches concerne la
façon dont systemd tue les services dont il est responsable, ce qui
n'est pas le cas de ce programme de calcul.

Merci de votre attention,

Edgar./*
* Test handling of SIGTERM. Intended to test whether poweroff(8)
* sends SIGTERM before sending SIGKILL.
*
* Build:
* gcc -O -Wall -Wextra record-sigterm.c -o record-sigterm
*
* Usage:
* record-sigterm [output-file]
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <unistd.h>

static volatile sig_atomic_t should_quit = 0;

static void sigterm_handler(int signum)
{
    (void) signum;
    should_quit = 1;
}


int main(int argc, char *argv[])
{
    /* Open the log file. */
    FILE *out;
    if (argc > 1) {
        out = fopen(argv[1], "w");
        if (!out) {
            perror(argv[1]);
            return EXIT_FAILURE;
        }
    } else {
        out = stdout;
    }


    /* Catch SIGTERM. */
    struct sigaction action = {
        .sa_handler = sigterm_handler,
        .sa_flags = 0
    };
    sigemptyset(&action.sa_mask);
    if (sigaction(SIGTERM, &action, NULL) == -1) {
        perror("SIGTERM");
        return EXIT_FAILURE;
    }


    /* Wait for SIGTERM. */
    printf("PID = %d\n", getpid());
    while (!should_quit)
        usleep(100000);


    /* Record termination. */
    time_t now = time(NULL);
    char time_buf[24];
    strftime(time_buf, sizeof time_buf, "%F %T", localtime(&now));
    fprintf(out, "%s: received SIGTERM, terminating\n", time_buf);
}