Files
rust-based-os-comp2022/chapter5/3implement-process-mechanism.html
2022-06-30 04:46:48 +00:00

1025 lines
137 KiB
HTML
Raw 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="chapter5练习" href="4exercise.html" /><link rel="prev" title="进程管理的核心数据结构" href="2core-data-structures.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"><a class="reference internal" href="2core-data-structures.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="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>初始进程 <code class="docutils literal notranslate"><span class="pre">initproc</span></code> 的创建;</p></li>
<li><p>进程调度机制:当进程主动调用 <code class="docutils literal notranslate"><span class="pre">sys_yield</span></code> 交出 CPU 使用权,或者内核本轮分配的时间片用尽之后如何切换到下一个进程;</p></li>
<li><p>进程生成机制:介绍进程相关的两个重要系统调用 <code class="docutils literal notranslate"><span class="pre">sys_fork/sys_exec</span></code> 的实现;</p></li>
<li><p>字符输入机制:介绍 <code class="docutils literal notranslate"><span class="pre">sys_read</span></code> 系统调用的实现;</p></li>
<li><p>进程资源回收机制:当进程调用 <code class="docutils literal notranslate"><span class="pre">sys_exit</span></code> 正常退出或者出错被内核终止后,如何保存其退出码,其父进程又是如何通过
<code class="docutils literal notranslate"><span class="pre">sys_waitpid</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">task</span></code> 子模块提供的 <code class="docutils literal notranslate"><span class="pre">add_initproc</span></code> 函数来将初始进程 <code class="docutils literal notranslate"><span class="pre">initproc</span></code>
加入任务管理器,但在这之前,我们需要初始进程的进程控制块 <code class="docutils literal notranslate"><span class="pre">INITPROC</span></code> ,这基于 <code class="docutils literal notranslate"><span class="pre">lazy_static</span></code> 在运行时完成。</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/task/mod.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">INITPROC</span>: <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="o">=</span><span class="w"> </span><span class="n">Arc</span>::<span class="n">new</span><span class="p">(</span><span class="n">TaskControlBlock</span>::<span class="n">new</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="n">get_app_data_by_name</span><span class="p">(</span><span class="s">"initproc"</span><span class="p">).</span><span class="n">unwrap</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="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">add_initproc</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">add_task</span><span class="p">(</span><span class="n">INITPROC</span><span class="p">.</span><span class="n">clone</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::new</span></code> 来创建一个进程控制块,它需要传入 ELF 可执行文件的数据切片作为参数,
这可以通过加载器 <code class="docutils literal notranslate"><span class="pre">loader</span></code> 子模块提供的 <code class="docutils literal notranslate"><span class="pre">get_app_data_by_name</span></code> 接口查找 <code class="docutils literal notranslate"><span class="pre">initproc</span></code> 的 ELF 数据来获得。在初始化
<code class="docutils literal notranslate"><span class="pre">INITPROC</span></code> 之后,则在 <code class="docutils literal notranslate"><span class="pre">add_initproc</span></code> 中可以调用 <code class="docutils literal notranslate"><span class="pre">task</span></code> 的任务管理器 <code class="docutils literal notranslate"><span class="pre">manager</span></code> 子模块提供的 <code class="docutils literal notranslate"><span class="pre">add_task</span></code> 接口将其加入到任务管理器。</p>
<p>接下来介绍 <code class="docutils literal notranslate"><span class="pre">TaskControlBlock::new</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">use</span><span class="w"> </span><span class="k">super</span>::<span class="p">{</span><span class="n">PidHandle</span><span class="p">,</span><span class="w"> </span><span class="n">pid_alloc</span><span class="p">,</span><span class="w"> </span><span class="n">KernelStack</span><span class="p">};</span><span class="w"></span>
<span class="linenos"> 4</span><span class="k">use</span><span class="w"> </span><span class="k">super</span>::<span class="n">TaskContext</span><span class="p">;</span><span class="w"></span>
<span class="linenos"> 5</span><span class="k">use</span><span class="w"> </span><span class="k">crate</span>::<span class="n">config</span>::<span class="n">TRAP_CONTEXT</span><span class="p">;</span><span class="w"></span>
<span class="linenos"> 6</span><span class="k">use</span><span class="w"> </span><span class="k">crate</span>::<span class="n">trap</span>::<span class="n">TrapContext</span><span class="p">;</span><span class="w"></span>
<span class="linenos"> 7</span>
<span class="linenos"> 8</span><span class="c1">// impl TaskControlBlock</span>
<span class="linenos"> 9</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="w"></span>
<span class="linenos">10</span><span class="w"> </span><span class="c1">// memory_set with elf program headers/trampoline/trap context/user stack</span>
<span class="linenos">11</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="p">(</span><span class="n">memory_set</span><span class="p">,</span><span class="w"> </span><span class="n">user_sp</span><span class="p">,</span><span class="w"> </span><span class="n">entry_point</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MemorySet</span>::<span class="n">from_elf</span><span class="p">(</span><span class="n">elf_data</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">trap_cx_ppn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">memory_set</span><span class="w"></span>
<span class="linenos">13</span><span class="w"> </span><span class="p">.</span><span class="n">translate</span><span class="p">(</span><span class="n">VirtAddr</span>::<span class="n">from</span><span class="p">(</span><span class="n">TRAP_CONTEXT</span><span class="p">).</span><span class="n">into</span><span class="p">())</span><span class="w"></span>
<span class="linenos">14</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">15</span><span class="w"> </span><span class="p">.</span><span class="n">ppn</span><span class="p">();</span><span class="w"></span>
<span class="linenos">16</span><span class="w"> </span><span class="c1">// alloc a pid and a kernel stack in kernel space</span>
<span class="linenos">17</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">pid_handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pid_alloc</span><span class="p">();</span><span class="w"></span>
<span class="linenos">18</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">kernel_stack</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">KernelStack</span>::<span class="n">new</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pid_handle</span><span class="p">);</span><span class="w"></span>
<span class="linenos">19</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="n">kernel_stack</span><span class="p">.</span><span class="n">get_top</span><span class="p">();</span><span class="w"></span>
<span class="linenos">20</span><span class="w"> </span><span class="c1">// push a task context which goes to trap_return to the top of kernel stack</span>
<span class="linenos">21</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">task_cx_ptr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">kernel_stack</span><span class="p">.</span><span class="n">push_on_top</span><span class="p">(</span><span class="n">TaskContext</span>::<span class="n">goto_trap_return</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">task_control_block</span><span class="w"> </span><span class="o">=</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">23</span><span class="w"> </span><span class="n">pid</span>: <span class="nc">pid_handle</span><span class="p">,</span><span class="w"></span>
<span class="linenos">24</span><span class="w"> </span><span class="n">kernel_stack</span><span class="p">,</span><span class="w"></span>
<span class="linenos">25</span><span class="w"> </span><span class="n">inner</span>: <span class="nc">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">TaskControlBlockInner</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">26</span><span class="w"> </span><span class="n">trap_cx_ppn</span><span class="p">,</span><span class="w"></span>
<span class="linenos">27</span><span class="w"> </span><span class="n">base_size</span>: <span class="nc">user_sp</span><span class="p">,</span><span class="w"></span>
<span class="linenos">28</span><span class="w"> </span><span class="n">task_cx</span>: <span class="nc">TaskContext</span>::<span class="n">goto_trap_return</span><span class="p">(</span><span class="n">kernel_stack_top</span><span class="p">),</span><span class="w"></span>
<span class="linenos">29</span><span class="w"> </span><span class="n">task_status</span>: <span class="nc">TaskStatus</span>::<span class="n">Ready</span><span class="p">,</span><span class="w"></span>
<span class="linenos">30</span><span class="w"> </span><span class="n">memory_set</span><span class="p">,</span><span class="w"></span>
<span class="linenos">31</span><span class="w"> </span><span class="n">parent</span>: <span class="nb">None</span><span class="p">,</span><span class="w"></span>
<span class="linenos">32</span><span class="w"> </span><span class="n">children</span>: <span class="nb">Vec</span>::<span class="n">new</span><span class="p">(),</span><span class="w"></span>
<span class="linenos">33</span><span class="w"> </span><span class="n">exit_code</span>: <span class="mi">0</span><span class="p">,</span><span class="w"></span>
<span class="linenos">34</span><span class="w"> </span><span class="p">})</span><span class="w"></span>
<span class="linenos">35</span><span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="linenos">36</span><span class="w"> </span><span class="p">};</span><span class="w"></span>
<span class="linenos">37</span><span class="w"> </span><span class="c1">// prepare TrapContext in user space</span>
<span class="linenos">38</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">trap_cx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">task_control_block</span><span class="p">.</span><span class="n">inner_exclusive_access</span><span class="p">().</span><span class="n">get_trap_cx</span><span class="p">();</span><span class="w"></span>
<span class="linenos">39</span><span class="w"> </span><span class="o">*</span><span class="n">trap_cx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">TrapContext</span>::<span class="n">app_init_context</span><span class="p">(</span><span class="w"></span>
<span class="linenos">40</span><span class="w"> </span><span class="n">entry_point</span><span class="p">,</span><span class="w"></span>
<span class="linenos">41</span><span class="w"> </span><span class="n">user_sp</span><span class="p">,</span><span class="w"></span>
<span class="linenos">42</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">token</span><span class="p">(),</span><span class="w"></span>
<span class="linenos">43</span><span class="w"> </span><span class="n">kernel_stack_top</span><span class="p">,</span><span class="w"></span>
<span class="linenos">44</span><span class="w"> </span><span class="n">trap_handler</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="linenos">45</span><span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="linenos">46</span><span class="w"> </span><span class="n">task_control_block</span><span class="w"></span>
<span class="linenos">47</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<ul class="simple">
<li><p>第 10 行,解析 ELF 得到应用地址空间 <code class="docutils literal notranslate"><span class="pre">memory_set</span></code> ,用户栈在应用地址空间中的位置 <code class="docutils literal notranslate"><span class="pre">user_sp</span></code> 以及应用的入口点 <code class="docutils literal notranslate"><span class="pre">entry_point</span></code></p></li>
<li><p>第 11 行,手动查页表找到应用地址空间中的 Trap 上下文实际所在的物理页帧。</p></li>
<li><p>第 16~18 行,为新进程分配 PID 以及内核栈,并记录下内核栈在内核地址空间的位置 <code class="docutils literal notranslate"><span class="pre">kernel_stack_top</span></code></p></li>
<li><p>第 20 行,在该进程的内核栈上压入初始化的任务上下文,使得第一次任务切换到它的时候可以跳转到 <code class="docutils literal notranslate"><span class="pre">trap_return</span></code> 并进入用户态开始执行。</p></li>
<li><p>第 21 行,整合之前的部分信息创建进程控制块 <code class="docutils literal notranslate"><span class="pre">task_control_block</span></code></p></li>
<li><p>第 39 行,初始化位于该进程应用地址空间中的 Trap 上下文,使得第一次进入用户态时,能正确跳转到应用入口点并设置好用户栈,
同时也保证在 Trap 的时候用户态能正确进入内核态。</p></li>
</ul>
</div>
<div class="section" id="id4">
<h2>进程调度机制<a class="headerlink" href="#id4" title="永久链接至标题"></a></h2>
<p>调用 <code class="docutils literal notranslate"><span class="pre">task</span></code> 子模块提供的 <code class="docutils literal notranslate"><span class="pre">suspend_current_and_run_next</span></code> 函数可以暂停当前任务,并切换到下一个任务,下面给出了两种典型的使用场景:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/syscall/process.rs</span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">sys_yield</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="kt">isize</span> <span class="p">{</span><span class="w"></span>
<span class="hll"><span class="w"> </span><span class="n">suspend_current_and_run_next</span><span class="p">();</span><span class="w"></span>
</span><span class="w"> </span><span class="mi">0</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="c1">// os/src/trap/mod.rs</span>
<span class="cp">#[no_mangle]</span><span class="w"></span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">trap_handler</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">set_kernel_trap_entry</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">scause</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">scause</span>::<span class="n">read</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">stval</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">stval</span>::<span class="n">read</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">scause</span><span class="p">.</span><span class="n">cause</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">Trap</span>::<span class="n">Interrupt</span><span class="p">(</span><span class="n">Interrupt</span>::<span class="n">SupervisorTimer</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">set_next_trigger</span><span class="p">();</span><span class="w"></span>
<span class="hll"><span class="w"> </span><span class="n">suspend_current_and_run_next</span><span class="p">();</span><span class="w"></span>
</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="o">..</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">trap_return</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">suspend_current_and_run_next</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/mod.rs</span>
<span class="linenos"> 2</span>
<span class="linenos"> 3</span><span class="k">use</span><span class="w"> </span><span class="n">processor</span>::<span class="p">{</span><span class="n">task_current_task</span><span class="p">,</span><span class="w"> </span><span class="n">schedule</span><span class="p">};</span><span class="w"></span>
<span class="linenos"> 4</span><span class="k">use</span><span class="w"> </span><span class="n">manager</span>::<span class="n">add_task</span><span class="p">;</span><span class="w"></span>
<span class="linenos"> 5</span>
<span class="linenos"> 6</span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">suspend_current_and_run_next</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos"> 7</span><span class="w"> </span><span class="c1">// There must be an application running.</span>
<span class="linenos"> 8</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">take_current_task</span><span class="p">().</span><span class="n">unwrap</span><span class="p">();</span><span class="w"></span>
<span class="linenos"> 9</span>
<span class="linenos">10</span><span class="w"> </span><span class="c1">// ---- access current TCB exclusively</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">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">12</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">task_cx_ptr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </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">mut</span><span class="w"> </span><span class="n">TaskContext</span><span class="p">;</span><span class="w"></span>
<span class="linenos">13</span><span class="w"> </span><span class="c1">// Change status to Ready</span>
<span class="linenos">14</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">Ready</span><span class="p">;</span><span class="w"></span>
<span class="linenos">15</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">16</span><span class="w"> </span><span class="c1">// ---- release current PCB</span>
<span class="linenos">17</span>
<span class="linenos">18</span><span class="w"> </span><span class="c1">// push back to ready queue.</span>
<span class="linenos">19</span><span class="w"> </span><span class="n">add_task</span><span class="p">(</span><span class="n">task</span><span class="p">);</span><span class="w"></span>
<span class="linenos">20</span><span class="w"> </span><span class="c1">// jump to scheduling cycle</span>
<span class="linenos">21</span><span class="w"> </span><span class="n">schedule</span><span class="p">(</span><span class="n">task_cx_ptr</span><span class="p">);</span><span class="w"></span>
<span class="linenos">22</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>首先通过 <code class="docutils literal notranslate"><span class="pre">take_current_task</span></code> 来取出当前正在执行的任务,修改其进程控制块内的状态,随后将这个任务放入任务管理器的队尾。接着调用
<code class="docutils literal notranslate"><span class="pre">schedule</span></code> 函数来触发调度并切换任务。当仅有一个任务的时候, <code class="docutils literal notranslate"><span class="pre">suspend_current_and_run_next</span></code> 的效果是会继续执行这个任务。</p>
</div>
<div class="section" id="id5">
<h2>进程的生成机制<a class="headerlink" href="#id5" title="永久链接至标题"></a></h2>
<div class="section" id="fork">
<h3>fork 系统调用的实现<a class="headerlink" href="#fork" title="永久链接至标题"></a></h3>
<p>实现 fork 时,最为关键且困难一点的是为子进程创建一个和父进程几乎完全相同的地址空间。我们的实现如下:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// os/src/mm/memory_set.rs</span>
<span class="linenos"> 2</span>
<span class="linenos"> 3</span><span class="k">impl</span><span class="w"> </span><span class="n">MapArea</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">from_another</span><span class="p">(</span><span class="n">another</span>: <span class="kp">&amp;</span><span class="nc">MapArea</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"> 5</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"> 6</span><span class="w"> </span><span class="n">vpn_range</span>: <span class="nc">VPNRange</span>::<span class="n">new</span><span class="p">(</span><span class="w"></span>
<span class="linenos"> 7</span><span class="w"> </span><span class="n">another</span><span class="p">.</span><span class="n">vpn_range</span><span class="p">.</span><span class="n">get_start</span><span class="p">(),</span><span class="w"></span>
<span class="linenos"> 8</span><span class="w"> </span><span class="n">another</span><span class="p">.</span><span class="n">vpn_range</span><span class="p">.</span><span class="n">get_end</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="w"> </span><span class="n">data_frames</span>: <span class="nc">BTreeMap</span>::<span class="n">new</span><span class="p">(),</span><span class="w"></span>
<span class="linenos">11</span><span class="w"> </span><span class="n">map_type</span>: <span class="nc">another</span><span class="p">.</span><span class="n">map_type</span><span class="p">,</span><span class="w"></span>
<span class="linenos">12</span><span class="w"> </span><span class="n">map_perm</span>: <span class="nc">another</span><span class="p">.</span><span class="n">map_perm</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="p">}</span><span class="w"></span>
<span class="linenos">15</span><span class="p">}</span><span class="w"></span>
<span class="linenos">16</span>
<span class="linenos">17</span><span class="k">impl</span><span class="w"> </span><span class="n">MemorySet</span><span class="w"> </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="k">fn</span> <span class="nf">from_existed_user</span><span class="p">(</span><span class="n">user_space</span>: <span class="kp">&amp;</span><span class="nc">MemorySet</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">MemorySet</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">19</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">memory_set</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">Self</span>::<span class="n">new_bare</span><span class="p">();</span><span class="w"></span>
<span class="linenos">20</span><span class="w"> </span><span class="c1">// map trampoline</span>
<span class="linenos">21</span><span class="w"> </span><span class="n">memory_set</span><span class="p">.</span><span class="n">map_trampoline</span><span class="p">();</span><span class="w"></span>
<span class="linenos">22</span><span class="w"> </span><span class="c1">// copy data sections/trap_context/user_stack</span>
<span class="linenos">23</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">area</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">user_space</span><span class="p">.</span><span class="n">areas</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="linenos">24</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">new_area</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MapArea</span>::<span class="n">from_another</span><span class="p">(</span><span class="n">area</span><span class="p">);</span><span class="w"></span>
<span class="linenos">25</span><span class="w"> </span><span class="n">memory_set</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">new_area</span><span class="p">,</span><span class="w"> </span><span class="nb">None</span><span class="p">);</span><span class="w"></span>
<span class="linenos">26</span><span class="w"> </span><span class="c1">// copy data from another space</span>
<span class="linenos">27</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">vpn</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">area</span><span class="p">.</span><span class="n">vpn_range</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">28</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">src_ppn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">user_space</span><span class="p">.</span><span class="n">translate</span><span class="p">(</span><span class="n">vpn</span><span class="p">).</span><span class="n">unwrap</span><span class="p">().</span><span class="n">ppn</span><span class="p">();</span><span class="w"></span>
<span class="linenos">29</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">dst_ppn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">memory_set</span><span class="p">.</span><span class="n">translate</span><span class="p">(</span><span class="n">vpn</span><span class="p">).</span><span class="n">unwrap</span><span class="p">().</span><span class="n">ppn</span><span class="p">();</span><span class="w"></span>
<span class="linenos">30</span><span class="w"> </span><span class="n">dst_ppn</span><span class="p">.</span><span class="n">get_bytes_array</span><span class="p">().</span><span class="n">copy_from_slice</span><span class="p">(</span><span class="n">src_ppn</span><span class="p">.</span><span class="n">get_bytes_array</span><span class="p">());</span><span class="w"></span>
<span class="linenos">31</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">32</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">33</span><span class="w"> </span><span class="n">memory_set</span><span class="w"></span>
<span class="linenos">34</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">35</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>这需要对内存管理子模块 <code class="docutils literal notranslate"><span class="pre">mm</span></code> 做一些拓展:</p>
<ul>
<li><p>第 4 行的 <code class="docutils literal notranslate"><span class="pre">MapArea::from_another</span></code> 可以从一个逻辑段复制得到一个虚拟地址区间、映射方式和权限控制均相同的逻辑段,
不同的是由于它还没有真正被映射到物理页帧上,所以 <code class="docutils literal notranslate"><span class="pre">data_frames</span></code> 字段为空。</p></li>
<li><p>第 18 行的 <code class="docutils literal notranslate"><span class="pre">MemorySet::from_existed_user</span></code> 可以复制一个完全相同的地址空间。首先在第 19 行,我们通过 <code class="docutils literal notranslate"><span class="pre">new_bare</span></code>
新创建一个空的地址空间,并在第 21 行通过 <code class="docutils literal notranslate"><span class="pre">map_trampoline</span></code> 为这个地址空间映射上跳板页面,这是因为我们解析 ELF
创建地址空间的时候,并没有将跳板页作为一个单独的逻辑段插入到地址空间的逻辑段向量 <code class="docutils literal notranslate"><span class="pre">areas</span></code> 中,所以这里需要单独映射上。</p>
<p>剩下的逻辑段都包含在 <code class="docutils literal notranslate"><span class="pre">areas</span></code> 中。我们遍历原地址空间中的所有逻辑段,将复制之后的逻辑段插入新的地址空间,
在插入的时候就已经实际分配了物理页帧了。接着我们遍历逻辑段中的每个虚拟页面,对应完成数据复制,
这只需要找出两个地址空间中的虚拟页面各被映射到哪个物理页帧,就可转化为将数据从物理内存中的一个位置复制到另一个位置,使用
<code class="docutils literal notranslate"><span class="pre">copy_from_slice</span></code> 即可轻松实现。</p>
</li>
</ul>
<p>接着,我们实现 <code class="docutils literal notranslate"><span class="pre">TaskControlBlock::fork</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">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="linenos"> 4</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="w"></span>
<span class="linenos"> 5</span><span class="w"> </span><span class="c1">// ---- access parent PCB exclusively</span>
<span class="linenos"> 6</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">parent_inner</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">inner_exclusive_access</span><span class="p">();</span><span class="w"></span>
<span class="linenos"> 7</span><span class="w"> </span><span class="c1">// copy user space(include trap context)</span>
<span class="linenos"> 8</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">memory_set</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MemorySet</span>::<span class="n">from_existed_user</span><span class="p">(</span><span class="o">&amp;</span><span class="n">parent_inner</span><span class="p">.</span><span class="n">memory_set</span><span class="p">);</span><span class="w"></span>
<span class="linenos"> 9</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">trap_cx_ppn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">memory_set</span><span class="w"></span>
<span class="linenos">10</span><span class="w"> </span><span class="p">.</span><span class="n">translate</span><span class="p">(</span><span class="n">VirtAddr</span>::<span class="n">from</span><span class="p">(</span><span class="n">TRAP_CONTEXT</span><span class="p">).</span><span class="n">into</span><span class="p">())</span><span class="w"></span>
<span class="linenos">11</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">12</span><span class="w"> </span><span class="p">.</span><span class="n">ppn</span><span class="p">();</span><span class="w"></span>
<span class="linenos">13</span><span class="w"> </span><span class="c1">// alloc a pid and a kernel stack in kernel space</span>
<span class="linenos">14</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">pid_handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pid_alloc</span><span class="p">();</span><span class="w"></span>
<span class="linenos">15</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">kernel_stack</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">KernelStack</span>::<span class="n">new</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pid_handle</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">kernel_stack_top</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">kernel_stack</span><span class="p">.</span><span class="n">get_top</span><span class="p">();</span><span class="w"></span>
<span class="linenos">17</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">task_control_block</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Arc</span>::<span class="n">new</span><span class="p">(</span><span class="n">TaskControlBlock</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">18</span><span class="w"> </span><span class="n">pid</span>: <span class="nc">pid_handle</span><span class="p">,</span><span class="w"></span>
<span class="linenos">19</span><span class="w"> </span><span class="n">kernel_stack</span><span class="p">,</span><span class="w"></span>
<span class="linenos">20</span><span class="w"> </span><span class="n">inner</span>: <span class="nc">unsafe</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">21</span><span class="w"> </span><span class="n">UPSafeCell</span>::<span class="n">new</span><span class="p">(</span><span class="n">TaskControlBlockInner</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">22</span><span class="w"> </span><span class="n">trap_cx_ppn</span><span class="p">,</span><span class="w"></span>
<span class="linenos">23</span><span class="w"> </span><span class="n">base_size</span>: <span class="nc">parent_inner</span><span class="p">.</span><span class="n">base_size</span><span class="p">,</span><span class="w"></span>
<span class="linenos">24</span><span class="w"> </span><span class="n">task_cx</span>: <span class="nc">TaskContext</span>::<span class="n">goto_trap_return</span><span class="p">(</span><span class="n">kernel_stack_top</span><span class="p">),</span><span class="w"></span>
<span class="linenos">25</span><span class="w"> </span><span class="n">task_status</span>: <span class="nc">TaskStatus</span>::<span class="n">Ready</span><span class="p">,</span><span class="w"></span>
<span class="linenos">26</span><span class="w"> </span><span class="n">memory_set</span><span class="p">,</span><span class="w"></span>
<span class="linenos">27</span><span class="w"> </span><span class="n">parent</span>: <span class="nb">Some</span><span class="p">(</span><span class="n">Arc</span>::<span class="n">downgrade</span><span class="p">(</span><span class="bp">self</span><span class="p">)),</span><span class="w"></span>
<span class="linenos">28</span><span class="w"> </span><span class="n">children</span>: <span class="nb">Vec</span>::<span class="n">new</span><span class="p">(),</span><span class="w"></span>
<span class="linenos">29</span><span class="w"> </span><span class="n">exit_code</span>: <span class="mi">0</span><span class="p">,</span><span class="w"></span>
<span class="linenos">30</span><span class="w"> </span><span class="p">})</span><span class="w"></span>
<span class="linenos">31</span><span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="linenos">32</span><span class="w"> </span><span class="p">});</span><span class="w"></span>
<span class="linenos">33</span><span class="w"> </span><span class="c1">// add child</span>
<span class="linenos">34</span><span class="w"> </span><span class="n">parent_inner</span><span class="p">.</span><span class="n">children</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">task_control_block</span><span class="p">.</span><span class="n">clone</span><span class="p">());</span><span class="w"></span>
<span class="linenos">35</span><span class="w"> </span><span class="c1">// modify kernel_sp in trap_cx</span>
<span class="linenos">36</span><span class="w"> </span><span class="c1">// **** access children PCB exclusively</span>
<span class="linenos">37</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">trap_cx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">task_control_block</span><span class="p">.</span><span class="n">inner_exclusive_access</span><span class="p">().</span><span class="n">get_trap_cx</span><span class="p">();</span><span class="w"></span>
<span class="linenos">38</span><span class="w"> </span><span class="n">trap_cx</span><span class="p">.</span><span class="n">kernel_sp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">kernel_stack_top</span><span class="p">;</span><span class="w"></span>
<span class="linenos">39</span><span class="w"> </span><span class="c1">// return</span>
<span class="linenos">40</span><span class="w"> </span><span class="n">task_control_block</span><span class="w"></span>
<span class="linenos">41</span><span class="w"> </span><span class="c1">// ---- release parent PCB automatically</span>
<span class="linenos">42</span><span class="w"> </span><span class="c1">// **** release children PCB automatically</span>
<span class="linenos">43</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">44</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>它基本上和新建进程控制块的 <code class="docutils literal notranslate"><span class="pre">TaskControlBlock::new</span></code> 是相同的,但要注意以下几点:</p>
<ul class="simple">
<li><p>子进程的地址空间不是通过解析 ELF而是通过在第 8 行调用 <code class="docutils literal notranslate"><span class="pre">MemorySet::from_existed_user</span></code> 复制父进程地址空间得到的;</p></li>
<li><p>在 fork 的时候需要注意父子进程关系的维护。既要将父进程的弱引用计数放到子进程的进程控制块中,又要将子进程插入到父进程的孩子向量 <code class="docutils literal notranslate"><span class="pre">children</span></code> 中。</p></li>
</ul>
<p>实现 <code class="docutils literal notranslate"><span class="pre">sys_fork</span></code> 时,我们需要特别注意如何体现父子进程的差异:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// os/src/syscall/process.rs</span>
<span class="linenos"> 2</span>
<span class="linenos"> 3</span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">sys_fork</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="kt">isize</span> <span class="p">{</span><span class="w"></span>
<span class="linenos"> 4</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">current_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"> 5</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">new_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">fork</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">new_pid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">new_task</span><span class="p">.</span><span class="n">pid</span><span class="p">.</span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="linenos"> 7</span><span class="w"> </span><span class="c1">// modify trap context of new_task, because it returns immediately after switching</span>
<span class="linenos"> 8</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">trap_cx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">new_task</span><span class="p">.</span><span class="n">inner_exclusive_access</span><span class="p">().</span><span class="n">get_trap_cx</span><span class="p">();</span><span class="w"></span>
<span class="linenos"> 9</span><span class="w"> </span><span class="c1">// we do not have to move to next instruction since we have done it before</span>
<span class="linenos">10</span><span class="w"> </span><span class="c1">// for child process, fork returns 0</span>
<span class="linenos">11</span><span class="w"> </span><span class="n">trap_cx</span><span class="p">.</span><span class="n">x</span><span class="p">[</span><span class="mi">10</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="linenos">12</span><span class="w"> </span><span class="c1">// add new task to scheduler</span>
<span class="linenos">13</span><span class="w"> </span><span class="n">add_task</span><span class="p">(</span><span class="n">new_task</span><span class="p">);</span><span class="w"></span>
<span class="linenos">14</span><span class="w"> </span><span class="n">new_pid</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">isize</span><span class="w"></span>
<span class="linenos">15</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>在调用 <code class="docutils literal notranslate"><span class="pre">sys_fork</span></code> 之前,我们已经将当前进程 Trap 上下文中的 sepc 向后移动了 4 字节,使得它回到用户态之后会从 ecall
的下一条指令开始执行。之后,当我们复制地址空间时,子进程地址空间 Trap 上下文的 sepc 也是移动之后的值,我们无需再进行修改。</p>
<p>父子进程回到用户态的瞬间都处于刚刚从一次系统调用返回的状态,但二者返回值不同。第 8~11 行我们将子进程的 Trap
上下文中用来存放系统调用返回值的 a0 寄存器修改为 0 ,而父进程系统调用的返回值会在 <code class="docutils literal notranslate"><span class="pre">syscall</span></code> 返回之后再设置为 <code class="docutils literal notranslate"><span class="pre">sys_fork</span></code>
的返回值。这就做到了父进程 <code class="docutils literal notranslate"><span class="pre">fork</span></code> 的返回值为子进程的 PID ,而子进程的返回值为 0。</p>
</div>
<div class="section" id="exec">
<h3>exec 系统调用的实现<a class="headerlink" href="#exec" title="永久链接至标题"></a></h3>
<p><code class="docutils literal notranslate"><span class="pre">exec</span></code> 系统调用使得一个进程能够加载一个新的 ELF 可执行文件替换原有的应用地址空间并开始执行。我们先从进程控制块的层面进行修改:</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">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="linenos"> 4</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="w"></span>
<span class="linenos"> 5</span><span class="w"> </span><span class="c1">// memory_set with elf program headers/trampoline/trap context/user stack</span>
<span class="linenos"> 6</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="p">(</span><span class="n">memory_set</span><span class="p">,</span><span class="w"> </span><span class="n">user_sp</span><span class="p">,</span><span class="w"> </span><span class="n">entry_point</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MemorySet</span>::<span class="n">from_elf</span><span class="p">(</span><span class="n">elf_data</span><span class="p">);</span><span class="w"></span>
<span class="linenos"> 7</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">trap_cx_ppn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">memory_set</span><span class="w"></span>
<span class="linenos"> 8</span><span class="w"> </span><span class="p">.</span><span class="n">translate</span><span class="p">(</span><span class="n">VirtAddr</span>::<span class="n">from</span><span class="p">(</span><span class="n">TRAP_CONTEXT</span><span class="p">).</span><span class="n">into</span><span class="p">())</span><span class="w"></span>
<span class="linenos"> 9</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">10</span><span class="w"> </span><span class="p">.</span><span class="n">ppn</span><span class="p">();</span><span class="w"></span>
<span class="linenos">11</span>
<span class="linenos">12</span><span class="w"> </span><span class="c1">// **** access inner exclusively</span>
<span class="linenos">13</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">inner</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">inner_exclusive_access</span><span class="p">();</span><span class="w"></span>
<span class="linenos">14</span><span class="w"> </span><span class="c1">// substitute memory_set</span>
<span class="linenos">15</span><span class="w"> </span><span class="n">inner</span><span class="p">.</span><span class="n">memory_set</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">memory_set</span><span class="p">;</span><span class="w"></span>
<span class="linenos">16</span><span class="w"> </span><span class="c1">// update trap_cx ppn</span>
<span class="linenos">17</span><span class="w"> </span><span class="n">inner</span><span class="p">.</span><span class="n">trap_cx_ppn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">trap_cx_ppn</span><span class="p">;</span><span class="w"></span>
<span class="linenos">18</span><span class="w"> </span><span class="c1">// initialize trap_cx</span>
<span class="linenos">19</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">trap_cx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">inner</span><span class="p">.</span><span class="n">get_trap_cx</span><span class="p">();</span><span class="w"></span>
<span class="linenos">20</span><span class="w"> </span><span class="o">*</span><span class="n">trap_cx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">TrapContext</span>::<span class="n">app_init_context</span><span class="p">(</span><span class="w"></span>
<span class="linenos">21</span><span class="w"> </span><span class="n">entry_point</span><span class="p">,</span><span class="w"></span>
<span class="linenos">22</span><span class="w"> </span><span class="n">user_sp</span><span class="p">,</span><span class="w"></span>
<span class="linenos">23</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">token</span><span class="p">(),</span><span class="w"></span>
<span class="linenos">24</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">kernel_stack</span><span class="p">.</span><span class="n">get_top</span><span class="p">(),</span><span class="w"></span>
<span class="linenos">25</span><span class="w"> </span><span class="n">trap_handler</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="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="c1">// **** release inner automatically</span>
<span class="linenos">28</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">29</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>它在解析传入的 ELF 格式数据之后只做了两件事情:</p>
<ul class="simple">
<li><p>首先从 ELF 生成一个全新的地址空间并直接替换进来(第 15 行),这将导致原有地址空间生命周期结束,里面包含的全部物理页帧都会被回收;</p></li>
<li><p>然后修改新的地址空间中的 Trap 上下文,将解析得到的应用入口点、用户栈位置以及一些内核的信息进行初始化,这样才能正常实现 Trap 机制。</p></li>
</ul>
<p><code class="docutils literal notranslate"><span class="pre">sys_exec</span></code> 的实现如下,它调用 <code class="docutils literal notranslate"><span class="pre">translated_str</span></code> 找到要执行的应用名,并试图从应用加载器提供的 <code class="docutils literal notranslate"><span class="pre">get_app_data_by_name</span></code>
接口中获取对应的 ELF 数据,如果找到的话就调用 <code class="docutils literal notranslate"><span class="pre">TaskControlBlock::exec</span></code> 替换地址空间。</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/syscall/process.rs</span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">sys_exec</span><span class="p">(</span><span class="n">path</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>-&gt; <span class="kt">isize</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">token</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">current_user_token</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">path</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">translated_str</span><span class="p">(</span><span class="n">token</span><span class="p">,</span><span class="w"> </span><span class="n">path</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">data</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">get_app_data_by_name</span><span class="p">(</span><span class="n">path</span><span class="p">.</span><span class="n">as_str</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="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="w"> </span><span class="n">task</span><span class="p">.</span><span class="n">exec</span><span class="p">(</span><span class="n">data</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="mi">0</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="o">-</span><span class="mi">1</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">sys_exec</span></code> 系统调用中传递给内核的只有一个应用名字符串在用户地址空间中的首地址,内核必限手动查页表来获得字符串的值。</p>
<p><code class="docutils literal notranslate"><span class="pre">translated_str</span></code> 用来从用户地址空间中查找字符串,其原理就是逐字节查页表直到发现一个 <code class="docutils literal notranslate"><span class="pre">\0</span></code> 为止。为什么要逐字节查页表?
因为内核不知道字符串的长度,且字符串可能是跨物理页的。</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/mm/page_table.rs</span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">translated_str</span><span class="p">(</span><span class="n">token</span>: <span class="kt">usize</span><span class="p">,</span><span class="w"> </span><span class="n">ptr</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>-&gt; <span class="nb">String</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">page_table</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PageTable</span>::<span class="n">from_token</span><span class="p">(</span><span class="n">token</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">string</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span>::<span class="n">new</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">va</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ptr</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="k">loop</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">ch</span>: <span class="kt">u8</span> <span class="o">=</span><span class="w"> </span><span class="o">*</span><span class="p">(</span><span class="n">page_table</span><span class="p">.</span><span class="n">translate_va</span><span class="p">(</span><span class="n">VirtAddr</span>::<span class="n">from</span><span class="p">(</span><span class="n">va</span><span class="p">)).</span><span class="n">unwrap</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="k">if</span><span class="w"> </span><span class="n">ch</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">break</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="n">string</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">ch</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">char</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">va</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="n">string</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
</div>
<div class="section" id="trap">
<h3>系统调用后重新获取 Trap 上下文<a class="headerlink" href="#trap" title="永久链接至标题"></a></h3>
<p>原来在 <code class="docutils literal notranslate"><span class="pre">trap_handler</span></code> 中我们是这样处理系统调用的:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/trap/mod.rs</span>
<span class="cp">#[no_mangle]</span><span class="w"></span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">trap_handler</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">set_kernel_trap_entry</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">cx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">current_trap_cx</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">scause</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">scause</span>::<span class="n">read</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">stval</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">stval</span>::<span class="n">read</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">scause</span><span class="p">.</span><span class="n">cause</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">Trap</span>::<span class="n">Exception</span><span class="p">(</span><span class="n">Exception</span>::<span class="n">UserEnvCall</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">cx</span><span class="p">.</span><span class="n">sepc</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">4</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">cx</span><span class="p">.</span><span class="n">x</span><span class="p">[</span><span class="mi">10</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">syscall</span><span class="p">(</span><span class="n">cx</span><span class="p">.</span><span class="n">x</span><span class="p">[</span><span class="mi">17</span><span class="p">],</span><span class="w"> </span><span class="p">[</span><span class="n">cx</span><span class="p">.</span><span class="n">x</span><span class="p">[</span><span class="mi">10</span><span class="p">],</span><span class="w"> </span><span class="n">cx</span><span class="p">.</span><span class="n">x</span><span class="p">[</span><span class="mi">11</span><span class="p">],</span><span class="w"> </span><span class="n">cx</span><span class="p">.</span><span class="n">x</span><span class="p">[</span><span class="mi">12</span><span class="p">]])</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="p">}</span><span class="w"></span>
<span class="w"> </span><span class="o">..</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">trap_return</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">cx</span></code> 是当前应用的 Trap 上下文的可变引用,我们需要通过查页表找到它具体被放在哪个物理页帧上,
并构造相同的虚拟地址来在内核中访问它。对于系统调用 <code class="docutils literal notranslate"><span class="pre">sys_exec</span></code> 来说,调用它之后, <code class="docutils literal notranslate"><span class="pre">trap_handler</span></code>
原来上下文中的 <code class="docutils literal notranslate"><span class="pre">cx</span></code> 失效了,因为它是就原来的地址空间而言的。为了能够处理类似的这种情况,我们在 <code class="docutils literal notranslate"><span class="pre">syscall</span></code>
返回之后需要重新获取 <code class="docutils literal notranslate"><span class="pre">cx</span></code> ,目前的实现如下:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/trap/mod.rs</span>
<span class="cp">#[no_mangle]</span><span class="w"></span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">trap_handler</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">set_kernel_trap_entry</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">scause</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">scause</span>::<span class="n">read</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">stval</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">stval</span>::<span class="n">read</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">scause</span><span class="p">.</span><span class="n">cause</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">Trap</span>::<span class="n">Exception</span><span class="p">(</span><span class="n">Exception</span>::<span class="n">UserEnvCall</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="c1">// jump to next instruction anyway</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">cx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">current_trap_cx</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">cx</span><span class="p">.</span><span class="n">sepc</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">4</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="c1">// get system call return value</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">syscall</span><span class="p">(</span><span class="n">cx</span><span class="p">.</span><span class="n">x</span><span class="p">[</span><span class="mi">17</span><span class="p">],</span><span class="w"> </span><span class="p">[</span><span class="n">cx</span><span class="p">.</span><span class="n">x</span><span class="p">[</span><span class="mi">10</span><span class="p">],</span><span class="w"> </span><span class="n">cx</span><span class="p">.</span><span class="n">x</span><span class="p">[</span><span class="mi">11</span><span class="p">],</span><span class="w"> </span><span class="n">cx</span><span class="p">.</span><span class="n">x</span><span class="p">[</span><span class="mi">12</span><span class="p">]]);</span><span class="w"></span>
<span class="w"> </span><span class="c1">// cx is changed during sys_exec, so we have to call it again</span>
<span class="w"> </span><span class="n">cx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">current_trap_cx</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">cx</span><span class="p">.</span><span class="n">x</span><span class="p">[</span><span class="mi">10</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">result</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="p">}</span><span class="w"></span>
<span class="w"> </span><span class="o">..</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">trap_return</span><span class="p">();</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="sys-read">
<h2>sys_read 获取输入<a class="headerlink" href="#sys-read" title="永久链接至标题"></a></h2>
<p>我们需要实现 <code class="docutils literal notranslate"><span class="pre">sys_read</span></code> 系统调用,使应用能够取得用户的键盘输入。</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/syscall/fs.rs</span>
<span class="k">use</span><span class="w"> </span><span class="k">crate</span>::<span class="n">sbi</span>::<span class="n">console_getchar</span><span class="p">;</span><span class="w"></span>
<span class="k">const</span><span class="w"> </span><span class="n">FD_STDIN</span>: <span class="kt">usize</span> <span class="o">=</span><span class="w"> </span><span class="mi">0</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">sys_read</span><span class="p">(</span><span class="n">fd</span>: <span class="kt">usize</span><span class="p">,</span><span class="w"> </span><span class="n">buf</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="n">len</span>: <span class="kt">usize</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">isize</span> <span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">fd</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">FD_STDIN</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="fm">assert_eq!</span><span class="p">(</span><span class="n">len</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="s">"Only support len = 1 in sys_read!"</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">c</span>: <span class="kt">usize</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">loop</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">console_getchar</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">suspend_current_and_run_next</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="k">continue</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="k">break</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="kd">let</span><span class="w"> </span><span class="n">ch</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="k">as</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">buffers</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">translated_byte_buffer</span><span class="p">(</span><span class="n">current_user_token</span><span class="p">(),</span><span class="w"> </span><span class="n">buf</span><span class="p">,</span><span class="w"> </span><span class="n">len</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="n">buffers</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">as_mut_ptr</span><span class="p">().</span><span class="n">write_volatile</span><span class="p">(</span><span class="n">ch</span><span class="p">);</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="mi">1</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="fm">panic!</span><span class="p">(</span><span class="s">"Unsupported fd in sys_read!"</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="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>目前我们仅支持从标准输入 <code class="docutils literal notranslate"><span class="pre">FD_STDIN</span></code> 即文件描述符 0 读入,且每次只能读入一个字符,这是利用 <code class="docutils literal notranslate"><span class="pre">sbi</span></code>
提供的接口 <code class="docutils literal notranslate"><span class="pre">console_getchar</span></code> 实现的。如果还没有输入,我们就切换到其他进程,等下次切换回来时再看看是否有输入了。
获取到输入后就退出循环,并手动查页表将输入字符正确写入到应用地址空间。</p>
</div>
<div class="section" id="id6">
<h2>进程资源回收机制<a class="headerlink" href="#id6" title="永久链接至标题"></a></h2>
<div class="section" id="id7">
<h3>进程的退出<a class="headerlink" href="#id7" title="永久链接至标题"></a></h3>
<p>当应用调用 <code class="docutils literal notranslate"><span class="pre">sys_exit</span></code> 系统调用主动退出,或者出错由内核终止之后,会在内核中调用 <code class="docutils literal notranslate"><span class="pre">exit_current_and_run_next</span></code> 函数:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// os/src/syscall/process.rs</span>
<span class="linenos"> 2</span>
<span class="linenos"> 3</span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">sys_exit</span><span class="p">(</span><span class="n">exit_code</span>: <span class="kt">i32</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="hll"><span class="linenos"> 4</span><span class="w"> </span><span class="n">exit_current_and_run_next</span><span class="p">(</span><span class="n">exit_code</span><span class="p">);</span><span class="w"></span>
</span><span class="linenos"> 5</span><span class="w"> </span><span class="fm">panic!</span><span class="p">(</span><span class="s">"Unreachable in sys_exit!"</span><span class="p">);</span><span class="w"></span>
<span class="linenos"> 6</span><span class="p">}</span><span class="w"></span>
<span class="linenos"> 7</span>
<span class="linenos"> 8</span><span class="c1">// os/src/trap/mod.rs</span>
<span class="linenos"> 9</span>
<span class="linenos">10</span><span class="cp">#[no_mangle]</span><span class="w"></span>
<span class="linenos">11</span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">trap_handler</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">12</span><span class="w"> </span><span class="n">set_kernel_trap_entry</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">scause</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">scause</span>::<span class="n">read</span><span class="p">();</span><span class="w"></span>
<span class="linenos">14</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">stval</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">stval</span>::<span class="n">read</span><span class="p">();</span><span class="w"></span>
<span class="linenos">15</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">scause</span><span class="p">.</span><span class="n">cause</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">16</span><span class="w"> </span><span class="n">Trap</span>::<span class="n">Exception</span><span class="p">(</span><span class="n">Exception</span>::<span class="n">StoreFault</span><span class="p">)</span><span class="w"> </span><span class="o">|</span><span class="w"></span>
<span class="linenos">17</span><span class="w"> </span><span class="n">Trap</span>::<span class="n">Exception</span><span class="p">(</span><span class="n">Exception</span>::<span class="n">StorePageFault</span><span class="p">)</span><span class="w"> </span><span class="o">|</span><span class="w"></span>
<span class="linenos">18</span><span class="w"> </span><span class="n">Trap</span>::<span class="n">Exception</span><span class="p">(</span><span class="n">Exception</span>::<span class="n">InstructionFault</span><span class="p">)</span><span class="w"> </span><span class="o">|</span><span class="w"></span>
<span class="linenos">19</span><span class="w"> </span><span class="n">Trap</span>::<span class="n">Exception</span><span class="p">(</span><span class="n">Exception</span>::<span class="n">InstructionPageFault</span><span class="p">)</span><span class="w"> </span><span class="o">|</span><span class="w"></span>
<span class="linenos">20</span><span class="w"> </span><span class="n">Trap</span>::<span class="n">Exception</span><span class="p">(</span><span class="n">Exception</span>::<span class="n">LoadFault</span><span class="p">)</span><span class="w"> </span><span class="o">|</span><span class="w"></span>
<span class="linenos">21</span><span class="w"> </span><span class="n">Trap</span>::<span class="n">Exception</span><span class="p">(</span><span class="n">Exception</span>::<span class="n">LoadPageFault</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">22</span><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="w"></span>
<span class="linenos">23</span><span class="w"> </span><span class="s">"[kernel] {:?} in application, bad addr = {:#x}, bad instruction = {:#x}, core dumped."</span><span class="p">,</span><span class="w"></span>
<span class="linenos">24</span><span class="w"> </span><span class="n">scause</span><span class="p">.</span><span class="n">cause</span><span class="p">(),</span><span class="w"></span>
<span class="linenos">25</span><span class="w"> </span><span class="n">stval</span><span class="p">,</span><span class="w"></span>
<span class="linenos">26</span><span class="w"> </span><span class="n">current_trap_cx</span><span class="p">().</span><span class="n">sepc</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="w"> </span><span class="c1">// page fault exit code</span>
<span class="hll"><span class="linenos">29</span><span class="w"> </span><span class="n">exit_current_and_run_next</span><span class="p">(</span><span class="o">-</span><span class="mi">2</span><span class="p">);</span><span class="w"></span>
</span><span class="linenos">30</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">31</span><span class="w"> </span><span class="n">Trap</span>::<span class="n">Exception</span><span class="p">(</span><span class="n">Exception</span>::<span class="n">IllegalInstruction</span><span class="p">)</span><span class="w"> </span><span class="o">=&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="fm">println!</span><span class="p">(</span><span class="s">"[kernel] IllegalInstruction in application, core dumped."</span><span class="p">);</span><span class="w"></span>
<span class="linenos">33</span><span class="w"> </span><span class="c1">// illegal instruction exit code</span>
<span class="hll"><span class="linenos">34</span><span class="w"> </span><span class="n">exit_current_and_run_next</span><span class="p">(</span><span class="o">-</span><span class="mi">3</span><span class="p">);</span><span class="w"></span>
</span><span class="linenos">35</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">36</span><span class="w"> </span><span class="o">..</span><span class="p">.</span><span class="w"></span>
<span class="linenos">37</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">38</span><span class="w"> </span><span class="n">trap_return</span><span class="p">();</span><span class="w"></span>
<span class="linenos">39</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>相比前面的章节, <code class="docutils literal notranslate"><span class="pre">exit_current_and_run_next</span></code> 带有一个退出码作为参数,这个退出码会在
<code class="docutils literal notranslate"><span class="pre">exit_current_and_run_next</span></code> 写入当前进程的进程控制块:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// os/src/mm/memory_set.rs</span>
<span class="linenos"> 2</span>
<span class="linenos"> 3</span><span class="k">impl</span><span class="w"> </span><span class="n">MemorySet</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">recycle_data_pages</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="linenos"> 5</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">areas</span><span class="p">.</span><span class="n">clear</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="p">}</span><span class="w"></span>
<span class="linenos"> 8</span>
<span class="linenos"> 9</span><span class="c1">// os/src/task/mod.rs</span>
<span class="linenos">10</span>
<span class="linenos">11</span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">exit_current_and_run_next</span><span class="p">(</span><span class="n">exit_code</span>: <span class="kt">i32</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">12</span><span class="w"> </span><span class="c1">// take from Processor</span>
<span class="linenos">13</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">take_current_task</span><span class="p">().</span><span class="n">unwrap</span><span class="p">();</span><span class="w"></span>
<span class="linenos">14</span><span class="w"> </span><span class="c1">// **** access current 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">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="c1">// Change status to Zombie</span>
<span class="linenos">17</span><span class="w"> </span><span class="n">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">Zombie</span><span class="p">;</span><span class="w"></span>
<span class="linenos">18</span><span class="w"> </span><span class="c1">// Record exit code</span>
<span class="linenos">19</span><span class="w"> </span><span class="n">inner</span><span class="p">.</span><span class="n">exit_code</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">exit_code</span><span class="p">;</span><span class="w"></span>
<span class="linenos">20</span><span class="w"> </span><span class="c1">// do not move to its parent but under initproc</span>
<span class="linenos">21</span>
<span class="linenos">22</span><span class="w"> </span><span class="c1">// ++++++ access initproc TCB exclusively</span>
<span class="linenos">23</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">24</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">initproc_inner</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">INITPROC</span><span class="p">.</span><span class="n">inner_exclusive_access</span><span class="p">();</span><span class="w"></span>
<span class="linenos">25</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">child</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">inner</span><span class="p">.</span><span class="n">children</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="linenos">26</span><span class="w"> </span><span class="n">child</span><span class="p">.</span><span class="n">inner_exclusive_access</span><span class="p">().</span><span class="n">parent</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">Arc</span>::<span class="n">downgrade</span><span class="p">(</span><span class="o">&amp;</span><span class="n">INITPROC</span><span class="p">));</span><span class="w"></span>
<span class="linenos">27</span><span class="w"> </span><span class="n">initproc_inner</span><span class="p">.</span><span class="n">children</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">child</span><span class="p">.</span><span class="n">clone</span><span class="p">());</span><span class="w"></span>
<span class="linenos">28</span><span class="w"> </span><span class="p">}</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="c1">// ++++++ release parent PCB</span>
<span class="linenos">31</span>
<span class="linenos">32</span><span class="w"> </span><span class="n">inner</span><span class="p">.</span><span class="n">children</span><span class="p">.</span><span class="n">clear</span><span class="p">();</span><span class="w"></span>
<span class="linenos">33</span><span class="w"> </span><span class="c1">// deallocate user space</span>
<span class="linenos">34</span><span class="w"> </span><span class="n">inner</span><span class="p">.</span><span class="n">memory_set</span><span class="p">.</span><span class="n">recycle_data_pages</span><span class="p">();</span><span class="w"></span>
<span class="linenos">35</span><span class="w"> </span><span class="nb">drop</span><span class="p">(</span><span class="n">inner</span><span class="p">);</span><span class="w"></span>
<span class="linenos">36</span><span class="w"> </span><span class="c1">// **** release current PCB</span>
<span class="linenos">37</span><span class="w"> </span><span class="c1">// drop task manually to maintain rc correctly</span>
<span class="linenos">38</span><span class="w"> </span><span class="nb">drop</span><span class="p">(</span><span class="n">task</span><span class="p">);</span><span class="w"></span>
<span class="linenos">39</span><span class="w"> </span><span class="c1">// we do not have to save task context</span>
<span class="linenos">40</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">_unused</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">TaskContext</span>::<span class="n">zero_init</span><span class="p">();</span><span class="w"></span>
<span class="linenos">41</span><span class="w"> </span><span class="n">schedule</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="n">_unused</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="p">);</span><span class="w"></span>
<span class="linenos">42</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<ul class="simple">
<li><p>第 13 行,调用 <code class="docutils literal notranslate"><span class="pre">take_current_task</span></code> 来将当前进程控制块从处理器监控 <code class="docutils literal notranslate"><span class="pre">PROCESSOR</span></code>
中取出,而不只是得到一份拷贝,这是为了正确维护进程控制块的引用计数;</p></li>
<li><p>第 17 行将进程控制块中的状态修改为 <code class="docutils literal notranslate"><span class="pre">TaskStatus::Zombie</span></code> 即僵尸进程;</p></li>
<li><p>第 19 行将传入的退出码 <code class="docutils literal notranslate"><span class="pre">exit_code</span></code> 写入进程控制块中,后续父进程在 <code class="docutils literal notranslate"><span class="pre">waitpid</span></code> 的时候可以收集;</p></li>
<li><p>第 24~26 行所做的事情是,将当前进程的所有子进程挂在初始进程 <code class="docutils literal notranslate"><span class="pre">initproc</span></code> 下面。第 32 行将当前进程的孩子向量清空。</p></li>
<li><p>第 34 行,对于当前进程占用的资源进行早期回收。 <code class="docutils literal notranslate"><span class="pre">MemorySet::recycle_data_pages</span></code> 只是将地址空间中的逻辑段列表
<code class="docutils literal notranslate"><span class="pre">areas</span></code> 清空,这将导致应用地址空间的所有数据被存放在的物理页帧被回收,而用来存放页表的那些物理页帧此时则不会被回收。</p></li>
<li><p>最后在第 41 行我们调用 <code class="docutils literal notranslate"><span class="pre">schedule</span></code> 触发调度及任务切换,我们再也不会回到该进程的执行过程,因此无需关心任务上下文的保存。</p></li>
</ul>
</div>
<div class="section" id="id8">
<h3>父进程回收子进程资源<a class="headerlink" href="#id8" title="永久链接至标题"></a></h3>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// os/src/syscall/process.rs</span>
<span class="linenos"> 2</span>
<span class="linenos"> 3</span><span class="sd">/// If there is not a child process whose pid is same as given, return -1.</span>
<span class="linenos"> 4</span><span class="sd">/// Else if there is a child process but it is still running, return -2.</span>
<span class="linenos"> 5</span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">sys_waitpid</span><span class="p">(</span><span class="n">pid</span>: <span class="kt">isize</span><span class="p">,</span><span class="w"> </span><span class="n">exit_code_ptr</span>: <span class="o">*</span><span class="k">mut</span><span class="w"> </span><span class="kt">i32</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">isize</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">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"> 7</span><span class="w"> </span><span class="c1">// find a child process</span>
<span class="linenos"> 8</span>
<span class="linenos"> 9</span><span class="w"> </span><span class="c1">// ---- access current TCB exclusively</span>
<span class="linenos">10</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">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">11</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">!</span><span class="n">inner</span><span class="w"></span>
<span class="linenos">12</span><span class="w"> </span><span class="p">.</span><span class="n">children</span><span class="w"></span>
<span class="linenos">13</span><span class="w"> </span><span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w"></span>
<span class="linenos">14</span><span class="w"> </span><span class="p">.</span><span class="n">any</span><span class="p">(</span><span class="o">|</span><span class="n">p</span><span class="o">|</span><span class="w"> </span><span class="n">pid</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="o">-</span><span class="mi">1</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="n">pid</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">p</span><span class="p">.</span><span class="n">getpid</span><span class="p">())</span><span class="w"></span>
<span class="linenos">15</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">16</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="o">-</span><span class="mi">1</span><span class="p">;</span><span class="w"></span>
<span class="linenos">17</span><span class="w"> </span><span class="c1">// ---- release current PCB</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="kd">let</span><span class="w"> </span><span class="n">pair</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">inner</span><span class="p">.</span><span class="n">children</span><span class="p">.</span><span class="n">iter</span><span class="p">().</span><span class="n">enumerate</span><span class="p">().</span><span class="n">find</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="n">p</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">20</span><span class="w"> </span><span class="c1">// ++++ temporarily access child PCB lock exclusively</span>
<span class="linenos">21</span><span class="w"> </span><span class="n">p</span><span class="p">.</span><span class="n">inner_exclusive_access</span><span class="p">().</span><span class="n">is_zombie</span><span class="p">()</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="p">(</span><span class="n">pid</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="o">-</span><span class="mi">1</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="n">pid</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">p</span><span class="p">.</span><span class="n">getpid</span><span class="p">())</span><span class="w"></span>
<span class="linenos">22</span><span class="w"> </span><span class="c1">// ++++ release child PCB</span>
<span class="linenos">23</span><span class="w"> </span><span class="p">});</span><span class="w"></span>
<span class="linenos">24</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">idx</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">pair</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">child</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">inner</span><span class="p">.</span><span class="n">children</span><span class="p">.</span><span class="n">remove</span><span class="p">(</span><span class="n">idx</span><span class="p">);</span><span class="w"></span>
<span class="linenos">26</span><span class="w"> </span><span class="c1">// confirm that child will be deallocated after removing from children list</span>
<span class="linenos">27</span><span class="w"> </span><span class="fm">assert_eq!</span><span class="p">(</span><span class="n">Arc</span>::<span class="n">strong_count</span><span class="p">(</span><span class="o">&amp;</span><span class="n">child</span><span class="p">),</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"></span>
<span class="linenos">28</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">found_pid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">child</span><span class="p">.</span><span class="n">getpid</span><span class="p">();</span><span class="w"></span>
<span class="linenos">29</span><span class="w"> </span><span class="c1">// ++++ temporarily access child TCB exclusively</span>
<span class="linenos">30</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">exit_code</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">child</span><span class="p">.</span><span class="n">inner_exclusive_access</span><span class="p">().</span><span class="n">exit_code</span><span class="p">;</span><span class="w"></span>
<span class="linenos">31</span><span class="w"> </span><span class="c1">// ++++ release child PCB</span>
<span class="linenos">32</span><span class="w"> </span><span class="o">*</span><span class="n">translated_refmut</span><span class="p">(</span><span class="n">inner</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="n">exit_code_ptr</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">exit_code</span><span class="p">;</span><span class="w"></span>
<span class="linenos">33</span><span class="w"> </span><span class="n">found_pid</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">isize</span><span class="w"></span>
<span class="linenos">34</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="linenos">35</span><span class="w"> </span><span class="o">-</span><span class="mi">2</span><span class="w"></span>
<span class="linenos">36</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">37</span><span class="w"> </span><span class="c1">// ---- release current PCB lock automatically</span>
<span class="linenos">38</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">sys_waitpid</span></code> 是一个立即返回的系统调用,它的返回值语义是:如果当前的进程不存在一个符合要求的子进程,则返回
-1如果至少存在一个但是其中没有僵尸进程也即仍未退出则返回 -2如果都不是的话则可以正常回收并返回回收子进程的
pid 。但在编写应用的开发者看来, <code class="docutils literal notranslate"><span class="pre">wait/waitpid</span></code> 两个辅助函数都必定能够返回一个有意义的结果,要么是 -1要么是一个正数
PID ,是不存在 -2 这种通过等待即可消除的中间结果的。等待的过程由用户库 <code class="docutils literal notranslate"><span class="pre">user_lib</span></code> 完成。</p>
<p>首先判断 <code class="docutils literal notranslate"><span class="pre">sys_waitpid</span></code> 是否会返回 -1 ,这取决于当前进程是否有一个符合要求的子进程。当传入的 <code class="docutils literal notranslate"><span class="pre">pid</span></code> 为 -1
的时候,任何一个子进程都算是符合要求;但 <code class="docutils literal notranslate"><span class="pre">pid</span></code> 不为 -1 的时候,则只有 PID 恰好与 <code class="docutils literal notranslate"><span class="pre">pid</span></code>
相同的子进程才算符合条件。我们简单通过迭代器即可完成判断。</p>
<p>再判断符合要求的子进程中是否有僵尸进程。如果找不到的话直接返回 <code class="docutils literal notranslate"><span class="pre">-2</span></code> ,否则进行下一步处理:</p>
<p>我们将子进程从向量中移除并置于当前上下文中,当它所在的代码块结束,这次引用变量的生命周期结束,子进程进程控制块的引用计数将变为
0 ,内核将彻底回收掉它占用的所有资源,包括内核栈、它的 PID 、存放页表的那些物理页帧等等。</p>
<p>获得子进程退出码后,考虑到应用传入的指针指向应用地址空间,我们还需要手动查页表找到对应物理内存中的位置。
<code class="docutils literal notranslate"><span class="pre">translated_refmut</span></code> 的实现可以在 <code class="docutils literal notranslate"><span class="pre">os/src/mm/page_table.rs</span></code> 中找到。</p>
</div>
</div>
</div>
</article>
<footer>
<div class="related-pages">
<a class="next-page" href="4exercise.html">
<div class="page-info">
<div class="context">
<span>Next</span>
</div>
<div class="title">chapter5练习</div>
</div>
<svg><use href="#svg-arrow-right"></use></svg>
</a>
<a class="prev-page" href="2core-data-structures.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/3implement-process-mechanism.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></li>
<li><a class="reference internal" href="#id5">进程的生成机制</a><ul>
<li><a class="reference internal" href="#fork">fork 系统调用的实现</a></li>
<li><a class="reference internal" href="#exec">exec 系统调用的实现</a></li>
<li><a class="reference internal" href="#trap">系统调用后重新获取 Trap 上下文</a></li>
</ul>
</li>
<li><a class="reference internal" href="#sys-read">sys_read 获取输入</a></li>
<li><a class="reference internal" href="#id6">进程资源回收机制</a><ul>
<li><a class="reference internal" href="#id7">进程的退出</a></li>
<li><a class="reference internal" href="#id8">父进程回收子进程资源</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>