Сигналы не включаются должным образом через execv () - PullRequest
3 голосов
/ 21 июня 2009

Я пишу критическую для системы программу для разрабатываемого дистрибутива Linux. Он должен перезагрузить себя при получении определенных сигналов, чтобы попытаться избежать сбоя. Проблема в том, что после перезапуска я не могу повторно включить этот сигнал. То есть сигнал не может быть получен дважды. После выполнения execv (), когда новый процесс вызывает signal () для установки сигнала, возвращается SIG_DFL. Каждый раз. Даже если я вызываю его дважды подряд - это указывает на то, что он никогда не был установлен в первую очередь. Некий ли странный флаг перенесен из исходного процесса?

Ответы [ 2 ]

9 голосов
/ 22 июня 2009

Вы недовольны тем фактом, что пытаетесь рекурсивно обработать сигнал.

При использовании signal() для регистрации обработчика сигнала этот номер сигнала блокируется до тех пор, пока не будет возвращен обработчик сигнала - фактически ядро ​​/ libc блокирует этот номер сигнала при вызове обработчика сигнала и разблокирует его после возврата обработчика сигнала. , Поскольку вы никогда не возвращаетесь из обработчика сигнала (вместо этого вы execl новый двоичный файл), SIGUSR1 остается заблокированным и поэтому не перехватывается во второй раз.

Это можно увидеть, изучив /proc/</pid>/status до и после отправки первого SIGUSR1.

До:

$ cat /proc/<pid>/status | grep -E "Sig(Cgt|Blk)"
SigBlk: 0000000000000000
SigCgt: 0000000000000200

После того, как:

$ cat /proc/<pid>/status | grep -E "Sig(Cgt|Blk)"
SigBlk: 0000000000000200
SigCgt: 0000000000000200

Обратите внимание, что SigCgt указывает, что сигнал 10 зарегистрирован (число является битовым полем; установлен 10-й бит, что соответствует SIGUSR1, цифры * см. man signal(7)). SigBlk пусто до того, как SIGUSR отправлено вашему процессу, но после отправки сигнала оно содержит SIGUSR1.

У вас есть два способа решить эту проблему:

а). Вручную разблокируйте SIGUSR перед вызовом execl в sighandler:

sigset_t sigs;
sigprocmask(0, 0, &sigs);
sigdelset(&sigs, SIGUSR1);
sigprocmask(SIG_SETMASK, &sigs);
* +1032 * б). Используйте sigaction с флагом SA_NODEFER вместо signal для регистрации обработчика сигнала. Это предотвратит блокировку SIGUSR1 внутри обработчика сигнала:
struct sigaction act;
act.sa_handler = signalhandler;
act.sa_mask = 0;
act.sa_flags = SA_NODEFER;
sigaction(SIGUSR1, &act, 0);
1 голос
/ 21 июня 2009

Обработчики сигналов не наследуются через exec, потому что exec перезаписывает все ваше адресное пространство, и любые обработчики сигналов, которые не сбрасываются, будут указывать на неправильное место.Единственный раз, когда он не сбрасывается, это если он установлен, скажем, SIG_IGN, что не зависит от адресного пространства процесса до exec.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...