Files
rust-based-os-comp2022/chapter5/2core-data-structures.html
2022-06-30 04:46:48 +00:00

899 lines
108 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html class="no-js" lang="zh_CN">
<head><meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="color-scheme" content="light dark"><link rel="index" title="索引" href="../genindex.html" /><link rel="search" title="搜索" href="../search.html" /><link rel="next" title="进程管理机制的设计实现" href="3implement-process-mechanism.html" /><link rel="prev" title="与进程有关的重要系统调用" href="1process.html" />
<meta name="generator" content="sphinx-4.1.2, furo 2021.08.31"/>
<title>进程管理的核心数据结构 - Open-Source-OS-Training-Camp-2022 文档</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/styles/furo.css?digest=c7c65a82b42f6b978e58466c1e9ef2509836d916" />
<link rel="stylesheet" type="text/css" href="../_static/tabs.css" />
<link rel="stylesheet" type="text/css" href="../_static/styles/furo-extensions.css?digest=16fb25fabf47304eee183a5e9af80b1ba98259b1" />
<link rel="stylesheet" type="text/css" href="../_static/my_style.css" />
<style>
body {
--color-code-background: #f8f8f8;
--color-code-foreground: black;
}
body[data-theme="dark"] {
--color-code-background: #202020;
--color-code-foreground: #d0d0d0;
}
@media (prefers-color-scheme: dark) {
body:not([data-theme="light"]) {
--color-code-background: #202020;
--color-code-foreground: #d0d0d0;
}
}
</style></head>
<body>
<script>
document.body.dataset.theme = localStorage.getItem("theme") || "auto";
</script>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-toc" viewBox="0 0 24 24">
<title>Contents</title>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" />
<line x1="4" y1="6" x2="20" y2="6" />
<line x1="10" y1="12" x2="20" y2="12" />
<line x1="6" y1="18" x2="20" y2="18" />
</svg>
</symbol>
<symbol id="svg-menu" viewBox="0 0 24 24">
<title>Menu</title>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-menu">
<line x1="3" y1="12" x2="21" y2="12"></line>
<line x1="3" y1="6" x2="21" y2="6"></line>
<line x1="3" y1="18" x2="21" y2="18"></line>
</svg>
</symbol>
<symbol id="svg-arrow-right" viewBox="0 0 24 24">
<title>Expand</title>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-chevron-right">
<polyline points="9 18 15 12 9 6"></polyline>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24">
<title>Light mode</title>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="feather-sun">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24">
<title>Dark mode</title>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-moon">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" />
</svg>
</symbol>
<symbol id="svg-sun-half" viewBox="0 0 24 24">
<title>Auto light/dark mode</title>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-shadow">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<circle cx="12" cy="12" r="9" />
<path d="M13 12h5" />
<path d="M13 15h4" />
<path d="M13 18h1" />
<path d="M13 9h4" />
<path d="M13 6h1" />
</svg>
</symbol>
</svg>
<input type="checkbox" class="sidebar-toggle" name="__navigation" id="__navigation">
<input type="checkbox" class="sidebar-toggle" name="__toc" id="__toc">
<label class="overlay sidebar-overlay" for="__navigation">
<div class="visually-hidden">Hide navigation sidebar</div>
</label>
<label class="overlay toc-overlay" for="__toc">
<div class="visually-hidden">Hide table of contents sidebar</div>
</label>
<div class="page">
<header class="mobile-header">
<div class="header-left">
<label class="nav-overlay-icon" for="__navigation">
<div class="visually-hidden">Toggle site navigation sidebar</div>
<i class="icon"><svg><use href="#svg-menu"></use></svg></i>
</label>
</div>
<div class="header-center">
<a href="../index.html"><div class="brand">Open-Source-OS-Training-Camp-2022 文档</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
<button class="theme-toggle">
<div class="visually-hidden">Toggle Light / Dark / Auto color theme</div>
<svg class="theme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
</button>
</div>
<label class="toc-overlay-icon toc-header-icon" for="__toc">
<div class="visually-hidden">Toggle table of contents sidebar</div>
<i class="icon"><svg><use href="#svg-toc"></use></svg></i>
</label>
</div>
</header>
<aside class="sidebar-drawer">
<div class="sidebar-container">
<div class="sidebar-sticky"><a class="sidebar-brand" href="../index.html">
<span class="sidebar-brand-text">Open-Source-OS-Training-Camp-2022 文档</span>
</a><form class="sidebar-search-container" method="get" action="../search.html" role="search">
<input class="sidebar-search" placeholder=搜索 name="q" aria-label="搜索">
<input type="hidden" name="check_keywords" value="yes">
<input type="hidden" name="area" value="default">
</form>
<div id="searchbox"></div><div class="sidebar-scroll"><div class="sidebar-tree">
<p class="caption" role="heading"><span class="caption-text">正文</span></p>
<ul class="current">
<li class="toctree-l1 has-children"><a class="reference internal" href="../0setup-devel-env.html">第零章:实验环境配置</a><input class="toctree-checkbox" id="toctree-checkbox-1" name="toctree-checkbox-1" role="switch" type="checkbox"/><label for="toctree-checkbox-1"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../chapter1/index.html">第一章:应用程序与基本执行环境</a><input class="toctree-checkbox" id="toctree-checkbox-2" name="toctree-checkbox-2" role="switch" type="checkbox"/><label for="toctree-checkbox-2"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l2"><a class="reference internal" href="../chapter1/0intro.html">引言</a></li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../chapter1/1app-ee-platform.html">应用程序执行环境与平台支持</a><input class="toctree-checkbox" id="toctree-checkbox-3" name="toctree-checkbox-3" role="switch" type="checkbox"/><label for="toctree-checkbox-3"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../chapter1/2remove-std.html">移除标准库依赖</a><input class="toctree-checkbox" id="toctree-checkbox-4" name="toctree-checkbox-4" role="switch" type="checkbox"/><label for="toctree-checkbox-4"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../chapter1/3mini-rt-usrland.html">构建用户态执行环境</a><input class="toctree-checkbox" id="toctree-checkbox-5" name="toctree-checkbox-5" role="switch" type="checkbox"/><label for="toctree-checkbox-5"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../chapter1/4mini-rt-baremetal.html">构建裸机执行环境</a><input class="toctree-checkbox" id="toctree-checkbox-6" name="toctree-checkbox-6" role="switch" type="checkbox"/><label for="toctree-checkbox-6"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a><input class="toctree-checkbox" id="toctree-checkbox-7" name="toctree-checkbox-7" role="switch" type="checkbox"/><label for="toctree-checkbox-7"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l2"><a class="reference internal" href="../chapter2/0intro.html">引言</a></li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../chapter2/2application.html">实现应用程序</a><input class="toctree-checkbox" id="toctree-checkbox-8" name="toctree-checkbox-8" role="switch" type="checkbox"/><label for="toctree-checkbox-8"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../chapter2/3batch-system.html">实现批处理操作系统</a><input class="toctree-checkbox" id="toctree-checkbox-9" name="toctree-checkbox-9" role="switch" type="checkbox"/><label for="toctree-checkbox-9"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../chapter2/4trap-handling.html">实现特权级的切换</a><input class="toctree-checkbox" id="toctree-checkbox-10" name="toctree-checkbox-10" role="switch" type="checkbox"/><label for="toctree-checkbox-10"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a><input class="toctree-checkbox" id="toctree-checkbox-11" name="toctree-checkbox-11" role="switch" type="checkbox"/><label for="toctree-checkbox-11"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l2"><a class="reference internal" href="../chapter3/0intro.html">引言</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter3/1multi-loader.html">多道程序放置与加载</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter3/2task-switching.html">任务切换</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter3/3multiprogramming.html">管理多道程序</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter3/4time-sharing-system.html">分时多任务系统</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter3/5exercise.html">chapter3练习</a></li>
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../chapter4/index.html">第四章:地址空间</a><input class="toctree-checkbox" id="toctree-checkbox-12" name="toctree-checkbox-12" role="switch" type="checkbox"/><label for="toctree-checkbox-12"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l2"><a class="reference internal" href="../chapter4/0intro.html">引言</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter4/3sv39-implementation-1.html">实现 SV39 多级页表机制(上)</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter4/4sv39-implementation-2.html">实现 SV39 多级页表机制(下)</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter4/5kernel-app-spaces.html">内核与应用的地址空间</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter4/6multitasking-based-on-as.html">基于地址空间的分时多任务</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter4/7exercise.html">chapter4练习</a></li>
</ul>
</li>
<li class="toctree-l1 current has-children"><a class="reference internal" href="index.html">第五章:进程及进程管理</a><input checked="" class="toctree-checkbox" id="toctree-checkbox-13" name="toctree-checkbox-13" role="switch" type="checkbox"/><label for="toctree-checkbox-13"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="0intro.html">引言</a></li>
<li class="toctree-l2"><a class="reference internal" href="1process.html">与进程有关的重要系统调用</a></li>
<li class="toctree-l2 current current-page"><a class="current reference internal" href="#">进程管理的核心数据结构</a></li>
<li class="toctree-l2"><a class="reference internal" href="3implement-process-mechanism.html">进程管理机制的设计实现</a></li>
<li class="toctree-l2"><a class="reference internal" href="4exercise.html">chapter5练习</a></li>
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../chapter6/index.html">第六章文件系统与I/O重定向</a><input class="toctree-checkbox" id="toctree-checkbox-14" name="toctree-checkbox-14" role="switch" type="checkbox"/><label for="toctree-checkbox-14"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l2"><a class="reference internal" href="../chapter6/0intro.html">引言</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter6/1file-descriptor.html">文件与文件描述符</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter6/1fs-interface.html">文件系统接口</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter6/2fs-implementation-1.html">简易文件系统 easy-fs (上)</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter6/2fs-implementation-2.html">简易文件系统 easy-fs (下)</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter6/3using-easy-fs-in-kernel.html">在内核中使用 easy-fs</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter6/4exercise.html">chapter6练习</a></li>
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../chapter7/index.html">第七章:进程间通信</a><input class="toctree-checkbox" id="toctree-checkbox-15" name="toctree-checkbox-15" role="switch" type="checkbox"/><label for="toctree-checkbox-15"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l2"><a class="reference internal" href="../chapter7/0intro.html">引言</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter7/1pipe.html">管道</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter7/2cmdargs-and-redirection.html">命令行参数与标准 I/O 重定向</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter7/3exercise.html">chapter7练习</a></li>
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../chapter8/index.html">第八章:并发</a><input class="toctree-checkbox" id="toctree-checkbox-16" name="toctree-checkbox-16" role="switch" type="checkbox"/><label for="toctree-checkbox-16"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l2"><a class="reference internal" href="../chapter8/0intro.html">引言</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter8/1thread-kernel.html">内核态的线程管理</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter8/2lock.html">锁机制</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter8/3semaphore.html">信号量机制</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter8/4condition-variable.html">条件变量机制</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter8/5exercise.html">chapter8 练习</a></li>
</ul>
</li>
</ul>
<p class="caption" role="heading"><span class="caption-text">附录</span></p>
<ul>
<li class="toctree-l1 has-children"><a class="reference internal" href="../appendix-a/index.html">附录 ARust 系统编程资料</a><input class="toctree-checkbox" id="toctree-checkbox-17" name="toctree-checkbox-17" role="switch" type="checkbox"/><label for="toctree-checkbox-17"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../appendix-b/index.html">附录 B常见工具的使用方法</a><input class="toctree-checkbox" id="toctree-checkbox-18" name="toctree-checkbox-18" role="switch" type="checkbox"/><label for="toctree-checkbox-18"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../appendix-c/index.html">附录 C深入机器模式RustSBI</a><input class="toctree-checkbox" id="toctree-checkbox-19" name="toctree-checkbox-19" role="switch" type="checkbox"/><label for="toctree-checkbox-19"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../appendix-d/index.html">附录 DRISC-V相关信息</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">开发注记</span></p>
<ul>
<li class="toctree-l1 has-children"><a class="reference internal" href="../setup-sphinx.html">修改和构建本项目</a><input class="toctree-checkbox" id="toctree-checkbox-20" name="toctree-checkbox-20" role="switch" type="checkbox"/><label for="toctree-checkbox-20"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../rest-example.html">reStructuredText 基本语法</a><input class="toctree-checkbox" id="toctree-checkbox-21" name="toctree-checkbox-21" role="switch" type="checkbox"/><label for="toctree-checkbox-21"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
</aside>
<div class="main">
<div class="content">
<article role="main">
<div class="content-icon-container">
<div class="theme-toggle-container theme-toggle-content">
<button class="theme-toggle">
<div class="visually-hidden">Toggle Light / Dark / Auto color theme</div>
<svg class="theme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
</button>
</div>
<label class="toc-overlay-icon toc-content-icon" for="__toc">
<div class="visually-hidden">Toggle table of contents sidebar</div>
<i class="icon"><svg><use href="#svg-toc"></use></svg></i>
</label>
</div>
<div class="section" id="id1">
<h1>进程管理的核心数据结构<a class="headerlink" href="#id1" title="永久链接至标题"></a></h1>
<div class="section" id="id2">
<h2>本节导读<a class="headerlink" href="#id2" title="永久链接至标题"></a></h2>
<p>为了更好实现进程管理,我们需要设计和调整内核中的一些数据结构,包括:</p>
<ul class="simple">
<li><p>基于应用名的应用链接/加载器</p></li>
<li><p>进程标识符 <code class="docutils literal notranslate"><span class="pre">PidHandle</span></code> 以及内核栈 <code class="docutils literal notranslate"><span class="pre">KernelStack</span></code></p></li>
<li><p>任务控制块 <code class="docutils literal notranslate"><span class="pre">TaskControlBlock</span></code></p></li>
<li><p>任务管理器 <code class="docutils literal notranslate"><span class="pre">TaskManager</span></code></p></li>
<li><p>处理器管理结构 <code class="docutils literal notranslate"><span class="pre">Processor</span></code></p></li>
</ul>
</div>
<div class="section" id="id3">
<h2>基于应用名的应用链接/加载器<a class="headerlink" href="#id3" title="永久链接至标题"></a></h2>
<p>在实现 <code class="docutils literal notranslate"><span class="pre">exec</span></code> 系统调用的时候,我们需要根据应用的名字而不仅仅是一个编号来获取应用的 ELF 格式数据。
因此,在链接器 <code class="docutils literal notranslate"><span class="pre">os/build.rs</span></code> 中,我们按顺序保存链接进来的每个应用的名字:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span> // os/build.rs
<span class="linenos"> 2</span>
<span class="linenos"> 3</span> for i in 0..apps.len() {
<span class="linenos"> 4</span> writeln!(f, r#" .quad app_{}_start"#, i)?;
<span class="linenos"> 5</span> }
<span class="linenos"> 6</span> writeln!(f, r#" .quad app_{}_end"#, apps.len() - 1)?;
<span class="linenos"> 7</span>
<span class="hll"><span class="linenos"> 8</span> writeln!(f, r#"
</span><span class="hll"><span class="linenos"> 9</span> .global _app_names
</span><span class="hll"><span class="linenos">10</span>_app_names:"#)?;
</span><span class="hll"><span class="linenos">11</span> for app in apps.iter() {
</span><span class="hll"><span class="linenos">12</span> writeln!(f, r#" .string "{}""#, app)?;
</span><span class="hll"><span class="linenos">13</span> }
</span><span class="linenos">14</span>
<span class="linenos">15</span> for (idx, app) in apps.iter().enumerate() {
<span class="linenos">16</span> ...
<span class="linenos">17</span> }
</pre></div>
</div>
<p>第 8~13 行,各个应用的名字通过 <code class="docutils literal notranslate"><span class="pre">.string</span></code> 伪指令放到数据段中,注意链接器会自动在每个字符串的结尾加入分隔符
<code class="docutils literal notranslate"><span class="pre">\0</span></code> ,它们的位置由全局符号 <code class="docutils literal notranslate"><span class="pre">_app_names</span></code> 指出。</p>
<p>而在加载器 <code class="docutils literal notranslate"><span class="pre">loader.rs</span></code> 中,我们用一个全局可见的 <em>只读</em> 向量 <code class="docutils literal notranslate"><span class="pre">APP_NAMES</span></code> 来按照顺序将所有应用的名字保存在内存中:</p>
<div class="highlight-Rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/loader.rs</span>
<span class="n">lazy_static</span><span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">static</span><span class="w"> </span><span class="k">ref</span><span class="w"> </span><span class="n">APP_NAMES</span>: <span class="nb">Vec</span><span class="o">&lt;&amp;'</span><span class="nb">static</span><span class="w"> </span><span class="kt">str</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">num_app</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">get_num_app</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="k">extern</span><span class="w"> </span><span class="s">"C"</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">fn</span> <span class="nf">_app_names</span><span class="p">();</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_app_names</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">usize</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="o">*</span><span class="k">const</span><span class="w"> </span><span class="kt">u8</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Vec</span>::<span class="n">new</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="k">unsafe</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">0</span><span class="o">..</span><span class="n">num_app</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">start</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="n">end</span><span class="p">.</span><span class="n">read_volatile</span><span class="p">()</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">'\0'</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">u8</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">end</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">slice</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">core</span>::<span class="n">slice</span>::<span class="n">from_raw_parts</span><span class="p">(</span><span class="n">start</span><span class="p">,</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">usize</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">usize</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="kt">str</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">core</span>::<span class="kt">str</span>::<span class="n">from_utf8</span><span class="p">(</span><span class="n">slice</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="kt">str</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">end</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="n">v</span><span class="w"></span>
<span class="w"> </span><span class="p">};</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>使用 <code class="docutils literal notranslate"><span class="pre">get_app_data_by_name</span></code> 可以按照应用的名字来查找获得应用的 ELF 数据,而 <code class="docutils literal notranslate"><span class="pre">list_apps</span></code>
在内核初始化时被调用,它可以打印出所有可用应用的名字。</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/loader.rs</span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">get_app_data_by_name</span><span class="p">(</span><span class="n">name</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Option</span><span class="o">&lt;&amp;'</span><span class="nb">static</span><span class="w"> </span><span class="p">[</span><span class="kt">u8</span><span class="p">]</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">num_app</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">get_num_app</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="n">num_app</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="o">|&amp;</span><span class="n">i</span><span class="o">|</span><span class="w"> </span><span class="n">APP_NAMES</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">name</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">i</span><span class="o">|</span><span class="w"> </span><span class="n">get_app_data</span><span class="p">(</span><span class="n">i</span><span class="p">))</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">list_apps</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"/**** APPS ****"</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">app</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">APP_NAMES</span><span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span><span class="w"> </span><span class="n">app</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"**************/"</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
</div>
<div class="section" id="id4">
<h2>进程标识符和内核栈<a class="headerlink" href="#id4" title="永久链接至标题"></a></h2>
<div class="section" id="id5">
<h3>进程标识符<a class="headerlink" href="#id5" title="永久链接至标题"></a></h3>
<p>同一时间存在的所有进程都有一个自己的进程标识符,它们是互不相同的整数。这里将其抽象为一个 <code class="docutils literal notranslate"><span class="pre">PidHandle</span></code>
类型,当它的生命周期结束后,对应的整数会被编译器自动回收:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/task/pid.rs</span>
<span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">PidHandle</span><span class="p">(</span><span class="k">pub</span><span class="w"> </span><span class="kt">usize</span><span class="p">);</span><span class="w"></span>
</pre></div>
</div>
<p>类似之前的物理页帧分配器 <code class="docutils literal notranslate"><span class="pre">FrameAllocator</span></code> ,我们实现一个同样使用简单栈式分配策略的进程标识符分配器
<code class="docutils literal notranslate"><span class="pre">PidAllocator</span></code> ,并将其全局实例化为 <code class="docutils literal notranslate"><span class="pre">PID_ALLOCATOR</span></code> </p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/task/pid.rs</span>
<span class="k">struct</span> <span class="nc">PidAllocator</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">current</span>: <span class="kt">usize</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">recycled</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">usize</span><span class="o">&gt;</span><span class="p">,</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="k">impl</span><span class="w"> </span><span class="n">PidAllocator</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">new</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nc">Self</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">PidAllocator</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">current</span>: <span class="mi">0</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">recycled</span>: <span class="nb">Vec</span>::<span class="n">new</span><span class="p">(),</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">alloc</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">PidHandle</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">pid</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">recycled</span><span class="p">.</span><span class="n">pop</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">PidHandle</span><span class="p">(</span><span class="n">pid</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">current</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">PidHandle</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">current</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">dealloc</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">pid</span>: <span class="kt">usize</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="fm">assert!</span><span class="p">(</span><span class="n">pid</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">current</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="fm">assert!</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">recycled</span><span class="p">.</span><span class="n">iter</span><span class="p">().</span><span class="n">find</span><span class="p">(</span><span class="o">|</span><span class="n">ppid</span><span class="o">|</span><span class="w"> </span><span class="o">**</span><span class="n">ppid</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">pid</span><span class="p">).</span><span class="n">is_none</span><span class="p">(),</span><span class="w"></span>
<span class="w"> </span><span class="s">"pid {} has been deallocated!"</span><span class="p">,</span><span class="w"> </span><span class="n">pid</span><span class="w"></span>
<span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">recycled</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">pid</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="n">lazy_static</span><span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">static</span><span class="w"> </span><span class="k">ref</span><span class="w"> </span><span class="n">PID_ALLOCATOR</span>: <span class="nc">UPSafeCell</span><span class="o">&lt;</span><span class="n">PidAllocator</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"></span>
<span class="w"> </span><span class="k">unsafe</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">UPSafeCell</span>::<span class="n">new</span><span class="p">(</span><span class="n">PidAllocator</span>::<span class="n">new</span><span class="p">())</span><span class="w"> </span><span class="p">};</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">PidAllocator::alloc</span></code> 将会分配出去一个将 <code class="docutils literal notranslate"><span class="pre">usize</span></code> 包装之后的 <code class="docutils literal notranslate"><span class="pre">PidHandle</span></code>
我们将其包装为一个全局分配进程标识符的接口 <code class="docutils literal notranslate"><span class="pre">pid_alloc</span></code></p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/task/pid.rs</span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">pid_alloc</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nc">PidHandle</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">PID_ALLOCATOR</span><span class="p">.</span><span class="n">exclusive_access</span><span class="p">().</span><span class="n">alloc</span><span class="p">()</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>同时我们也需要为 <code class="docutils literal notranslate"><span class="pre">PidHandle</span></code> 实现 <code class="docutils literal notranslate"><span class="pre">Drop</span></code> Trait 来允许编译器进行自动的资源回收:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/task/pid.rs</span>
<span class="k">impl</span><span class="w"> </span><span class="nb">Drop</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">PidHandle</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">fn</span> <span class="nf">drop</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="c1">//println!("drop pid {}", self.0);</span>
<span class="w"> </span><span class="n">PID_ALLOCATOR</span><span class="p">.</span><span class="n">exclusive_access</span><span class="p">().</span><span class="n">dealloc</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="mi">0</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
</div>
<div class="section" id="id6">
<h3>内核栈<a class="headerlink" href="#id6" title="永久链接至标题"></a></h3>
<p>从本章开始,我们将应用编号替换为进程标识符来决定每个进程内核栈在地址空间中的位置。</p>
<p>在内核栈 <code class="docutils literal notranslate"><span class="pre">KernelStack</span></code> 中保存着它所属进程的 PID </p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/task/pid.rs</span>
<span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">KernelStack</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">pid</span>: <span class="kt">usize</span><span class="p">,</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>它提供以下方法:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// os/src/task/pid.rs</span>
<span class="linenos"> 2</span>
<span class="linenos"> 3</span><span class="sd">/// Return (bottom, top) of a kernel stack in kernel space.</span>
<span class="linenos"> 4</span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">kernel_stack_position</span><span class="p">(</span><span class="n">app_id</span>: <span class="kt">usize</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="p">(</span><span class="kt">usize</span><span class="p">,</span><span class="w"> </span><span class="kt">usize</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos"> 5</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">top</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">TRAMPOLINE</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">app_id</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="n">KERNEL_STACK_SIZE</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">PAGE_SIZE</span><span class="p">);</span><span class="w"></span>
<span class="linenos"> 6</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">bottom</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">top</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">KERNEL_STACK_SIZE</span><span class="p">;</span><span class="w"></span>
<span class="linenos"> 7</span><span class="w"> </span><span class="p">(</span><span class="n">bottom</span><span class="p">,</span><span class="w"> </span><span class="n">top</span><span class="p">)</span><span class="w"></span>
<span class="linenos"> 8</span><span class="p">}</span><span class="w"></span>
<span class="linenos"> 9</span>
<span class="linenos">10</span><span class="k">impl</span><span class="w"> </span><span class="n">KernelStack</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">11</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">pid_handle</span>: <span class="kp">&amp;</span><span class="nc">PidHandle</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Self</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">12</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">pid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pid_handle</span><span class="p">.</span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="linenos">13</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="p">(</span><span class="n">kernel_stack_bottom</span><span class="p">,</span><span class="w"> </span><span class="n">kernel_stack_top</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">kernel_stack_position</span><span class="p">(</span><span class="n">pid</span><span class="p">);</span><span class="w"></span>
<span class="linenos">14</span><span class="w"> </span><span class="n">KERNEL_SPACE</span><span class="p">.</span><span class="n">exclusive_access</span><span class="p">().</span><span class="n">insert_framed_area</span><span class="p">(</span><span class="w"></span>
<span class="linenos">15</span><span class="w"> </span><span class="n">kernel_stack_bottom</span><span class="p">.</span><span class="n">into</span><span class="p">(),</span><span class="w"></span>
<span class="linenos">16</span><span class="w"> </span><span class="n">kernel_stack_top</span><span class="p">.</span><span class="n">into</span><span class="p">(),</span><span class="w"></span>
<span class="linenos">17</span><span class="w"> </span><span class="n">MapPermission</span>::<span class="n">R</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">MapPermission</span>::<span class="n">W</span><span class="p">,</span><span class="w"></span>
<span class="linenos">18</span><span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="linenos">19</span><span class="w"> </span><span class="n">KernelStack</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">20</span><span class="w"> </span><span class="n">pid</span>: <span class="nc">pid_handle</span><span class="p">.</span><span class="mi">0</span><span class="p">,</span><span class="w"></span>
<span class="linenos">21</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">22</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">23</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">push_on_top</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">value</span>: <span class="nc">T</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="o">*</span><span class="k">mut</span><span class="w"> </span><span class="n">T</span><span class="w"> </span><span class="k">where</span><span class="w"></span>
<span class="linenos">24</span><span class="w"> </span><span class="n">T</span>: <span class="nb">Sized</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">25</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">kernel_stack_top</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">get_top</span><span class="p">();</span><span class="w"></span>
<span class="linenos">26</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">ptr_mut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">kernel_stack_top</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">core</span>::<span class="n">mem</span>::<span class="n">size_of</span>::<span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">())</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="o">*</span><span class="k">mut</span><span class="w"> </span><span class="n">T</span><span class="p">;</span><span class="w"></span>
<span class="linenos">27</span><span class="w"> </span><span class="k">unsafe</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="o">*</span><span class="n">ptr_mut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">value</span><span class="p">;</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">28</span><span class="w"> </span><span class="n">ptr_mut</span><span class="w"></span>
<span class="linenos">29</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">30</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">get_top</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">usize</span> <span class="p">{</span><span class="w"></span>
<span class="linenos">31</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="p">(</span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="n">kernel_stack_top</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">kernel_stack_position</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">pid</span><span class="p">);</span><span class="w"></span>
<span class="linenos">32</span><span class="w"> </span><span class="n">kernel_stack_top</span><span class="w"></span>
<span class="linenos">33</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">34</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<ul class="simple">
<li><p>第 11 行, <code class="docutils literal notranslate"><span class="pre">new</span></code> 方法可以从一个 <code class="docutils literal notranslate"><span class="pre">PidHandle</span></code> ,也就是一个已分配的进程标识符中对应生成一个内核栈 <code class="docutils literal notranslate"><span class="pre">KernelStack</span></code>
它调用了第 4 行声明的 <code class="docutils literal notranslate"><span class="pre">kernel_stack_position</span></code> 函数来根据进程标识符计算内核栈在内核地址空间中的位置,
随即在第 14 行将一个逻辑段插入内核地址空间 <code class="docutils literal notranslate"><span class="pre">KERNEL_SPACE</span></code> 中。</p></li>
<li><p>第 25 行的 <code class="docutils literal notranslate"><span class="pre">push_on_top</span></code> 方法可以将一个类型为 <code class="docutils literal notranslate"><span class="pre">T</span></code> 的变量压入内核栈顶并返回其裸指针,
这也是一个泛型函数。它在实现的时候用到了第 32 行的 <code class="docutils literal notranslate"><span class="pre">get_top</span></code> 方法来获取当前内核栈顶在内核地址空间中的地址。</p></li>
</ul>
<p>内核栈 <code class="docutils literal notranslate"><span class="pre">KernelStack</span></code> 用到了 RAII 的思想,具体来说,实际保存它的物理页帧的生命周期被绑定到它下面,当
<code class="docutils literal notranslate"><span class="pre">KernelStack</span></code> 生命周期结束后,这些物理页帧也将会被编译器自动回收:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/task/pid.rs</span>
<span class="k">impl</span><span class="w"> </span><span class="nb">Drop</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">KernelStack</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">fn</span> <span class="nf">drop</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="p">(</span><span class="n">kernel_stack_bottom</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">kernel_stack_position</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">pid</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">kernel_stack_bottom_va</span>: <span class="nc">VirtAddr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">kernel_stack_bottom</span><span class="p">.</span><span class="n">into</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">KERNEL_SPACE</span><span class="w"></span>
<span class="w"> </span><span class="p">.</span><span class="n">exclusive_access</span><span class="p">()</span><span class="w"></span>
<span class="w"> </span><span class="p">.</span><span class="n">remove_area_with_start_vpn</span><span class="p">(</span><span class="n">kernel_stack_bottom_va</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">KernelStack</span></code> 实现 <code class="docutils literal notranslate"><span class="pre">Drop</span></code> Trait一旦它的生命周期结束就将内核地址空间中对应的逻辑段删除为此在 <code class="docutils literal notranslate"><span class="pre">MemorySet</span></code>
中新增了一个名为 <code class="docutils literal notranslate"><span class="pre">remove_area_with_start_vpn</span></code> 的方法,感兴趣的读者可以查阅。</p>
</div>
</div>
<div class="section" id="id7">
<h2>进程控制块<a class="headerlink" href="#id7" title="永久链接至标题"></a></h2>
<p>在内核中,每个进程的执行状态、资源控制等元数据均保存在一个被称为 <strong>进程控制块</strong> (PCB, Process Control Block)
的结构中,它是内核对进程进行管理的单位。在内核看来,它就等价于一个进程。</p>
<p>承接前面的章节,我们仅需对任务控制块 <code class="docutils literal notranslate"><span class="pre">TaskControlBlock</span></code> 进行若干改动,让它直接承担进程控制块的功能:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// os/src/task/task.rs</span>
<span class="linenos"> 2</span>
<span class="linenos"> 3</span><span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">TaskControlBlock</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos"> 4</span><span class="w"> </span><span class="c1">// immutable</span>
<span class="linenos"> 5</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="n">pid</span>: <span class="nc">PidHandle</span><span class="p">,</span><span class="w"></span>
<span class="linenos"> 6</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="n">kernel_stack</span>: <span class="nc">KernelStack</span><span class="p">,</span><span class="w"></span>
<span class="linenos"> 7</span><span class="w"> </span><span class="c1">// mutable</span>
<span class="linenos"> 8</span><span class="w"> </span><span class="n">inner</span>: <span class="nc">UPSafeCell</span><span class="o">&lt;</span><span class="n">TaskControlBlockInner</span><span class="o">&gt;</span><span class="p">,</span><span class="w"></span>
<span class="linenos"> 9</span><span class="p">}</span><span class="w"></span>
<span class="linenos">10</span>
<span class="linenos">11</span><span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">TaskControlBlockInner</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">12</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="n">trap_cx_ppn</span>: <span class="nc">PhysPageNum</span><span class="p">,</span><span class="w"></span>
<span class="linenos">13</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="n">base_size</span>: <span class="kt">usize</span><span class="p">,</span><span class="w"></span>
<span class="linenos">14</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="n">task_cx</span>: <span class="nc">TaskContext</span><span class="p">,</span><span class="w"></span>
<span class="linenos">15</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="n">task_status</span>: <span class="nc">TaskStatus</span><span class="p">,</span><span class="w"></span>
<span class="linenos">16</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="n">memory_set</span>: <span class="nc">MemorySet</span><span class="p">,</span><span class="w"></span>
<span class="linenos">17</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="n">parent</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="n">Weak</span><span class="o">&lt;</span><span class="n">TaskControlBlock</span><span class="o">&gt;&gt;</span><span class="p">,</span><span class="w"></span>
<span class="linenos">18</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="n">children</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Arc</span><span class="o">&lt;</span><span class="n">TaskControlBlock</span><span class="o">&gt;&gt;</span><span class="p">,</span><span class="w"></span>
<span class="linenos">19</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="n">exit_code</span>: <span class="kt">i32</span><span class="p">,</span><span class="w"></span>
<span class="linenos">20</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>任务控制块中包含两部分:</p>
<ul class="simple">
<li><p>在初始化之后就不再变化的作为一个字段直接放在任务控制块中。这里将进程标识符 <code class="docutils literal notranslate"><span class="pre">PidHandle</span></code> 和内核栈 <code class="docutils literal notranslate"><span class="pre">KernelStack</span></code> 放在其中;</p></li>
<li><p>在运行过程中可能发生变化的则放在 <code class="docutils literal notranslate"><span class="pre">TaskControlBlockInner</span></code> 中,将它再包裹上一层 <code class="docutils literal notranslate"><span class="pre">UPSafeCell&lt;T&gt;</span></code> 放在任务控制块中。
在此使用 <code class="docutils literal notranslate"><span class="pre">UPSafeCell&lt;T&gt;</span></code> 可以提供互斥从而避免数据竞争。</p></li>
</ul>
<p><code class="docutils literal notranslate"><span class="pre">TaskControlBlockInner</span></code> 中包含下面这些内容:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">trap_cx_ppn</span></code> 指出了应用地址空间中的 Trap 上下文被放在的物理页帧的物理页号。</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">base_size</span></code> 的含义是:应用数据仅有可能出现在应用地址空间低于 <code class="docutils literal notranslate"><span class="pre">base_size</span></code> 字节的区域中。借助它我们可以清楚的知道应用有多少数据驻留在内存中。</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">task_cx</span></code> 保存任务上下文,用于任务切换。</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">task_status</span></code> 维护当前进程的执行状态。</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">memory_set</span></code> 表示应用地址空间。</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">parent</span></code> 指向当前进程的父进程(如果存在的话)。注意我们使用 <code class="docutils literal notranslate"><span class="pre">Weak</span></code> 而非 <code class="docutils literal notranslate"><span class="pre">Arc</span></code>
来包裹另一个任务控制块,因此这个智能指针将不会影响父进程的引用计数。</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">children</span></code> 则将当前进程的所有子进程的任务控制块以 <code class="docutils literal notranslate"><span class="pre">Arc</span></code> 智能指针的形式保存在一个向量中,这样才能够更方便的找到它们。</p></li>
<li><p>当进程调用 exit 系统调用主动退出或者执行出错由内核终止的时候,它的退出码 <code class="docutils literal notranslate"><span class="pre">exit_code</span></code>
会被内核保存在它的任务控制块中,并等待它的父进程通过 waitpid 回收它的资源的同时也收集它的 PID 以及退出码。</p></li>
</ul>
<p>注意我们在维护父子进程关系的时候大量用到了智能指针 <code class="docutils literal notranslate"><span class="pre">Arc/Weak</span></code> ,当且仅当它的引用计数变为 0 的时候,进程控制块以及被绑定到它上面的各类资源才会被回收。</p>
<p><code class="docutils literal notranslate"><span class="pre">TaskControlBlockInner</span></code> 提供的方法主要是对于它内部字段的快捷访问:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/task/task.rs</span>
<span class="k">impl</span><span class="w"> </span><span class="n">TaskControlBlockInner</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">get_trap_cx</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kp">&amp;</span><span class="o">'</span><span class="nb">static</span> <span class="nc">mut</span><span class="w"> </span><span class="n">TrapContext</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">trap_cx_ppn</span><span class="p">.</span><span class="n">get_mut</span><span class="p">()</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">get_user_token</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">usize</span> <span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">memory_set</span><span class="p">.</span><span class="n">token</span><span class="p">()</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="k">fn</span> <span class="nf">get_status</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">TaskStatus</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">task_status</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">is_zombie</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">bool</span> <span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">get_status</span><span class="p">()</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">TaskStatus</span>::<span class="n">Zombie</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>而任务控制块 <code class="docutils literal notranslate"><span class="pre">TaskControlBlock</span></code> 目前提供以下方法:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/task/task.rs</span>
<span class="k">impl</span><span class="w"> </span><span class="n">TaskControlBlock</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">inner_exclusive_access</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">RefMut</span><span class="o">&lt;'</span><span class="nb">_</span><span class="p">,</span><span class="w"> </span><span class="n">TaskControlBlockInner</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">inner</span><span class="p">.</span><span class="n">exclusive_access</span><span class="p">()</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">getpid</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">usize</span> <span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">pid</span><span class="p">.</span><span class="mi">0</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">elf_data</span>: <span class="kp">&amp;</span><span class="p">[</span><span class="kt">u8</span><span class="p">])</span><span class="w"> </span>-&gt; <span class="nc">Self</span><span class="w"> </span><span class="p">{</span><span class="o">..</span><span class="p">.}</span><span class="w"></span>
<span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">exec</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">elf_data</span>: <span class="kp">&amp;</span><span class="p">[</span><span class="kt">u8</span><span class="p">])</span><span class="w"> </span><span class="p">{</span><span class="o">..</span><span class="p">.}</span><span class="w"></span>
<span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">fork</span><span class="p">(</span><span class="bp">self</span>: <span class="kp">&amp;</span><span class="nc">Arc</span><span class="o">&lt;</span><span class="n">TaskControlBlock</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Arc</span><span class="o">&lt;</span><span class="n">TaskControlBlock</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="o">..</span><span class="p">.}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">inner_exclusive_access</span></code> 尝试获取互斥锁来得到 <code class="docutils literal notranslate"><span class="pre">TaskControlBlockInner</span></code> 的可变引用。</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">getpid</span></code><code class="docutils literal notranslate"><span class="pre">usize</span></code> 的形式返回当前进程的进程标识符。</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">new</span></code> 用来创建一个新的进程,目前仅用于内核中手动创建唯一一个初始进程 <code class="docutils literal notranslate"><span class="pre">initproc</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">exec</span></code> 用来实现 <code class="docutils literal notranslate"><span class="pre">exec</span></code> 系统调用,即当前进程加载并执行另一个 ELF 格式可执行文件。</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">fork</span></code> 用来实现 <code class="docutils literal notranslate"><span class="pre">fork</span></code> 系统调用,即当前进程 fork 出来一个与之几乎相同的子进程。</p></li>
</ul>
<p><code class="docutils literal notranslate"><span class="pre">new/exec/fork</span></code> 的实现我们将在下一小节再介绍。</p>
</div>
<div class="section" id="id8">
<h2>任务管理器<a class="headerlink" href="#id8" title="永久链接至标题"></a></h2>
<p>在前面的章节中,任务管理器 <code class="docutils literal notranslate"><span class="pre">TaskManager</span></code> 不仅负责管理所有的任务,还维护着 CPU 当前在执行哪个任务。
由于这种设计不够灵活,我们需要将任务管理器对于 CPU 的监控职能拆分到处理器管理结构 <code class="docutils literal notranslate"><span class="pre">Processor</span></code> 中去,
任务管理器自身仅负责管理所有任务。在这里,任务指的就是进程。</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// os/src/task/manager.rs</span>
<span class="linenos"> 2</span>
<span class="linenos"> 3</span><span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">TaskManager</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos"> 4</span><span class="w"> </span><span class="n">ready_queue</span>: <span class="nc">VecDeque</span><span class="o">&lt;</span><span class="n">Arc</span><span class="o">&lt;</span><span class="n">TaskControlBlock</span><span class="o">&gt;&gt;</span><span class="p">,</span><span class="w"></span>
<span class="linenos"> 5</span><span class="p">}</span><span class="w"></span>
<span class="linenos"> 6</span>
<span class="linenos"> 7</span><span class="sd">/// A simple FIFO scheduler.</span>
<span class="linenos"> 8</span><span class="k">impl</span><span class="w"> </span><span class="n">TaskManager</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos"> 9</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">new</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nc">Self</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">10</span><span class="w"> </span><span class="bp">Self</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">11</span><span class="w"> </span><span class="n">ready_queue</span>: <span class="nc">VecDeque</span>::<span class="n">new</span><span class="p">(),</span><span class="w"></span>
<span class="linenos">12</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">13</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">14</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">add</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">task</span>: <span class="nc">Arc</span><span class="o">&lt;</span><span class="n">TaskControlBlock</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">15</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">ready_queue</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">task</span><span class="p">);</span><span class="w"></span>
<span class="linenos">16</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">17</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">fetch</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Option</span><span class="o">&lt;</span><span class="n">Arc</span><span class="o">&lt;</span><span class="n">TaskControlBlock</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">18</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">ready_queue</span><span class="p">.</span><span class="n">pop_front</span><span class="p">()</span><span class="w"></span>
<span class="linenos">19</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">20</span><span class="p">}</span><span class="w"></span>
<span class="linenos">21</span>
<span class="linenos">22</span><span class="n">lazy_static</span><span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">23</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">static</span><span class="w"> </span><span class="k">ref</span><span class="w"> </span><span class="n">TASK_MANAGER</span>: <span class="nc">UPSafeCell</span><span class="o">&lt;</span><span class="n">TaskManager</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"></span>
<span class="linenos">24</span><span class="w"> </span><span class="k">unsafe</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">UPSafeCell</span>::<span class="n">new</span><span class="p">(</span><span class="n">TaskManager</span>::<span class="n">new</span><span class="p">())</span><span class="w"> </span><span class="p">};</span><span class="w"></span>
<span class="linenos">25</span><span class="p">}</span><span class="w"></span>
<span class="linenos">26</span>
<span class="linenos">27</span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">add_task</span><span class="p">(</span><span class="n">task</span>: <span class="nc">Arc</span><span class="o">&lt;</span><span class="n">TaskControlBlock</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">28</span><span class="w"> </span><span class="n">TASK_MANAGER</span><span class="p">.</span><span class="n">exclusive_access</span><span class="p">().</span><span class="n">add</span><span class="p">(</span><span class="n">task</span><span class="p">);</span><span class="w"></span>
<span class="linenos">29</span><span class="p">}</span><span class="w"></span>
<span class="linenos">30</span>
<span class="linenos">31</span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">fetch_task</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nb">Option</span><span class="o">&lt;</span><span class="n">Arc</span><span class="o">&lt;</span><span class="n">TaskControlBlock</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">32</span><span class="w"> </span><span class="n">TASK_MANAGER</span><span class="p">.</span><span class="n">exclusive_access</span><span class="p">().</span><span class="n">fetch</span><span class="p">()</span><span class="w"></span>
<span class="linenos">33</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">TaskManager</span></code> 将所有的任务控制块用引用计数 <code class="docutils literal notranslate"><span class="pre">Arc</span></code> 智能指针包裹后放在一个双端队列 <code class="docutils literal notranslate"><span class="pre">VecDeque</span></code> 中。
使用智能指针的原因在于,任务控制块经常需要被放入/取出,如果直接移动任务控制块自身将会带来大量的数据拷贝开销,
而对于智能指针进行移动则没有多少开销。其次,允许任务控制块的共享引用在某些情况下能够让我们的实现更加方便。</p>
<p><code class="docutils literal notranslate"><span class="pre">TaskManager</span></code> 提供 <code class="docutils literal notranslate"><span class="pre">add/fetch</span></code> 两个操作,前者表示将一个任务加入队尾,后者则表示从队头中取出一个任务来执行。
从调度算法来看,这里用到的就是最简单的 RR 算法。全局实例 <code class="docutils literal notranslate"><span class="pre">TASK_MANAGER</span></code> 则提供给内核的其他子模块 <code class="docutils literal notranslate"><span class="pre">add_task/fetch_task</span></code> 两个函数。</p>
</div>
<div class="section" id="id9">
<h2>处理器管理结构<a class="headerlink" href="#id9" title="永久链接至标题"></a></h2>
<p>处理器管理结构 <code class="docutils literal notranslate"><span class="pre">Processor</span></code> 负责维护从任务管理器 <code class="docutils literal notranslate"><span class="pre">TaskManager</span></code> 分离出去的那部分 CPU 状态:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/task/processor.rs</span>
<span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">Processor</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">current</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="n">Arc</span><span class="o">&lt;</span><span class="n">TaskControlBlock</span><span class="o">&gt;&gt;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">idle_task_cx</span>: <span class="nc">TaskContext</span><span class="p">,</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>包括:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">current</span></code> 表示在当前处理器上正在执行的任务;</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">idle_task_cx_ptr</span></code> 表示当前处理器上的 idle 控制流的任务上下文的地址。</p></li>
</ul>
<p>在单核环境下,我们仅创建单个 <code class="docutils literal notranslate"><span class="pre">Processor</span></code> 的全局实例 <code class="docutils literal notranslate"><span class="pre">PROCESSOR</span></code> </p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/task/processor.rs</span>
<span class="n">lazy_static</span><span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">static</span><span class="w"> </span><span class="k">ref</span><span class="w"> </span><span class="n">PROCESSOR</span>: <span class="nc">UPSafeCell</span><span class="o">&lt;</span><span class="n">Processor</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">unsafe</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">UPSafeCell</span>::<span class="n">new</span><span class="p">(</span><span class="n">Processor</span>::<span class="n">new</span><span class="p">())</span><span class="w"> </span><span class="p">};</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<div class="section" id="id10">
<h3>正在执行的任务<a class="headerlink" href="#id10" title="永久链接至标题"></a></h3>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// os/src/task/processor.rs</span>
<span class="linenos"> 2</span>
<span class="linenos"> 3</span><span class="k">impl</span><span class="w"> </span><span class="n">Processor</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos"> 4</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">take_current</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Option</span><span class="o">&lt;</span><span class="n">Arc</span><span class="o">&lt;</span><span class="n">TaskControlBlock</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos"> 5</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">current</span><span class="p">.</span><span class="n">take</span><span class="p">()</span><span class="w"></span>
<span class="linenos"> 6</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos"> 7</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">current</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Option</span><span class="o">&lt;</span><span class="n">Arc</span><span class="o">&lt;</span><span class="n">TaskControlBlock</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos"> 8</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">current</span><span class="p">.</span><span class="n">as_ref</span><span class="p">().</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">task</span><span class="o">|</span><span class="w"> </span><span class="n">Arc</span>::<span class="n">clone</span><span class="p">(</span><span class="n">task</span><span class="p">))</span><span class="w"></span>
<span class="linenos"> 9</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">10</span><span class="p">}</span><span class="w"></span>
<span class="linenos">11</span>
<span class="linenos">12</span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">take_current_task</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nb">Option</span><span class="o">&lt;</span><span class="n">Arc</span><span class="o">&lt;</span><span class="n">TaskControlBlock</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">13</span><span class="w"> </span><span class="n">PROCESSOR</span><span class="p">.</span><span class="n">take_current</span><span class="p">()</span><span class="w"></span>
<span class="linenos">14</span><span class="p">}</span><span class="w"></span>
<span class="linenos">15</span>
<span class="linenos">16</span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">current_task</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nb">Option</span><span class="o">&lt;</span><span class="n">Arc</span><span class="o">&lt;</span><span class="n">TaskControlBlock</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">17</span><span class="w"> </span><span class="n">PROCESSOR</span><span class="p">.</span><span class="n">current</span><span class="p">()</span><span class="w"></span>
<span class="linenos">18</span><span class="p">}</span><span class="w"></span>
<span class="linenos">19</span>
<span class="linenos">20</span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">current_user_token</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="kt">usize</span> <span class="p">{</span><span class="w"></span>
<span class="linenos">21</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">task</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">current_task</span><span class="p">().</span><span class="n">unwrap</span><span class="p">();</span><span class="w"></span>
<span class="linenos">22</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">token</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">task</span><span class="p">.</span><span class="n">inner_exclusive_access</span><span class="p">().</span><span class="n">get_user_token</span><span class="p">();</span><span class="w"></span>
<span class="linenos">23</span><span class="w"> </span><span class="n">token</span><span class="w"></span>
<span class="linenos">24</span><span class="p">}</span><span class="w"></span>
<span class="linenos">25</span>
<span class="linenos">26</span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">current_trap_cx</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="kp">&amp;</span><span class="o">'</span><span class="nb">static</span> <span class="nc">mut</span><span class="w"> </span><span class="n">TrapContext</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">27</span><span class="w"> </span><span class="n">current_task</span><span class="p">()</span><span class="w"></span>
<span class="linenos">28</span><span class="w"> </span><span class="p">.</span><span class="n">unwrap</span><span class="p">()</span><span class="w"></span>
<span class="linenos">29</span><span class="w"> </span><span class="p">.</span><span class="n">inner_exclusive_access</span><span class="p">()</span><span class="w"></span>
<span class="linenos">30</span><span class="w"> </span><span class="p">.</span><span class="n">get_trap_cx</span><span class="p">()</span><span class="w"></span>
<span class="linenos">31</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<ul class="simple">
<li><p>第 4 行的 <code class="docutils literal notranslate"><span class="pre">Processor::take_current</span></code> 可以取出当前正在执行的任务。 <code class="docutils literal notranslate"><span class="pre">Option::take</span></code> 意味着 <code class="docutils literal notranslate"><span class="pre">current</span></code> 字段也变为 <code class="docutils literal notranslate"><span class="pre">None</span></code></p></li>
<li><p>第 7 行的 <code class="docutils literal notranslate"><span class="pre">Processor::current</span></code> 返回当前执行的任务的一份拷贝。。</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">current_user_token</span></code><code class="docutils literal notranslate"><span class="pre">current_trap_cx</span></code> 基于 <code class="docutils literal notranslate"><span class="pre">current_task</span></code> 实现,提供当前正在执行的任务的更多信息。</p></li>
</ul>
</div>
<div class="section" id="idle">
<h3>任务调度的 idle 控制流<a class="headerlink" href="#idle" title="永久链接至标题"></a></h3>
<p>每个 <code class="docutils literal notranslate"><span class="pre">Processor</span></code> 都有一个 idle 控制流,它们运行在每个核各自的启动栈上,功能是尝试从任务管理器中选出一个任务来在当前核上执行。
在内核初始化完毕之后,核通过调用 <code class="docutils literal notranslate"><span class="pre">run_tasks</span></code> 函数来进入 idle 控制流:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// os/src/task/processor.rs</span>
<span class="linenos"> 2</span>
<span class="linenos"> 3</span><span class="k">impl</span><span class="w"> </span><span class="n">Processor</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos"> 4</span><span class="w"> </span><span class="k">fn</span> <span class="nf">get_idle_task_cx_ptr</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="o">*</span><span class="k">mut</span><span class="w"> </span><span class="n">TaskContext</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos"> 5</span><span class="w"> </span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">idle_task_cx</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="o">*</span><span class="k">mut</span><span class="w"> </span><span class="n">_</span><span class="w"></span>
<span class="linenos"> 6</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos"> 7</span><span class="p">}</span><span class="w"></span>
<span class="linenos"> 8</span>
<span class="linenos"> 9</span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">run_tasks</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">10</span><span class="w"> </span><span class="k">loop</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">11</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">processor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PROCESSOR</span><span class="p">.</span><span class="n">exclusive_access</span><span class="p">();</span><span class="w"></span>
<span class="linenos">12</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">task</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">fetch_task</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">13</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">idle_task_cx_ptr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">processor</span><span class="p">.</span><span class="n">get_idle_task_cx_ptr</span><span class="p">();</span><span class="w"></span>
<span class="linenos">14</span><span class="w"> </span><span class="c1">// access coming task TCB exclusively</span>
<span class="linenos">15</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">task_inner</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">task</span><span class="p">.</span><span class="n">inner_exclusive_access</span><span class="p">();</span><span class="w"></span>
<span class="linenos">16</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">next_task_cx_ptr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">task_inner</span><span class="p">.</span><span class="n">task_cx</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="o">*</span><span class="k">const</span><span class="w"> </span><span class="n">TaskContext</span><span class="p">;</span><span class="w"></span>
<span class="linenos">17</span><span class="w"> </span><span class="n">task_inner</span><span class="p">.</span><span class="n">task_status</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">TaskStatus</span>::<span class="n">Running</span><span class="p">;</span><span class="w"></span>
<span class="linenos">18</span><span class="w"> </span><span class="nb">drop</span><span class="p">(</span><span class="n">task_inner</span><span class="p">);</span><span class="w"></span>
<span class="linenos">19</span><span class="w"> </span><span class="c1">// release coming task TCB manually</span>
<span class="linenos">20</span><span class="w"> </span><span class="n">processor</span><span class="p">.</span><span class="n">current</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">task</span><span class="p">);</span><span class="w"></span>
<span class="linenos">21</span><span class="w"> </span><span class="c1">// release processor manually</span>
<span class="linenos">22</span><span class="w"> </span><span class="nb">drop</span><span class="p">(</span><span class="n">processor</span><span class="p">);</span><span class="w"></span>
<span class="linenos">23</span><span class="w"> </span><span class="k">unsafe</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">24</span><span class="w"> </span><span class="n">__switch</span><span class="p">(</span><span class="n">idle_task_cx_ptr</span><span class="p">,</span><span class="w"> </span><span class="n">next_task_cx_ptr</span><span class="p">);</span><span class="w"></span>
<span class="linenos">25</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">26</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">27</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">28</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>调度功能的主体在 <code class="docutils literal notranslate"><span class="pre">run_tasks</span></code> 中实现。它循环调用 <code class="docutils literal notranslate"><span class="pre">fetch_task</span></code> 直到顺利从任务管理器中取出一个任务,然后获得
<code class="docutils literal notranslate"><span class="pre">__switch</span></code> 两个参数进行任务切换。注意在整个过程中要严格控制临界区。</p>
<p>当一个应用交出 CPU 使用权时,进入内核后它会调用 <code class="docutils literal notranslate"><span class="pre">schedule</span></code> 函数来切换到 idle 控制流并开启新一轮的任务调度。</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/task/processor.rs</span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">schedule</span><span class="p">(</span><span class="n">switched_task_cx_ptr</span>: <span class="o">*</span><span class="k">mut</span><span class="w"> </span><span class="n">TaskContext</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">processor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PROCESSOR</span><span class="p">.</span><span class="n">exclusive_access</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">idle_task_cx_ptr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">processor</span><span class="p">.</span><span class="n">get_idle_task_cx_ptr</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="nb">drop</span><span class="p">(</span><span class="n">processor</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">unsafe</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">__switch</span><span class="p">(</span><span class="n">switched_task_cx_ptr</span><span class="p">,</span><span class="w"> </span><span class="n">idle_task_cx_ptr</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>切换回去之后,我们将跳转到 <code class="docutils literal notranslate"><span class="pre">Processor::run</span></code><code class="docutils literal notranslate"><span class="pre">__switch</span></code> 返回之后的位置,也即开启了下一轮循环。</p>
</div>
</div>
</div>
</article>
<footer>
<div class="related-pages">
<a class="next-page" href="3implement-process-mechanism.html">
<div class="page-info">
<div class="context">
<span>Next</span>
</div>
<div class="title">进程管理机制的设计实现</div>
</div>
<svg><use href="#svg-arrow-right"></use></svg>
</a>
<a class="prev-page" href="1process.html">
<svg><use href="#svg-arrow-right"></use></svg>
<div class="page-info">
<div class="context">
<span>Previous</span>
</div>
<div class="title">与进程有关的重要系统调用</div>
</div>
</a>
</div>
<div class="related-information">
Copyright &#169; OS2022Summer
|
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a>
and
<a class="muted-link" href="https://pradyunsg.me">@pradyunsg</a>'s
<a href="https://github.com/pradyunsg/furo">Furo theme</a>.
|
<a class="muted-link" href="../_sources/chapter5/2core-data-structures.rst.txt"
rel="nofollow">
显示源代码
</a>
</div>
</footer>
</div>
<aside class="toc-drawer">
<div class="toc-sticky toc-scroll">
<div class="toc-title-container">
<span class="toc-title">
目录
</span>
</div>
<div class="toc-tree-container">
<div class="toc-tree">
<ul>
<li><a class="reference internal" href="#">进程管理的核心数据结构</a><ul>
<li><a class="reference internal" href="#id2">本节导读</a></li>
<li><a class="reference internal" href="#id3">基于应用名的应用链接/加载器</a></li>
<li><a class="reference internal" href="#id4">进程标识符和内核栈</a><ul>
<li><a class="reference internal" href="#id5">进程标识符</a></li>
<li><a class="reference internal" href="#id6">内核栈</a></li>
</ul>
</li>
<li><a class="reference internal" href="#id7">进程控制块</a></li>
<li><a class="reference internal" href="#id8">任务管理器</a></li>
<li><a class="reference internal" href="#id9">处理器管理结构</a><ul>
<li><a class="reference internal" href="#id10">正在执行的任务</a></li>
<li><a class="reference internal" href="#idle">任务调度的 idle 控制流</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</aside>
</div>
</div><script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/scripts/main.js"></script>
<script kind="utterances">
var commentsRunWhenDOMLoaded = cb => {
if (document.readyState != 'loading') {
cb()
} else if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', cb)
} else {
document.attachEvent('onreadystatechange', function() {
if (document.readyState == 'complete') cb()
})
}
}
var addUtterances = () => {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://utteranc.es/client.js";
script.async = "async";
script.setAttribute("repo", "LearningOS/rust-based-os-comp2022");
script.setAttribute("issue-term", "pathname");
script.setAttribute("theme", "github-light");
script.setAttribute("label", "comments");
script.setAttribute("crossorigin", "anonymous");
sections = document.querySelectorAll("div.section");
if (sections !== null) {
section = sections[sections.length-1];
section.appendChild(script);
}
}
commentsRunWhenDOMLoaded(addUtterances);
</script>
<script src="../_static/translations.js"></script>
</body>
</html>