Как правильно обрабатывать сигналы, чтобы профилировщик процессора gperftools все еще работал?

Я хочу профилировать мою программу-демон, которая приостанавливает основной поток:

sigset_t signal_mask;
sigemptyset(&signal_mask);
sigaddset(&signal_mask, SIGTERM);
sigaddset(&signal_mask, SIGINT);

int sig;
sigwait(&signal_mask, &sig);

Все остальные потоки просто блокируют все сигналы. Насколько я знаю, профилировщик использует SIGPROF сигнал для его операций. Если я начну профилирование с таким кодом, выходной файл.prof будет пустым:

env CPUPROFILE = daemon.prof./daemon

Как правильно обрабатывать сигналы в основном потоке и других потоках, чтобы включить профилирование? Или может проблема в другом?

2 ответа

Все остальные потоки просто блокируют все сигналы.

Вам просто нужно разблокировать SIGPROF во всех темах (или в тех, которые вы хотите профилировать). Мы просто решали точно такую ​​же проблему в многопоточном демоне.

Мне нужно увидеть больше вашего кода, но ваше заявление о том, что "все остальные потоки просто блокируют все сигналы" вызывает... сигналы.

Вы должны помнить, что большинство системных вызовов были созданы до того, как существовала концепция потоков. Обработка сигналов является одним из них. Таким образом, когда вы блокируете сигнал в ЛЮБОМ потоке, он, вероятно, блокируется для ВСЕХ потоков.

На самом деле, проверьте man-страницу signal(2):

The effects of signal() in a multithreaded process are unspecified.

Да, это печально, но это цена, которую вы должны заплатить за использование профилировщика статистической выборки с низкими издержками. И обойти это очень просто: просто удалите SIGPROF (или SIGALRM, если вы используете режим REAL) из своего набора маски сигналов, и все будет в порядке.

И вообще, если только вы не обязаны это делать, вы не должны выполнять маскирование сигналов на уровне процесса ни в чем, кроме основного потока... где "main" не обязательно означает поток, в котором выполняется MAIN(), но скорее, нить, которую вы считаете "боссом" всех остальных, по причинам, которые вы уже слишком ясно прояснили.:)

Вы также можете попробовать использовать оболочку sigmask библиотеки pthread pthread_sigmask, но мне неясно, насколько хорошо она работает в таких ситуациях, как дочерний поток, УДАЛЯЯ запись из сигма-маски (pthreads наследуют сигма-маску pthread своего родителя).

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