`SIGWINCH` 是如何通过 Bash 的?
How does `SIGWINCH` pass through Bash?
如果我 运行 Bash 中的一个程序侦听 SIGWINCH
,并且我调整 Bash 正在 运行 的终端的大小,然后该程序将收到 SIGWINCH
。我想知道这个信号是如何中继到 Bash.
下的程序 运行ning 的
这是我对所发生情况的理解,使用我在本文末尾列出的示例 catch_sig
程序 post:
- 终端仿真器会运行Bash后面一个PTY的接收端。因此,Bash 的“STDIN”和“STDOUT”将是 TTY。
- Bash 运行s
catch_sig
作为分叉的子进程。 catch_sig
进程继承了Bash的I/O的FD,也就是上面提到的TTY。
- 当终端仿真器的大小改变时,应该调用
ioctl(pty_fd, TIOCSWINSZ, &size)
,其中pty_fd
是上述PTY的发送端。此调用 ioctl
将更新接收 TTY 的大小,并将尝试发送 SIGWINCH
TTY 的进程组。
- Bash 和
catch_sig
是上述进程组的一部分,因此 SIGWINCH
会分别发送给它们。
然而,我在上面遇到的一个困难是,如果我尝试使用 kill
手动将 SIGWINCH
发送到 Bash 的进程组,那么 catch_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;
}
For example, if the PID (and process group) for Bash is 123
and I run catch_sig
in it, and then I run kill -WINCH -123
in a separate pane, then catch_sig
doesn't receive the signal. Why is this this the case?
终端仅向前台(即控制)进程组发送SIGWINCH
。当 Bash 为 interactive 时,每个作业(前台或后台)都被放置在一个单独的进程组中,前台作业暂时获得终端的控制权。例如:
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)。
因此,当您调整终端 window 的大小时,而 catch_sig
在前台 运行(即它的进程组被 Bash 设为前台进程组),而且还没有完成),SIGWINCH
只发送到 catch_sig
的进程组。然后 Bash 在 catch_sig
终止时重新获得终端的控制权。
可以使用 kill
复制,如下所示。
2 号航站楼:
$ kill -WINCH -124
1 号航站楼:
got signal: 28
有关详细信息,请参阅 how job control is implemented in POSIX shells。
如果我 运行 Bash 中的一个程序侦听 SIGWINCH
,并且我调整 Bash 正在 运行 的终端的大小,然后该程序将收到 SIGWINCH
。我想知道这个信号是如何中继到 Bash.
这是我对所发生情况的理解,使用我在本文末尾列出的示例 catch_sig
程序 post:
- 终端仿真器会运行Bash后面一个PTY的接收端。因此,Bash 的“STDIN”和“STDOUT”将是 TTY。
- Bash 运行s
catch_sig
作为分叉的子进程。catch_sig
进程继承了Bash的I/O的FD,也就是上面提到的TTY。 - 当终端仿真器的大小改变时,应该调用
ioctl(pty_fd, TIOCSWINSZ, &size)
,其中pty_fd
是上述PTY的发送端。此调用ioctl
将更新接收 TTY 的大小,并将尝试发送SIGWINCH
TTY 的进程组。 - Bash 和
catch_sig
是上述进程组的一部分,因此SIGWINCH
会分别发送给它们。
然而,我在上面遇到的一个困难是,如果我尝试使用 kill
手动将 SIGWINCH
发送到 Bash 的进程组,那么 catch_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;
}
For example, if the PID (and process group) for Bash is
123
and I runcatch_sig
in it, and then I runkill -WINCH -123
in a separate pane, thencatch_sig
doesn't receive the signal. Why is this this the case?
终端仅向前台(即控制)进程组发送SIGWINCH
。当 Bash 为 interactive 时,每个作业(前台或后台)都被放置在一个单独的进程组中,前台作业暂时获得终端的控制权。例如:
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)。
因此,当您调整终端 window 的大小时,而 catch_sig
在前台 运行(即它的进程组被 Bash 设为前台进程组),而且还没有完成),SIGWINCH
只发送到 catch_sig
的进程组。然后 Bash 在 catch_sig
终止时重新获得终端的控制权。
可以使用 kill
复制,如下所示。
2 号航站楼:
$ kill -WINCH -124
1 号航站楼:
got signal: 28
有关详细信息,请参阅 how job control is implemented in POSIX shells。