Есть ли способ проверить, нахожусь ли я в обработчике сигналов?
Мне приходится работать над модулем регистрации, который можно вызывать из разных мест большого проекта. У меня проблема в том, что иногда модуль может вызываться из кода, выполняемого внутри обработчика сигнала. Обычно модуль регистрации включает данные о времени, используя localtime() и strftime(), но, конечно, эти вызовы не являются безопасными для асинхронного сигнала и могут вызывать взаимные блокировки, если вызваны из обработчика сигнала. Есть ли способ (в системе GNU/Linux) сказать, выполняется ли мой код в настоящее время в контексте обработчика сигнала, кроме, например, установки каждого обработчика сигнала во время обработки? Я думаю, что было бы лучше упростить наши обработчики сигналов, но в этом случае у меня нет выбора относительно того, где может быть вызван модуль регистрации. Было бы хорошо, если бы я мог протестировать и просто опустить информацию о временной метке, если модуль вызывается во время обработки сигнала.
3 ответа
Прежде всего, ваш вопрос ("Я в обработчике сигналов?") Не имеет четко определенного ответа. Рассмотрим следующий код:
#include <setjmp.h>
#include <signal.h>
jmp_buf jb;
int foo(int s)
{
longjmp(jb,1);
}
int main()
{
if (setjmp(jb)) {
puts("Am I in a signal handler now, or not?");
return 0;
}
signal(SIGINT, foo);
raise(SIGINT);
}
С учетом вышесказанного, существует методика, которую вы можете использовать, чтобы ответить на этот вопрос значимым образом для многих программ. Выберите сигнал, который вы не собираетесь использовать, и добавьте его в sa_mask
для всех обрабатываемых вами сигналов установка обработчиков сигналов с использованием sigaction
, Тогда вы можете использовать sigprocmask
чтобы проверить текущую маску сигнала, и если назначенный вами сигнал находится в маске сигнала, это означает, что обработчик сигнала был вызван и еще не возвращен (возврат приведет к восстановлению исходной маски сигнала).
Самый простой способ - войти через (именованный) канал (записи в PIPE_MAX являются атомарными) или через сокет UDP (то же самое). Источник сообщения может быть установлен функцией, генерирующей сообщение. Конечно, вам понадобится процесс, который на самом деле читает и обрабатывает сообщения, но его можно оставить вне контекста обработчика сигнала.
Кстати: вам не нужен отдельный процесс для получения сообщений, вы можете отправить сообщения своему собственному процессу и добавить (конец чтения) канал к fd_set (если ваша программа находится в цикле выбора или опроса), или периодически опрашивать.
Есть ли в вашей системе sigpending
? Я не знаю, как ведет себя эта функция во время обработки сигнала. Однако, если он возвращает установленный флаг, вы можете быть пессимистичными и пропустить асинхронные небезопасные вызовы, если ожидают какие-либо сигналы.