при выключении linux systemd отправляет несколько сигналов sigterm моему приложению - PullRequest
0 голосов
/ 07 апреля 2020

Я установил обработчик сигнала, как показано ниже на c ++, для приложения, предназначенного для работы на linux:

Установите обработчик сигнала для вызова функции stati c:

// Setup the SIGNTERM signal handler for kill/pkill or systemd terminate
if (signal(SIGTERM, manager_signal_handler) == SIG_ERR)
{
    ERROR << "Failed to add signal SIGTERM to signal handler with error code: " << std::strerror(errno) << ENDL;
}

Обработчик сигнала stati c - который вызывает функцию-член экземпляра класса

static dds_manager_base *p_this_dds_manager_base = nullptr;
static void dds_manager_signal_handler(int signum)
{
    if (p_this_manager_base)
    {
        DEBUG << "static manager_signal_handler calling: p_this_manager_base->signal_handler\n";
        p_this_manager_base->signal_handler(signum);
    }
    else
    {
        ERROR << "manager_signal_handler - manager pointer not set\n";
    }
}

Функция-член - обрабатывает сигнал:

void dds_manager_base::signal_handler(int signum)
{
    DEBUG << "dds_manager_base::signal_handler - received signal: " << signum << ENDL;
    // Termination actions - can take 5-10 seconds...
}

Я использую sytemctnl powerdown до отключения linux (что останавливает службу, в которой запущено мое приложение). Я заметил, что мое приложение получает 2 или даже 3 сигнала SIGTERM с интервалом около 500 мс.

Я могу справиться с этой ситуацией, но я ожидал, что 1 SIGTERM, за которым следует SIGABRT, может быть, через 90 секунд, если мое приложение не завершается в течение этого срока.

Моя проблема в том, что, как только я обрабатываю сигнал, в некоторых случаях мое приложение завершается достаточно быстро, чтобы мой класс больше не существовал, и я получаю дамп ядра, потому что signal_handler () функции больше нет Таким образом, у меня была идея вернуть сигнал на default behaviour signal(SIGTERM, SIG_DFL);, как только я обработал сигнал - но поскольку systemd вызывает SIGTERM более одного раза при втором вызове, std::exit() (я полагаю, что это поведение по умолчанию) вызывается и завершается мое приложение, прежде чем оно сможет корректно завершить работу.

Вот мой файл службы / модуля:

[Unit]
Description=Invoke script to start the corvus application
After = network.target mnt-appdata.mount

[Service]
Type=idle
ExecStart=/mnt/appdata/deploy/services/start_module.sh ${SYS_NUM} ${DDS_NUM}

[Install]
WantedBy=multi-user.target

Вы можете видеть, что скрипт start_module.sh является вызовом - это то, что затем запускает мое приложение выполнив: ./my-application &

Итак, мои вопросы: - Почему я получаю более одного SIGTERM и так близко друг к другу? - Что я могу сделать, чтобы решить эту проблему?

1 Ответ

1 голос
/ 07 апреля 2020

Что я заметил, так это то, что мое приложение получает 2 или даже 3 SIGTERM сигналы на расстоянии около 500 мс.

Это не поведение systemd, вы можете проверить ваши наблюдения.

См. man systemd.kill для получения полной информации:

   KillMode=

Указывает, как процессы этой единицы должны быть убиты. Один из контрольной группы, процесс, смешанный, нет.

Если установлено значение control-group, все остальные процессы в контрольной группе этого устройства будут остановлены при остановке устройства (для служб: после выполнения команды останова, как сконфигурировано с ExecStop =). Если задано значение process, уничтожается только основной процесс. Если установлено значение смешанный, сигнал SIGTERM (см. Ниже) отправляется в основной процесс, а последующий сигнал SIGKILL (см. Ниже) отправляется во все остальные процессы группы управления устройства. Если установлено значение none, ни один процесс не прекращается. В этом случае при остановке устройства будет выполнена только команда останова, но в противном случае процесс не будет остановлен. Процессы, остающиеся живыми после остановки, остаются в их контрольной группе, и контрольная группа продолжает существовать после остановки, если она не пуста.

Сначала процессы будут завершаться через SIGTERM (если только сигнал для отправки не изменен через KillSignal =). Опционально, сразу за ним следует SIGHUP (если включено с SendSIGHUP =). Если затем, после задержки (настроенной с помощью опции TimeoutStopSec =), процессы все еще остаются, запрос завершения повторяется с сигналом SIGKILL (если только это не отключено с помощью опции SendSIGKILL =). Смотрите kill (2) для получения дополнительной информации.

По умолчанию используется контрольная группа.

...