mirror of
https://github.com/LearningOS/rust-based-os-comp2022.git
synced 2026-02-08 12:53:34 +08:00
615 lines
44 KiB
HTML
615 lines
44 KiB
HTML
<!doctype html>
|
||
<html class="no-js" lang="zh_CN">
|
||
<head><meta charset="utf-8"/>
|
||
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
||
<meta name="color-scheme" content="light dark"><link rel="index" title="索引" href="../genindex.html" /><link rel="search" title="搜索" href="../search.html" /><link rel="next" title="内核态的线程管理" href="1thread-kernel.html" /><link rel="prev" title="第八章:并发" href="index.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 has-children"><a class="reference internal" href="../chapter5/index.html">第五章:进程及进程管理</a><input 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>
|
||
<li class="toctree-l2"><a class="reference internal" href="../chapter5/0intro.html">引言</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../chapter5/1process.html">与进程有关的重要系统调用</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../chapter5/2core-data-structures.html">进程管理的核心数据结构</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../chapter5/3implement-process-mechanism.html">进程管理机制的设计实现</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../chapter5/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 current has-children"><a class="reference internal" href="index.html">第八章:并发</a><input checked="" 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 class="current">
|
||
<li class="toctree-l2 current current-page"><a class="current reference internal" href="#">引言</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="1thread-kernel.html">内核态的线程管理</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="2lock.html">锁机制</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="3semaphore.html">信号量机制</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="4condition-variable.html">条件变量机制</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="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">附录 A:Rust 系统编程资料</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">附录 D:RISC-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>到本章开始之前,我们好像已经完成了组成应用程序执行环境的操作系统的三个重要抽象:进程、地址空间和文件,
|
||
让应用程序开发、运行和存储数据越来越方便和灵活。有了进程以后,可以让操作系统从宏观层面实现多个应用的并发执行,
|
||
而并发是通过操作系统基于处理器的时间片不断地切换进程来达到的。到目前为止的并发,仅仅是进程间的并发,
|
||
对于一个进程内部还没有并发性的体现。而这就是线程(Thread)出现的起因:提高一个进程内的并发性。</p>
|
||
<p>有了进程以后,为什么还会出现线程呢?考虑如下情况,对于很多应用(以单一进程的形式运行)而言,
|
||
逻辑上存在多个可并行执行的任务,如果其中一个任务被阻塞,将会引起不依赖该任务的其他任务也被阻塞。
|
||
举个具体的例子,我们平常用编辑器来编辑文本内容的时候,都会有一个定时自动保存的功能,
|
||
这个功能的作用是在系统或应用本身出现故障的情况前,已有的文档内容会被提前保存。
|
||
假设编辑器自动保存时由于磁盘性能导致写入较慢,导致整个进程被操作系统挂起,这就会影响到用户编辑文档的人机交互体验:
|
||
即软件的及时响应能力不足,用户只有等到磁盘写入完成后,操作系统重新调度该进程运行后,用户才可编辑。
|
||
如果我们把一个进程内的多个可并行执行任务通过一种更细粒度的方式让操作系统进行调度,
|
||
那么就可以通过处理器时间片切换实现这种细粒度的并发执行。这种细粒度的调度对象就是线程。</p>
|
||
<div class="section" id="term-thread-define">
|
||
<span id="id3"></span><h3>线程定义<a class="headerlink" href="#term-thread-define" title="永久链接至标题">¶</a></h3>
|
||
<p>简单地说,线程是进程的组成部分,进程可包含1 – n个线程,属于同一个进程的线程共享进程的资源,
|
||
比如地址空间、打开的文件等。基本的线程由线程ID、执行状态、当前指令指针 (PC)、寄存器集合和栈组成。
|
||
线程是可以被操作系统或用户态调度器独立调度(Scheduling)和分派(Dispatch)的基本单位。</p>
|
||
<p>在本章之前,进程是程序的基本执行实体,是程序关于某数据集合上的一次运行活动,是系统进行资源(处理器、
|
||
地址空间和文件等)分配和调度的基本单位。在有了线程后,对进程的定义也要调整了,进程是线程的资源容器,
|
||
线程成为了程序的基本执行实体。</p>
|
||
</div>
|
||
<div class="section" id="id4">
|
||
<h3>同步互斥<a class="headerlink" href="#id4" title="永久链接至标题">¶</a></h3>
|
||
<p>在上面提到了同步互斥和数据一致性,它们的含义是什么呢?当多个线程共享同一进程的地址空间时,
|
||
每个线程都可以访问属于这个进程的数据(全局变量)。如果每个线程使用到的变量都是其他线程不会读取或者修改的话,
|
||
那么就不存在一致性问题。如果变量是只读的,多个线程读取该变量也不会有一致性问题。但是,当一个线程修改变量时,
|
||
其他线程在读取这个变量时,可能会看到一个不一致的值,这就是数据不一致性的问题。</p>
|
||
<div class="admonition note">
|
||
<p class="admonition-title">注解</p>
|
||
<p><strong>并发相关术语</strong></p>
|
||
<ul class="simple">
|
||
<li><p>共享资源(shared resource):不同的线程/进程都能访问的变量或数据结构。</p></li>
|
||
<li><p>临界区(critical section):访问共享资源的一段代码。</p></li>
|
||
<li><p>竞态条件(race condition):多个线程/进程都进入临界区时,都试图更新共享的数据结构,导致产生了不期望的结果。</p></li>
|
||
<li><p>不确定性(indeterminate): 多个线程/进程在执行过程中出现了竞态条件,导致执行结果取决于哪些线程在何时运行,
|
||
即执行结果不确定,而开发者期望得到的是确定的结果。</p></li>
|
||
<li><p>互斥(mutual exclusion):一种操作原语,能保证只有一个线程进入临界区,从而避免出现竞态,并产生确定的执行结果。</p></li>
|
||
<li><p>原子性(atomic):一系列操作要么全部完成,要么一个都没执行,不会看到中间状态。在数据库领域,
|
||
具有原子性的一系列操作称为事务(transaction)。</p></li>
|
||
<li><p>同步(synchronization):多个并发执行的进程/线程在一些关键点上需要互相等待,这种相互制约的等待称为进程/线程同步。</p></li>
|
||
<li><p>死锁(dead lock):一个线程/进程集合里面的每个线程/进程都在等待只能由这个集合中的其他一个线程/进程
|
||
(包括他自身)才能引发的事件,这种情况就是死锁。</p></li>
|
||
<li><p>饥饿(hungry):指一个可运行的线程/进程尽管能继续执行,但由于操作系统的调度而被无限期地忽视,导致不能执行的情况。</p></li>
|
||
</ul>
|
||
</div>
|
||
<p>在后续的章节中,会大量使用上述术语,如果现在还不够理解,没关系,随着后续的一步一步的分析和实验,
|
||
相信大家能够掌握上述术语的实际含义。</p>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="id5">
|
||
<h2>实践体验<a class="headerlink" href="#id5" title="永久链接至标题">¶</a></h2>
|
||
<div class="admonition note">
|
||
<p class="admonition-title">注解</p>
|
||
<p>基于github classroom的开发方式</p>
|
||
<p>基于github classroom,可方便建立开发用的git repository,并可基于github的 codespace (在线版ubuntu +vscode)在线开发使用。整个开发环境仅仅需要一个网络浏览器。</p>
|
||
<ol class="arabic simple">
|
||
<li><p>在网络浏览器中用自己的 github id 登录 github.com</p></li>
|
||
<li><p>接收 <a class="reference external" href="https://classroom.github.com/a/zqGJEPK-">第五个实验(os8)的github classroom在线邀请</a> ,根据提示一路选择OK即可。</p></li>
|
||
<li><p>完成第二步后,你的第五个实验的 github repository 会被自动建立好,点击此github repository的链接,就可看到你要完成的第一个实验了。</p></li>
|
||
<li><p>在你的第五个实验的网页的中上部可以看到一个醒目的 <cite>code</cite> 绿色按钮,点击后,可以进一步看到 <cite>codespace</cite> 标签和醒目的 <cite>create codesapce on main</cite> 绿色按钮。请点击这个绿色按钮,就可以进入到在线的ubuntu +vscode环境中</p></li>
|
||
<li><p>再按照下面的环境安装提示在vscode的 <cite>console</cite> 中安装配置开发环境:rustc,qemu等工具。注:也可在vscode的 <cite>console</cite> 中执行 <code class="docutils literal notranslate"><span class="pre">make</span> <span class="pre">codespaces_setenv</span></code> 来自动安装配置开发环境(执行``sudo``需要root权限,仅需要执行一次)。</p></li>
|
||
<li><p>在vscode的 <cite>console</cite> 中执行 <cite>make setupclassroom_test8</cite> (该命令仅执行一次)配置githubclassroom 自动评分功能。</p></li>
|
||
<li><p>然后就可以基于在线vscode进行开发、运行、提交等完整的实验过程了。</p></li>
|
||
</ol>
|
||
<p>上述的3,4,5步不是必须的,你也可以线下本地开发。</p>
|
||
<p>注:如果是本地的ubuntu中建立开发环境,可在shell中执行 <code class="docutils literal notranslate"><span class="pre">make</span> <span class="pre">ubuntu_local_setenv</span></code> 来自动安装配置开发环境(执行``sudo``需要root权限,仅需要执行一次)。</p>
|
||
</div>
|
||
<p>获取本章代码:</p>
|
||
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>git clone https://github.com/LearningOS/rust-based-os-comp2022.git
|
||
<span class="gp">$ </span><span class="nb">cd</span> rust-based-os-comp2022/
|
||
<span class="gp">$ </span>make setupclassroom_test8 //注意:这一步很重要,是用于github classroom自动评测你的工作。这一步只需在首次克隆项目仓库时执行一次,以后一般就不用执行了,除非 .github/workflows/classroom.yml发生了变化。
|
||
</pre></div>
|
||
</div>
|
||
<p>在 qemu 模拟器上运行本章代码 <a class="reference external" href="https://github.com/LearningOS/rust-based-os-comp2022/tree/main/os8-ref">lab5(os8)参考框架:</a> :</p>
|
||
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span><span class="nb">cd</span> os8-ref
|
||
<span class="gp">$ </span>make run
|
||
</pre></div>
|
||
</div>
|
||
<p>内核初始化完成之后就会进入 shell 程序,我们可以体会一下线程的创建和执行过程。在这里我们运行一下本章的测例 <code class="docutils literal notranslate"><span class="pre">ch8b_threads</span></code> :</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">>></span> <span class="n">ch8b_threads</span>
|
||
<span class="n">aaa</span><span class="o">....</span><span class="n">bbb</span><span class="o">...</span><span class="n">ccc</span><span class="o">...</span>
|
||
<span class="n">thread</span><span class="c1">#1 exited with code 1</span>
|
||
<span class="n">thread</span><span class="c1">#2 exited with code 2</span>
|
||
<span class="n">thread</span><span class="c1">#3 exited with code 3</span>
|
||
<span class="n">main</span> <span class="n">thread</span> <span class="n">exited</span><span class="o">.</span>
|
||
<span class="n">Shell</span><span class="p">:</span> <span class="n">Process</span> <span class="mi">2</span> <span class="n">exited</span> <span class="k">with</span> <span class="n">code</span> <span class="mi">0</span>
|
||
<span class="o">>></span>
|
||
</pre></div>
|
||
</div>
|
||
<p>它会有4个线程在执行,等前3个线程执行完毕后,主线程退出,导致整个进程退出。</p>
|
||
<p>此外,在本章的操作系统支持通过互斥来执行“哲学家就餐问题”这个应用程序:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>>> ch8b_phil_din_mutex
|
||
Here comes 5 philosophers!
|
||
time cost = 720
|
||
'-' -> THINKING; 'x' -> EATING; ' ' -> WAITING
|
||
#0: ------- xxxxxxxx---------- xxxx----- xxxxxx--xxx
|
||
#1: ---xxxxxx-- xxxxxxx---------- x---xxxxxx
|
||
#2: ----- xx---------xx----xxxxxx------------ xxxx
|
||
#3: -----xxxxxxxxxx------xxxxx-------- xxxxxx-- xxxxxxxxx
|
||
#4: ------ x------ xxxxxx-- xxxxx------ xx
|
||
#0: ------- xxxxxxxx---------- xxxx----- xxxxxx--xxx
|
||
Shell: Process 2 exited with code 0
|
||
>>
|
||
</pre></div>
|
||
</div>
|
||
<p>我们可以看到5个代表“哲学家”的线程通过操作系统的 <strong>信号量</strong> 互斥机制在进行 “THINKING”、“EATING”、“WAITING” 的日常生活。
|
||
没有哲学家由于拿不到筷子而饥饿,也没有两个哲学家同时拿到一个筷子。</p>
|
||
<div class="admonition note">
|
||
<p class="admonition-title">注解</p>
|
||
<p><strong>哲学家就餐问题</strong></p>
|
||
<p>计算机科学家 Dijkstra 提出并解决的哲学家就餐问题是经典的进程同步互斥问题。哲学家就餐问题描述如下:</p>
|
||
<p>有5个哲学家共用一张圆桌,分别坐在周围的5张椅子上,在圆桌上有5个碗和5只筷子,他们的生活方式是交替地进行思考和进餐。
|
||
平时,每个哲学家进行思考,饥饿时便试图拿起其左右最靠近他的筷子,只有在他拿到两只筷子时才能进餐。进餐完毕,放下筷子继续思考。</p>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="id7">
|
||
<h2>本章的 <a class="reference external" href="https://github.com/LearningOS/rust-based-os-comp2022/tree/main/os8-ref">lab5(os8)参考框架:</a> 代码树<a class="headerlink" href="#id7" title="永久链接至标题">¶</a></h2>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span> .
|
||
<span class="linenos"> 2</span> ├── bootloader
|
||
<span class="linenos"> 3</span> │ └── rustsbi-qemu.bin
|
||
<span class="linenos"> 4</span> ├── Dockerfile
|
||
<span class="linenos"> 5</span> ├── easy-fs
|
||
<span class="linenos"> 6</span> │ ├── Cargo.lock
|
||
<span class="linenos"> 7</span> │ ├── Cargo.toml
|
||
<span class="linenos"> 8</span> │ └── src
|
||
<span class="linenos"> 9</span> │ ├── bitmap.rs
|
||
<span class="linenos">10</span> │ ├── block_cache.rs
|
||
<span class="linenos">11</span> │ ├── block_dev.rs
|
||
<span class="linenos">12</span> │ ├── efs.rs
|
||
<span class="linenos">13</span> │ ├── layout.rs
|
||
<span class="linenos">14</span> │ ├── lib.rs
|
||
<span class="linenos">15</span> │ └── vfs.rs
|
||
<span class="linenos">16</span> ├── easy-fs-fuse
|
||
<span class="linenos">17</span> │ ├── Cargo.lock
|
||
<span class="linenos">18</span> │ ├── Cargo.toml
|
||
<span class="linenos">19</span> │ └── src
|
||
<span class="linenos">20</span> │ └── main.rs
|
||
<span class="linenos">21</span> ├── LICENSE
|
||
<span class="linenos">22</span> ├── Makefile
|
||
<span class="linenos">23</span> ├── os
|
||
<span class="linenos">24</span> │ ├── build.rs
|
||
<span class="linenos">25</span> │ ├── Cargo.lock
|
||
<span class="linenos">26</span> │ ├── Cargo.toml
|
||
<span class="linenos">27</span> │ ├── Makefile
|
||
<span class="linenos">28</span> │ └── src
|
||
<span class="linenos">29</span> │ ├── config.rs (修改:扩大了内核堆空间)
|
||
<span class="linenos">30</span> │ ├── console.rs
|
||
<span class="linenos">31</span> │ ├── drivers
|
||
<span class="linenos">32</span> │ │ ├── block
|
||
<span class="linenos">33</span> │ │ │ ├── mod.rs
|
||
<span class="linenos">34</span> │ │ │ └── virtio_blk.rs
|
||
<span class="linenos">35</span> │ │ └── mod.rs
|
||
<span class="linenos">36</span> │ ├── entry.asm
|
||
<span class="linenos">37</span> │ ├── fs
|
||
<span class="linenos">38</span> │ │ ├── inode.rs
|
||
<span class="linenos">39</span> │ │ ├── mod.rs
|
||
<span class="linenos">40</span> │ │ ├── pipe.rs
|
||
<span class="linenos">41</span> │ │ └── stdio.rs
|
||
<span class="linenos">42</span> │ ├── lang_items.rs
|
||
<span class="linenos">43</span> │ ├── linker.ld
|
||
<span class="linenos">44</span> │ ├── logging.rs
|
||
<span class="linenos">45</span> │ ├── main.rs
|
||
<span class="linenos">46</span> │ ├── mm
|
||
<span class="linenos">47</span> │ │ ├── address.rs
|
||
<span class="linenos">48</span> │ │ ├── frame_allocator.rs
|
||
<span class="linenos">49</span> │ │ ├── heap_allocator.rs
|
||
<span class="linenos">50</span> │ │ ├── memory_set.rs (修改:去除了构建进程地址空间时分配用户栈和映射陷入上下文的逻辑)
|
||
<span class="linenos">51</span> │ │ ├── mod.rs
|
||
<span class="linenos">52</span> │ │ └── page_table.rs
|
||
<span class="linenos">53</span> │ ├── sbi.rs
|
||
<span class="linenos">54</span> │ ├── sync (新增:互斥锁、信号量和条件变量三种同步互斥机制的实现)
|
||
<span class="linenos">55</span> │ │ ├── condvar.rs
|
||
<span class="linenos">56</span> │ │ ├── mod.rs
|
||
<span class="linenos">57</span> │ │ ├── mutex.rs
|
||
<span class="linenos">58</span> │ │ ├── semaphore.rs
|
||
<span class="linenos">59</span> │ │ └── up.rs
|
||
<span class="linenos">60</span> │ ├── syscall
|
||
<span class="linenos">61</span> │ │ ├── fs.rs (修改:将原先对 task 的调用改为对 process 的调用)
|
||
<span class="linenos">62</span> │ │ ├── mod.rs
|
||
<span class="linenos">63</span> │ │ ├── process.rs (修改:将原先对 task 的调用改为对 process 的调用)
|
||
<span class="linenos">64</span> │ │ ├── sync.rs (新增:三种同步互斥机制相关的系统调用,以及基于定时器条件变量的 sleep 调用)
|
||
<span class="linenos">65</span> │ │ └── thread.rs (新增:线程相关系统调用)
|
||
<span class="linenos">66</span> │ ├── task
|
||
<span class="linenos">67</span> │ │ ├── context.rs (修改:将任务上下文的成员变量改为 pub 类型)
|
||
<span class="linenos">68</span> │ │ ├── id.rs (新增:由 pid.rs 修改而来,提供 pid/tid 、 kstack/ustack 的分配和回收机制)
|
||
<span class="linenos">69</span> │ │ ├── kthread.rs (新增:完全在内核态运行的线程,仅供参考,在实验中未使用)
|
||
<span class="linenos">70</span> │ │ ├── manager.rs
|
||
<span class="linenos">71</span> │ │ ├── mod.rs (修改:增加阻塞线程的功能,将 exit 扩展到多线程,并在主线程退出时一并退出进程)
|
||
<span class="linenos">72</span> │ │ ├── processor.rs (修改:增加获取当前线程的中断上下文虚拟地址及获取当前进程的功能)
|
||
<span class="linenos">73</span> │ │ ├── process.rs (新增:将原先 Task 中的地址空间、文件等机制拆分为进程)
|
||
<span class="linenos">74</span> │ │ ├── stackless_coroutine.rs (新增:完全在内核态运行的无栈协程,仅供参考,在实验中未使用)
|
||
<span class="linenos">75</span> │ │ ├── switch.rs
|
||
<span class="linenos">76</span> │ │ ├── switch.S
|
||
<span class="linenos">77</span> │ │ └── task.rs (修改:将进程相关的功能移至 process.rs 中)
|
||
<span class="linenos">78</span> │ ├── timer.rs (修改:增加定时器条件变量的实现)
|
||
<span class="linenos">79</span> │ └── trap
|
||
<span class="linenos">80</span> │ ├── context.rs
|
||
<span class="linenos">81</span> │ ├── mod.rs (修改:使用线程对应的中断上下文地址而非固定的 TRAP_CONTEXT)
|
||
<span class="linenos">82</span> │ └── trap.S
|
||
<span class="linenos">83</span> ├── README.md
|
||
<span class="linenos">84</span> └── rust-toolchain
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</article>
|
||
<footer>
|
||
|
||
<div class="related-pages">
|
||
<a class="next-page" href="1thread-kernel.html">
|
||
<div class="page-info">
|
||
<div class="context">
|
||
<span>Next</span>
|
||
</div>
|
||
<div class="title">内核态的线程管理</div>
|
||
</div>
|
||
<svg><use href="#svg-arrow-right"></use></svg>
|
||
</a>
|
||
<a class="prev-page" href="index.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 © 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/chapter8/0intro.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><ul>
|
||
<li><a class="reference internal" href="#term-thread-define">线程定义</a></li>
|
||
<li><a class="reference internal" href="#id4">同步互斥</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#id5">实践体验</a></li>
|
||
<li><a class="reference internal" href="#id7">本章的 lab5(os8)参考框架: 代码树</a></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> |