<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>信号 on 大飞的博客</title>
    <link>https://www.dafei.me/tags/%E4%BF%A1%E5%8F%B7/</link>
    <description>Recent content in 信号 on 大飞的博客</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Thu, 14 May 2026 04:00:00 +0000</lastBuildDate>
    <atom:link href="https://www.dafei.me/tags/%E4%BF%A1%E5%8F%B7/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>从零写OS（二十四）：signal 信号机制</title>
      <link>https://www.dafei.me/posts/os-24-signal/</link>
      <pubDate>Thu, 14 May 2026 04:00:00 +0000</pubDate>
      <guid>https://www.dafei.me/posts/os-24-signal/</guid>
      <description>&lt;p&gt;到目前为止，进程只能顺序跑完，没有&amp;quot;被打断&amp;quot;的能力。按 Ctrl+C 没有反应，子进程崩溃父进程不知道，&lt;code&gt;kill&lt;/code&gt; 命令更无从谈起。&lt;/p&gt;
&lt;p&gt;这一章实现 &lt;strong&gt;signal&lt;/strong&gt;——内核向进程发送异步通知的机制。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;信号是什么&#34;&gt;信号是什么&lt;/h2&gt;
&lt;p&gt;信号是一个整数编号，内核用它告诉进程&amp;quot;发生了某件事&amp;quot;：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;信号&lt;/th&gt;
          &lt;th&gt;编号&lt;/th&gt;
          &lt;th&gt;默认行为&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;SIGUSR1&lt;/td&gt;
          &lt;td&gt;10&lt;/td&gt;
          &lt;td&gt;终止&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;SIGKILL&lt;/td&gt;
          &lt;td&gt;9&lt;/td&gt;
          &lt;td&gt;终止（不可捕获）&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;SIGTERM&lt;/td&gt;
          &lt;td&gt;15&lt;/td&gt;
          &lt;td&gt;终止&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;SIGCHLD&lt;/td&gt;
          &lt;td&gt;17&lt;/td&gt;
          &lt;td&gt;忽略&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;进程可以用 &lt;code&gt;signal(sig, handler)&lt;/code&gt; 注册自定义处理函数，也可以接受默认行为。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;关键信号不立刻打断进程&#34;&gt;关键：信号不立刻打断进程&lt;/h2&gt;
&lt;p&gt;信号发送时只是设置一个 &lt;strong&gt;pending 位&lt;/strong&gt;，不立刻跳转。等进程下次从内核态返回用户态时，才检查并派发：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;SYS_KILL → pending_signals |= (1 &amp;lt;&amp;lt; sig)

syscall 处理完 → 准备 sysret
                    ↓
          检查 pending_signals
                    ↓
        有信号 → 操纵 user_rip/user_rsp → sysret 跳到 handler
        handler 执行完 ret → 回到原来被中断的位置
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这和硬件中断不同——硬件中断可以在任意时刻打断 CPU，信号只在内核→用户的切换点才生效。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;派发机制trampoline&#34;&gt;派发机制（trampoline）&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;signal_dispatch&lt;/code&gt; 收到两个指针：内核栈上保存的 &lt;code&gt;user_rip&lt;/code&gt;（原来准备 sysret 到的地址）和 &lt;code&gt;user_rsp&lt;/code&gt;。它做的事：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;1. user_rsp -= 8
2. *(user_rsp) = user_rip    // 原返回地址压到用户栈
3. user_rip = handler_addr   // sysret 改跳到 handler
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;sysret 跳到 handler，handler 执行完 &lt;code&gt;ret&lt;/code&gt;，弹出用户栈上的原 rip，回到 kill syscall 之后继续。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
