Linux C ловит сигнал об улавливании для изящного завершения
У меня есть процесс, использующий сокеты, соединения с базой данных и подобные. Это, в основном, серверный процесс, передающий данные датчика и веб-интерфейс, и поэтому важно обеспечить, чтобы приложение, если оно было убито, прекратило изящество.
Как обрабатывать неожиданные исключения, такие как segfaults (по крайней мере для отладки), а также убивать сигналы, чтобы я мог закрыть любые подключения и остановить любые потоки, чтобы процесс не оставил беспорядка ничем, что он использует?
Ответы
Ответ 1
Вы устанавливаете обработчики сигналов для улавливания сигналов, однако в 99% случаев вы просто хотите выйти и позволить ОС Linux заботиться о очистке - он будет успешно закрывать все файлы, сокеты, свободные потоки памяти и завершения работы.
Итак, если вы не хотите что-то конкретно сделать, например отправить сообщение в сокеты, вам нужно просто выйти из процесса и не пытаться поймать сигнал.
Ответ 2
Сигналы поймать трудно. Ты должен быть осторожен. Ваш первый шаг - использовать sigaction
для установки обработчика сигналов для желаемых сигналов.
-
Выберите набор сигналов для ответа и выберите, что они означают для вашего процесса. Например, SIGTERM
завершает работу, SIGHUP
перезагружается, SIGUSR1
перезагружает конфигурацию и т.д.
-
Не пытайтесь реагировать на все сигналы и не пытайтесь "очистить" после сигнала, который указывает на ошибку в вашей программе. SIGKILL
невозможно поймать. SIGSEGV
, SIGBUS
, и другие, подобные им, не должны быть пойманы, если у вас нет ОЧЕНЬ хорошей причины. Если вы хотите отлаживать, то поднимите ulimit для дампов ядра - добавление отладчика к основному изображению намного эффективнее, чем все, что вы или я когда-либо могли бы кодировать. (Если вы попытаетесь очистить после SIGSEGV
или что-то в этом роде, поймите, что код очистки может вызвать дополнительный SIGSEGV
, и ситуация может быстро ухудшиться. Просто избегайте всего беспорядка и пусть SIGSEGV
завершает вашу программу.)
-
Как вы обрабатываете сигналы, сложно. Если ваше приложение имеет основной цикл (например, select
или poll
), тогда обработчик сигнала может просто установить флаг или записать байт в специальный канал, чтобы сигнализировать о выходе основного цикла. Вы также можете использовать siglongjmp
, чтобы выскочить из обработчика сигнала, но это ОЧЕНЬ трудно получить правильно и обычно не то, что вы хотите.
Трудно рекомендовать что-то, не зная, как структурировано ваше приложение и что оно делает.
Также помните, что обработчик сигнала сам должен делать почти ничего. Многие функции небезопасны для вызова из обработчиков сигналов.
Ответ 3
Мне иногда нравится получать обратную трассировку на SIGSEGV, увлекательная часть выглядит следующим образом:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void sig_handler(int);
int main() {
signal(SIGSEGV, sig_handler);
int *p = NULL;
return *p;
}
void sig_handler(int sig) {
switch (sig) {
case SIGSEGV:
fprintf(stderr, "give out a backtrace or something...\n");
abort();
default:
fprintf(stderr, "wasn't expecting that!\n");
abort();
}
}
Вы хотите быть очень осторожным в отношении этих вещей, например. убедитесь, что вы не можете вызвать другой сигнал.