在 Linux 内核中do_signal是信号处理机制的核心发动机。它并不负责“发送”信号那是 send_signal 的事而是负责**“交付”Delivery**——即当一个进程从内核态返回用户态的临界时刻检查是否有挂起的信号并执行相应的处理动作。1. 核心触发时机返回用户态的前夜do_signal 不是被随机调用的它通常发生在以下路径系统调用返回执行完 sys_read 等调用准备返回时。中断/异常返回时钟中断或缺页异常处理完毕返回时。逻辑闭环 内核在从 entry_INT80_32 或 entry_SYSCALL_64 返回前会检查当前线程的 TIF_SIGPENDING 标志。如果置位则调用 do_signal。2. 源码逻辑拆解 (以 x86 架构为例)在内核源码 arch/x86/kernel/signal.c 中do_signal 的核心逻辑可以概括为以下步骤第一步获取待处理信号 (get_signal)内核会调用 get_signal 从进程的信号队列pending中取出一个信号。屏蔽检查如果信号被 sigprocmask 阻塞则跳过。默认行为处理如果信号的动作是 SIG_IGN忽略或 SIG_DFL默认且无害如 SIGCHLD内核直接在这里处理掉不打扰用户态。致命信号处理如果是 SIGKILL 或 SIGSTOP内核直接让进程终止或停止永远不会返回用户态。第二步处理用户自定义 Handler (handle_signal)如果信号绑定了用户态的处理函数通过 sigaction 注册do_signal 就会调用 handle_signal。第三步伪造栈帧 (The Signal Trampoline)这是最精妙的地方。由于处理函数在用户态内核不能直接跳转。保存上下文内核将当前的寄存器状态包括 EIP/RIP压入用户栈构建一个 sigframe。修改 EIP将内核栈回跳地址修改为用户态信号处理函数的入口。插入返回代码在用户栈里埋下一段特殊的指令sigreturn 系统调用。3. 为什么需要陷入和返回理解 do_signal 的关键在于信号处理函数运行在用户态但决策由内核态做出。执行路径变更原本 CPU 应该回到系统调用后的下一行指令执行但 do_signal 强行把 EIP 改成了处理函数的地址。执行 Handler用户执行处理逻辑。恢复现场 (sys_sigreturn)处理函数结束后执行之前埋下的 sigreturn。这会再次陷入内核由内核从用户栈读取 sigframe恢复原来的寄存器状态原来的 EIP。