pgid в обработчике сигналов отличается от реального pgid
У меня есть следующая простая программа, которая устанавливает pgid и pgroup основной программы для STDIN. Затем у меня есть обработчик сигнала, который печатает pgid текущего процесса и pgid процесса, из которого отправляется сигнал. Вот мой код
pid_t pid;
void handler(int signum, siginfo_t* siginfo, void* context){
printf("pgid is %d, shell_pgid is %d \n", getpgid(siginfo->si_pid), pid);
}
int main()
{
struct sigaction sa;
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGINT, &sa, NULL);
pid = getpid();
setpgid(pid, pid);
tcsetpgrp(STDIN_FILENO, pid);
while(1){
}
}
Однако, когда я нажимаю ^C, я получаю вывод
^Cpgid is 335, shell_pgid is 3924
Разве они не должны быть одинаковыми, так как программа работает в основной программе и сигнал также отправляется из того же источника?
1 ответ
Я думаю, вы можете быть немного озадачены тем, как работают идентификаторы группы процессов.
Во-первых, я убрал ваш источник:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
pid_t pid;
void
handler (int signum, siginfo_t * siginfo, void *context)
{
printf ("in signal handler pid is %d, getpgid(pid) is %d \n",
pid, getpgid (pid));
printf
("in signal handler siginfo->si_pid is %d, getpgid(siginfo->si_pid) is %d \n",
siginfo->si_pid, getpgid (siginfo->si_pid));
exit (0);
}
int
main (int argc, char **argv)
{
struct sigaction sa;
memset (&sa, 0, sizeof (sa));
sa.sa_sigaction = handler;
sigemptyset (&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO;
sigaction (SIGINT, &sa, NULL);
pid = getpid ();
printf ("before call pgid is %d pid=%d\n", getpgid (pid), pid);
setpgid (pid, pid);
printf ("after setpgid call pgid is %d pid=%d\n", getpgid (pid), pid);
tcsetpgrp (STDIN_FILENO, pid);
printf ("after tcsetprgrp call pgid is %d pid=%d\n", getpgid (pid), pid);
while (1)
{
}
}
Основное изменение заключается в том, что если ваш обработчик принимает три параметра, вам нужно использовать SA_SIGINFO
и укажите обработчик в sa_sigaction
не sa_handler
, Без этого ваш обработчик может получить недопустимые второй и третий аргументы.
Затем я исправил ваш обработчик, чтобы он распечатал si_pid
так же как pid
,
Я также добавил некоторую дополнительную отладку.
Вот что происходит, когда я бегу прямо из оболочки:
$ ./x
before call pgid is 15136 pid=15136
after setpgid call pgid is 15136 pid=15136
after tcsetprgrp call pgid is 15136 pid=15136
^Cin signal handler pid is 15136, getpgid(pid) is 15136
in signal handler siginfo->si_pid is 0, getpgid(siginfo->si_pid) is 15136
Обратите внимание, что siginfo->si_pid
сообщает как 0, потому что si_pid
заполняется только сигналами, отправленными через kill
, Это означает, что 0 передается getpgid()
который возвращает PGID
вызывающего процесса, что неудивительно, что getpgid(pid)
вернулся на предыдущую строку.
Вот что произойдет, если я убью его kill -SIGINT
из другого процесса, а не нажав ^C
,
$ ./x
before call pgid is 15165 pid=15165
after setpgid call pgid is 15165 pid=15165
after tcsetprgrp call pgid is 15165 pid=15165
in signal handler pid is 15165, getpgid(pid) is 15165
in signal handler siginfo->si_pid is 14858, getpgid(siginfo->si_pid) is 14858
Как вы можете видеть, последняя строка сообщает PID процесса, отправляющего kill
,
В обоих приведенных выше примерах PGID
уже равен PID
когда процесс запущен. Это почему? Итак, мы запустили одну команду из командной строки, поэтому есть одна группа процессов (только), поэтому PGID
всегда будет PID
,
Так что же произойдет, если мы запустим группу процессов, где мы не первый процесс? Попробуй это:
$ echo | ./x
before call pgid is 15173 pid=15174
after setpgid call pgid is 15174 pid=15174
after tcsetprgrp call pgid is 15174 pid=15174
in signal handler pid is 15174, getpgid(pid) is 15174
in signal handler siginfo->si_pid is 14858, getpgid(siginfo->si_pid) is 14858
Обратите внимание, что мне пришлось убить с kill -SIGINT
потому что ^C
переходит к группе процессов, которая есть (после PGID
изменено) только echo
, Итак PGID
на входе 15173
(ПИД echo
) но меняется, чтобы быть 15174
(как вы просили).
Я думаю, что все работает, как ожидалось.
Я думаю, что проблема у вас в основном в вашем обработчике сигналов. Во-первых, вы, кажется, ожидаете si_pid
быть заполненным. Во-вторых, ваш printf
говорит, что вы печатаете pgid
а также shell_pgid
(два PGID
с, а на самом деле вы печатаете PGID
процесса выдачи уничтожения (или если нет результата getpgid(0)
какой PGID
вызывающего процесса), затем PID процесса, т.е. PID
и PGID
, И также я подозреваю, что неправильная установка обработчика может дать вам ненужный второй параметр в любом случае.