Есть ли способ проверить, нахожусь ли я в обработчике сигналов?

Мне приходится работать над модулем регистрации, который можно вызывать из разных мест большого проекта. У меня проблема в том, что иногда модуль может вызываться из кода, выполняемого внутри обработчика сигнала. Обычно модуль регистрации включает данные о времени, используя 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? Я не знаю, как ведет себя эта функция во время обработки сигнала. Однако, если он возвращает установленный флаг, вы можете быть пессимистичными и пропустить асинхронные небезопасные вызовы, если ожидают какие-либо сигналы.

Другие вопросы по тегам