on_exit и CTRL + C - PullRequest
       12

on_exit и CTRL + C

1 голос
/ 03 апреля 2012

У меня есть небольшая программа, которая открывает файл и выполняет с ним некоторые операции. Я подписал закрытие файла на завершение программы следующим образом:

static
void exit_handler (int ev, void *arg)
{
    fprintf(stderr, "bye %d\n", WEXITSTATUS(ev));
    fclose((FILE *)arg);
}

int main (int argc, char *argv[])
{
    FILE *out;

    ...

    out = fopen(argv[1], "wt");
    if (out == NULL) {
        perror("Opening output file");
        exit(EXIT_FAILURE);
    }
    on_exit(exit_handler, out);

    ...
}

Пытаясь выполнить это, я замечаю, что он работает правильно, только если программа нормально завершается. В случае CTRL + C (SIGINT) обратный вызов exit_handler не выполняется.

Разве это не странно? Должен ли я связать exit(EXIT_FAILURE) вызов с обработчиком сигнала для SIGTERM? Какова лучшая практика в этом случае?

Ответы [ 4 ]

4 голосов
/ 03 апреля 2012

Прежде всего, on_exit не определено POSIX (atexit с той же семантикой). Во-вторых, руководство по Linux говорит:

Функция on_exit () регистрирует данную функцию для вызова при нормальном завершении процесса , либо через выход (3), либо через возврат из основная программа ().

Убийство сигналом не является нормальным выходом для процесса, поэтому обратные вызовы, установленные с on_exit и atexit, не вызываются неявно.

3 голосов
/ 03 апреля 2012

Нет, а на самом деле то, что вы хотите, невозможно.Сигнал, генерируемый Ctrl + C, является асинхронным , что означает, что он может возникать между любыми двумя машинными инструкциями в вашей программе в зависимости от нажатия Ctrl + C.Таким образом, если ваша программа полностью не избегает вызова асинхронных небезопасных функций где-либо в основном потоке программы, незаконно вызывать асинхронные небезопасные функции из обработчика сигнала.exit является async-signal-unsafe, как и большинство операций по очистке по умолчанию, которые он выполняет (например, очистка / закрытие открытых файлов).Я ожидаю, что функция atexit, которую вы хотите зарегистрировать (atexit, а не on_exit, правильное имя для этой функции), также захочет делать небезопасные асинхронные сигналы действия.

Если вам нужно выполнить очистку при выходе на основе сигнала, вам нужно установить обработчик сигнала, который не exit сам по себе, а вместо этого устанавливает глобальный флаг изменчивости, который будет проверяться вашим основным потоком программы (и exit, если онправда).

3 голосов
/ 03 апреля 2012

on_exit не будет вызываться для сигналов SIGTERM. Вам нужно добавить обработчик для этого с signal. Например:

void signalHandler(void)
{
  ...
}

int main(void)
{
  signal(SIGTERM, signalHandler);
}

Также обратите внимание, что SIGKILL не может быть пойман с помощью дизайна.

2 голосов
/ 03 апреля 2012

из справочная страница из on_exit,

Функция on_exit () регистрирует данную функцию, которая вызывается при нормальном завершении процесса, будь то через exit (3) иличерез возврат из main () программы.

Таким образом, вам нужно подробно подключить обработчик для SIGTERM, используя специальные функции из signal.h

Что-то на линии

struct sigaction action;

memset (&action, 0, sizeof(action));
action.sa_handler = sigterm_handler;

if (sigaction(SIGTERM, &action, 0)) 
{
    perror ("sigaction");
    return 1;
}

/* SIGTERM handler. */
static void sigterm_handler (int sig)
{
...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...