<?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/%E8%B0%83%E5%BA%A6/</link>
    <description>Recent content in 调度 on 大飞的博客</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Wed, 06 May 2026 09:00:00 +0000</lastBuildDate>
    <atom:link href="https://www.dafei.me/tags/%E8%B0%83%E5%BA%A6/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>从零写OS（九）：进程调度，CPU 的分时复用</title>
      <link>https://www.dafei.me/posts/os-09-process/</link>
      <pubDate>Wed, 06 May 2026 09:00:00 +0000</pubDate>
      <guid>https://www.dafei.me/posts/os-09-process/</guid>
      <description>&lt;p&gt;到目前为止，内核一直是单线程跑到底——一件事没做完，别的什么都不能干。&lt;/p&gt;
&lt;p&gt;这一章让内核同时跑多个进程。每隔一段时间，时钟中断打断当前进程，把 CPU 交给下一个，轮流执行。这就是&lt;strong&gt;多任务&lt;/strong&gt;的核心机制。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;上下文是什么&#34;&gt;上下文是什么&lt;/h2&gt;
&lt;p&gt;进程被打断之后，下次恢复时要从断点继续执行，不能出错。这意味着必须把 CPU 的状态完整保存下来——这份状态就叫&lt;strong&gt;上下文&lt;/strong&gt;（Context）。&lt;/p&gt;
&lt;p&gt;x86-64 ABI 规定了 &lt;strong&gt;callee-saved 寄存器&lt;/strong&gt;（被调用者负责保存的寄存器，C 函数调用约定中，这些寄存器的值在函数调用前后必须保持不变）：&lt;code&gt;rbx&lt;/code&gt;、&lt;code&gt;rbp&lt;/code&gt;、&lt;code&gt;r12&lt;/code&gt;~&lt;code&gt;r15&lt;/code&gt;。加上程序指针 &lt;code&gt;rip&lt;/code&gt; 和栈指针 &lt;code&gt;rsp&lt;/code&gt;，这些就是切换时需要保存和恢复的全部。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; r15, r14, r13, r12;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; rbx, rbp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; rip;   &lt;span style=&#34;color:#75715e&#34;&gt;// 下次从哪里继续执行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; rsp;   &lt;span style=&#34;color:#75715e&#34;&gt;// 栈在哪里
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;context_t&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个进程一份 context，切换时：把当前进程的寄存器存入 &lt;code&gt;ctx&lt;/code&gt;，再把下一个进程 &lt;code&gt;ctx&lt;/code&gt; 里的值写回寄存器——CPU 就&amp;quot;变身&amp;quot;成另一个进程了。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;进程结构&#34;&gt;进程结构&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define MAX_PROCS  8
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define STACK_SIZE 8192   &lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 每个进程 8KB 内核栈
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PROC_UNUSED &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PROC_READY,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PROC_RUNNING,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;proc_state_t&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;context_t&lt;/span&gt;    ctx;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint8_t&lt;/span&gt;     &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;stack;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;proc_state_t&lt;/span&gt; state;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt;     pid;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;process_t&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;process_t&lt;/span&gt; procs[MAX_PROCS];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; current_proc &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;状态机很简单：&lt;code&gt;UNUSED&lt;/code&gt;（槽位空闲）→ &lt;code&gt;READY&lt;/code&gt;（等待调度）→ &lt;code&gt;RUNNING&lt;/code&gt;（正在跑）→ 被打断后回到 &lt;code&gt;READY&lt;/code&gt;。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
