Как SIGWINCH проходит через Bash? - PullRequest
3 голосов
/ 03 августа 2020

Если я запустил программу в Bash, которая прослушивает SIGWINCH, и я изменю размер терминала, на котором работает Bash, тогда программа получит SIGWINCH. Я хотел бы знать, как этот сигнал передается в программу, работающую под Bash.

Вот мое понимание того, что происходит, используя образец catch_sig программы, который я перечисляю в конце этого сообщения:

  • Эмулятор терминала будет работать Bash за принимающей стороной PTY. Таким образом, «STDIN» и «STDOUT» для Bash будут TTY.
  • Bash запускает catch_sig как подпроцесс путем разветвления. Процесс catch_sig наследует FD Bash для ввода-вывода, которые являются упомянутыми выше TTY.
  • При изменении размера эмулятора терминала он должен вызвать ioctl(pty_fd, TIOCSWINSZ, &size), где pty_fd - отправляющий конец указанного выше PTY. Этот вызов ioctl обновит размер принимающего TTY и попытается отправить SIGWINCH группу процессов для TTY.
  • Bash и catch_sig являются частью указанной выше группы процессов, поэтому SIGWINCH отправляется им обоим по отдельности.

Однако одна проблема, с которой я столкнулся с вышеуказанным, заключается в том, что если я попытаюсь отправить SIGWINCH в группу процессов для Bash вручную с помощью kill, тогда catch_sig не получит сигнал. Например, если PID (и группа процессов) для Bash равен 123, и я запускаю в нем catch_sig, а затем запускаю kill -WINCH -123 в отдельной панели, то catch_sig не получает сигнал . Почему это так?

Ниже приведен исходный код демонстрационной программы catch_sig, как упоминалось выше:

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

static void sigwinch_handler(int sig) {
        printf("got signal: %d\n", sig);
}

int main() {
        signal(SIGWINCH, sigwinch_handler);
        printf("waiting for signal...\n");
        pause();
        return 0;
}

1 Ответ

3 голосов
/ 03 августа 2020

Например, если PID (и группа процессов) для Bash - 123, и я запускаю в нем catch_sig, а затем я запускаю kill -WINCH -123 в отдельной панели, тогда catch_sig не получает сигнал. Почему это так?

Когда Bash является интерактивным , каждое задание - переднее или фоновое - помещается в отдельную группу процессов, чтобы ими можно было управлять индивидуально. Например:

Терминал №1:

$ tty
/dev/pts/0
$ echo $$
123
$ ./catch_sig
waiting for signal...

Терминал №2:

$ ps -t /dev/pts/0 -o pid,pgid,stat,comm
  PID  PGID STAT COMMAND
  123   <b>123</b> S<s  bash
  124   <b>124</b> <b>S<+</b>  catch_sig

Знак плюс (+) в поле STAT означает, что процесс является членом группы процессов переднего плана, см. ps (1) .

Итак, когда вы изменяете размер окна терминала в то время как catch_sig выполняется на переднем плане (т.е. его группа процессов была сделана группой процессов переднего плана Bash и еще не завершена), SIGWINCH отправляется только группе процессов catch_sig. Затем Bash восстанавливает управление терминалом, когда catch_sig завершается.

Что можно воспроизвести с помощью kill, как показано ниже.

Терминал # 2:

$ kill -WINCH -124

Терминал # 1:

got signal: 28

Для получения дополнительной информации см. , как управление заданиями реализовано в оболочках POSIX .

...