Sigwire:Linux 信号实时切换终端工具
速览
Sigwire 是一个运行在终端中的实时信号交换机(TUI),用于捕获和转发 Linux 系统上的各种信号。它提供可视化的界面让用户轻松管理进程信号,适用于调试和系统监控场景。该工具开源免费,面向开发者。
AI 深度解读
背景
在 Linux 系统中,信号(signal)是进程间通信和内核通知的基本机制。无论是用户按 Ctrl-C 发送 SIGINT,还是内核因段错误发送 SIGSEGV,抑或是 systemd 发送 SIGTERM 终止服务,信号无处不在。然而,调试信号相关的问题一直非常困难:传统工具如 strace 只能跟踪单个进程,ptrace 会引入性能开销且被跟踪进程能感知到,而系统级信号流(谁发送、谁接收、是否被捕获、是否中断了阻塞系统调用)几乎不可见。
Sigwire 正是为了解决这一痛点而生——它通过挂钩内核信号跟踪点(tracepoints),将整个系统的信号活动实时流式传输到终端,形成一个动态的“信号配线盘”(patchbay),让开发者能像 tail -f 一样观察所有信号。
核心内容
Sigwire 是一个运行在终端中的实时 TUI(文本用户界面)工具,它利用 Linux 内核的 BPF(Berkeley Packet Filter)机制,挂钩 signal:signal_generate 和 signal:signal_deliver 两个跟踪点,以及 rt_sigreturn(2) 和系统调用退出跟踪点,捕获每个信号从生成到传递的完整生命周期。与 strace -f 或 ptrace 不同,Sigwire 不绑定任何进程,被跟踪的进程完全不知情,且无额外 ptrace 开销。
安装与运行
一次安装守护进程(yeet daemon):
curl -fsSL https://yeet.cx | sh # 安装 yeet daemon(一次性)
yeet run github:yeet-src/sigwire # 运行仪表盘(守护进程负责加载有特权的 BPF 程序)
仅支持 Linux。无需任何配置——系统上恒有信号流量,启动后立即开始滚动。
界面与交互
默认视图按时间倒序显示最新信号,每一行代表一个生成的信号,格式如下:
| 时间 | 发送方 | 信号 | 接收方 | 备注 | |------|--------|------|--------|------| | now | bash·4402──SIGINT───▶ | node·8813 | kill(2) ↯ EINTR read caught 41µs | | 1.2s | systemd·1──────SIGTERM──▶ | nginx·1291 | kill(2) caught 1.2ms | | 3.4s | kernel·8813──SIGSEGV──▶ | chrome·8813 | fault default ☠ | | 4.1s | postgres·507──SIGUSR1───▶ | postgres·509 ×6 | kill(2) caught 9µs |
- 发送方/接收方:格式为
comm·pid,发送方是生成信号的主体(当前进程),接收方是目标进程。 - 信号线:信号名称按严重性着色(256 色),颜色映射与 UI 其余部分一致。
- ×N:当同一信号在短时间内被重复发送时折叠为一行,显示倍数。
- 备注:包含信号来源(
kill(2)、tgkill、sigqueue、timer、kernel、fault)以及是否中断了阻塞系统调用(↯ EINTR read,或↺ restarted read若设置了SA_RESTART),然后是处置方式:caught 41µs:用户态处理程序运行了,并显示耗时。default:无处理程序,执行默认动作。⊘ ignored:被忽略。
- ☠:标记真正的致命信号(见下方致命计数规则)。
每一行在传递结果确定后冻结,永不改变,因此突发信号流稳定滚动,不会闪烁。
右侧边栏(聚合视图)
默认显示按流量排序的顶部信号、来源分类、传递统计(捕获 vs 默认 vs 忽略)。按 ↑/↓(或 p)冻结滚动并选中一行时,边栏变为详情面板,显示该信号的所有已知信息:
- 信号编号与名称
- 发送方/接收方详情
- 生成方式(
tgkill、SI_TKILL、作用域等) - 传递结果(
handled caught、default等) - 系统调用中断详情(如
EINTR ← read) - 处理程序地址(如
0x55f0a1c3)及运行时长(ran 3.0ms) sigaction标志(SA_SIGINFO、SA_RESTART、SA_NODEFER等)- 目标进程在传递时刻的信号屏蔽字(
sigprocmask)
按 Esc 关闭详情,按 p 恢复实时滚动。
信号过滤(静音功能)
三个信号被认为是背景噪音:SIGCHLD(子进程回收)、SIGURG(Go 的异步抢占心跳)、SIGWINCH(终端窗口大小变化,广播给所有前台进程)。Sigwire 默认将它们静音,但用户可以自定义。
按 s 打开信号选择器:模态列表显示每个信号及其当前严重性颜色和已见数量,每个信号可切换为“显示”或“静音”。用方向键选择(或直接输入数字跳转,如 1、5 跳到 15),按空格切换。按 a 全选/全取消。标题栏会显示当前静音数量。
静音掩码是一个 __u64 全局变量,位于运行中的 BPF 程序的 .data 段内。切换时通过 DataSec.patch() 即时修改对应位,内核在信号到达环形缓冲区之前就将其丢弃,因此静音操作零成本,且无需重新加载程序。
致命信号计数规则
Sigwire 的 ☠ fatal 计数器非常保守。因为 signal_generate 在生成时触发,Sigwire 此时无法知道目标是否已安装处理程序——一个 SIGTERM 可能被捕获并优雅关闭,也可能被完全忽略。因此只有两种情况才计为死亡:
SIGKILL被传递——不可捕获、不可忽略,绝对致命;- 内核自身引发的同步故障信号(
SIGSEGV、SIGBUS、SIGABRT、SIGILL、SIGFPE、SIGTRAP、SIGSYS、SIGQUIT)——非用户态kill发起的信号。
其余所有信号(如 systemd 的 SIGTERM、Ctrl-C 的 SIGINT、运行时的 SIGPWR)只显示和着色,但不计为死亡,因为很可能不是。
核心架构
源码由两个 BPF C 文件(`src/bpf/s
