`SIGWINCH` 如何通过 Bash?

Sea*_*her 4 linux bash signals tty pty

如果我击运行一个程序,用于监听SIGWINCH,和我调整的是击在运行终端,然后程序会收到SIGWINCH。我想知道这个信号是如何传递给在 Bash 下运行的程序的。

这是我对发生的事情的理解,使用catch_sig我在本文末尾列出的示例程序:

  • 终端模拟器将在 PTY 的接收端后面运行 Bash。因此,Bash 的“STDIN”和“STDOUT”将是 TTY。
  • Bashcatch_sig通过分叉作为子进程运行。该catch_sig进程继承了 Bash 的 I/O FD,也就是上面提到的 TTY。
  • 当终端仿真器的大小发生变化时,它应该调用ioctl(pty_fd, TIOCSWINSZ, &size)pty_fd上面的 PTY 的发送端在哪里。此调用ioctl将更新接收 TTY 的大小,并将尝试发送SIGWINCHTTY 的进程组。
  • Bash 和catch_sig是上述进程组的一部分,因此分别SIGWINCH发送给他们两个。

然而,我在上面遇到的一个困难是,如果我尝试SIGWINCH手动发送到 Bash 的进程组,killcatch_sig不会收到信号。例如,如果 Bash 的 PID(和进程组)是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;
}
Run Code Online (Sandbox Code Playgroud)

ogu*_*ail 5

例如,如果 Bash 的 PID(和进程组)是123并且我catch_sig在其中运行,然后我kill -WINCH -123在单独的窗格中运行,则catch_sig不会收到信号。为什么会这样?

终端只发送SIGWINCH给前台(即控制)进程组。当 Bash 是交互式的时,每个作业——前台或后台——都被放置在一个单独的进程组中,前台作业被临时授予终端的控制权。例如:

1号航站楼:

$ tty
/dev/pts/0
$ echo $$
123
$ ./catch_sig
waiting for signal...
Run Code Online (Sandbox Code Playgroud)

2 号航站楼:

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

字段中的加号 ( +)STAT表示该进程是前台进程组的成员,请参阅ps(1)

因此,当您catch_sig在前台运行时调整终端窗口的大小(即它的进程组被 Bash 设置为前台进程组,并且尚未完成),只会SIGWINCH发送到其catch_sig进程组。然后 Bash 在catch_sig终止时重新获得对终端的控制。

可以使用kill如下所示进行复制。

2 号航站楼:

$ kill -WINCH -124
Run Code Online (Sandbox Code Playgroud)

1号航站楼:

got signal: 28
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅如何在 POSIX shell 中实现作业控制