You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
zCore-Tutorial/ch01-02-process-object.html

442 lines
26 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE HTML>
<html lang="cn" class="sidebar-visible no-js light">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>🚧 对象管理器Process 对象 - 简明 zCore 教程</title>
<!-- Custom HTML head -->
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
</head>
<body>
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded affix "><a href="index.html">简明 zCore 教程</a></li><li class="chapter-item expanded affix "><a href="zcore-intro.html">🚧 zCore 整体结构和设计模式</a></li><li class="chapter-item expanded affix "><a href="fuchsia.html">🚧 Fuchsia OS 和 Zircon 微内核</a></li><li class="chapter-item expanded "><a href="ch01-00-object.html"><strong aria-hidden="true">1.</strong> 内核对象</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch01-01-kernel-object.html"><strong aria-hidden="true">1.1.</strong> ✅ 初识内核对象</a></li><li class="chapter-item expanded "><a href="ch01-02-process-object.html" class="active"><strong aria-hidden="true">1.2.</strong> 🚧 对象管理器Process 对象</a></li><li class="chapter-item expanded "><a href="ch01-03-channel-object.html"><strong aria-hidden="true">1.3.</strong> 🚧 对象传送器Channel 对象</a></li></ol></li><li class="chapter-item expanded "><a href="ch02-00-task.html"><strong aria-hidden="true">2.</strong> 任务管理</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch02-01-zircon-task.html"><strong aria-hidden="true">2.1.</strong> 🚧 Zircon 任务管理体系</a></li><li class="chapter-item expanded "><a href="ch02-02-process-job-object.html"><strong aria-hidden="true">2.2.</strong> 🚧 进程管理Process 与 Job 对象</a></li><li class="chapter-item expanded "><a href="ch02-03-thread-object.html"><strong aria-hidden="true">2.3.</strong> 🚧 线程管理Thread 对象</a></li></ol></li><li class="chapter-item expanded "><a href="ch03-00-memory.html"><strong aria-hidden="true">3.</strong> 内存管理</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch03-01-zircon-memory.html"><strong aria-hidden="true">3.1.</strong> 🚧 Zircon 内存管理模型</a></li><li class="chapter-item expanded "><a href="ch03-02-vmo.html"><strong aria-hidden="true">3.2.</strong> 🚧 物理内存VMO 对象</a></li><li class="chapter-item expanded "><a href="ch03-03-vmo-paged.html"><strong aria-hidden="true">3.3.</strong> 🚧 物理内存:按页分配的 VMO</a></li><li class="chapter-item expanded "><a href="ch03-04-vmar.html"><strong aria-hidden="true">3.4.</strong> 🚧 虚拟内存VMAR 对象</a></li></ol></li><li class="chapter-item expanded "><a href="ch04-00-userspace.html"><strong aria-hidden="true">4.</strong> 用户程序</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch04-01-user-program.html"><strong aria-hidden="true">4.1.</strong> 🚧 Zircon 用户程序</a></li><li class="chapter-item expanded "><a href="ch04-02-context-switch.html"><strong aria-hidden="true">4.2.</strong> 🚧 上下文切换</a></li><li class="chapter-item expanded "><a href="ch04-03-syscall.html"><strong aria-hidden="true">4.3.</strong> 🚧 系统调用</a></li></ol></li><li class="chapter-item expanded "><a href="ch05-00-signal-and-waiting.html"><strong aria-hidden="true">5.</strong> 信号和等待</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch05-01-wait-signal.html"><strong aria-hidden="true">5.1.</strong> 🚧 等待内核对象的信号</a></li><li class="chapter-item expanded "><a href="ch05-02-port-object.html"><strong aria-hidden="true">5.2.</strong> 🚧 同时等待多个信号Port 对象</a></li><li class="chapter-item expanded "><a href="ch05-03-more-signal-objects.html"><strong aria-hidden="true">5.3.</strong> 🚧 实现更多EventPair, Timer 对象</a></li><li class="chapter-item expanded "><a href="ch05-04-futex-object.html"><strong aria-hidden="true">5.4.</strong> 🚧 用户态同步互斥Futex 对象</a></li></ol></li><li class="chapter-item expanded "><a href="ch06-00-hal.html"><strong aria-hidden="true">6.</strong> 硬件抽象层</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch06-01-zcore-hal-unix.html"><strong aria-hidden="true">6.1.</strong> ✅ UNIX硬件抽象层</a></li></ol></li></ol> </div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky bordered">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">简明 zCore 教程</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/rcore-os/zCore-Tutorial" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h4 id="对象管理器process-对象"><a class="header" href="#对象管理器process-对象">对象管理器Process 对象</a></h4>
<h2 id="句柄操作内核对象的桥梁"><a class="header" href="#句柄操作内核对象的桥梁">句柄——操作内核对象的桥梁</a></h2>
<p>在1.1中我们用Rust语言实现了一个最核心的内核对象在本小节我们将逐步了解与内核对象相关的三个重要概念中的其他两个<strong>句柄Handle和权限Rights</strong></p>
<p>句柄是允许用户程序引用内核对象引用的一种内核结构,它可以被认为是与特定内核对象的会话或连接。</p>
<p>通常情况下,多个进程通过不同的句柄同时访问同一个对象。对象可能有多个句柄(在一个或多个进程中)引用它们。但单个句柄只能绑定到单个进程或绑定到内核。</p>
<h3 id="定义句柄"><a class="header" href="#定义句柄">定义句柄</a></h3>
<p>在 object 模块下定义一个子模块:</p>
<pre><code class="language-rust noplaypen">// src/object/mod.rs
mod handle;
pub use self::handle::*;
</code></pre>
<p>定义句柄:</p>
<pre><code class="language-rust noplaypen">// src/object/handle.rs
use super::{KernelObject, Rights};
use alloc::sync::Arc;
/// 内核对象句柄
#[derive(Clone)]
pub struct Handle {
pub object: Arc&lt;dyn KernelObject&gt;,
pub rights: Rights,
}
</code></pre>
<p>一个Handle包含object和right两个字段object是实现了<code>KernelObject</code>Trait的内核对象Rights是该句柄的权限我们将在下面提到它。</p>
<p>Arc<T>是一个可以在多线程上使用的引用计数类型,这个计数会随着 <code>Arc&lt;T&gt;</code> 的创建或复制而增加,并当 <code>Arc&lt;T&gt;</code> 生命周期结束被回收时减少。当这个计数变为零之后,这个计数变量本身以及被引用的变量都会从堆上被回收。</p>
<p>我们为什么要在这里使用Arc智能指针呢</p>
<p>绝大多数内核对象的析构都发生在句柄数量为 0 时也就是最后一个指向内核对象的Handle被关闭该对象也随之消亡抑或进入一种无法撤销的最终状态。很明显这与Arc<T>天然的契合。</p>
<h2 id="控制句柄的权限rights"><a class="header" href="#控制句柄的权限rights">控制句柄的权限——Rights</a></h2>
<p>上文的Handle中有一个字段是rights也就是句柄的权限。顾名思义权限规定该句柄对引用的对象可以进行何种操作。</p>
<p>当不同的权限和同一个对象绑定在一起时,也就形成了不同的句柄。</p>
<h3 id="定义权限"><a class="header" href="#定义权限">定义权限</a></h3>
<p>在 object 模块下定义一个子模块:</p>
<pre><code class="language-rust noplaypen">// src/object/mod.rs
mod rights;
pub use self::rights::*;
</code></pre>
<p>权限就是u32的一个数字</p>
<pre><code class="language-rust noplaypen">// src/object/rights.rs
use bitflags::bitflags;
bitflags! {
/// 句柄权限
pub struct Rights: u32 {
const DUPLICATE = 1 &lt;&lt; 0;
const TRANSFER = 1 &lt;&lt; 1;
const READ = 1 &lt;&lt; 2;
const WRITE = 1 &lt;&lt; 3;
const EXECUTE = 1 &lt;&lt; 4;
...
}
</code></pre>
<p><a href="https://docs.rs/bitflags/1.2.1/bitflags/"><strong>bitflags</strong></a> 是一个 Rust 中常用来比特标志位的 crate 。它提供了 一个 <code>bitflags!</code> 宏,如上面的代码段所展示的那样,借助 <code>bitflags!</code> 宏我们将一个 <code>u32</code> 的 rights 包装为一个 <code>Rights</code> 结构体。注意,在使用之前我们需要引入该 crate 的依赖:</p>
<pre><code class="language-rust noplaypen"><span class="boring">Cargo.toml
</span>
[dependencies]
bitflags = &quot;1.2&quot;
</code></pre>
<p>定义好权限之后,我们回到句柄相关方法的实现。</p>
<p>首先是最简单的部分创建一个handle很显然我们需要提供两个参数分别是句柄关联的内核对象和句柄的权限。</p>
<pre><code class="language-rust noplaypen">impl Handle {
/// 创建一个新句柄
pub fn new(object: Arc&lt;dyn KernelObject&gt;, rights: Rights) -&gt; Self {
Handle { object, rights }
}
}
</code></pre>
<h3 id="测试"><a class="header" href="#测试">测试</a></h3>
<p>好啦,让我们来测试一下!</p>
<pre><code class="language-rust noplaypen">#[cfg(test)]
mod tests {
use super::*;
use crate::object::DummyObject;
#[test]
fn new_obj_handle() {
let obj = DummyObject::new();
let handle1 = Handle::new(obj.clone(), Rights::BASIC);
}
}
</code></pre>
<h2 id="句柄存储的载体process"><a class="header" href="#句柄存储的载体process">句柄存储的载体——Process</a></h2>
<p>实现完了句柄之后,我们开始考虑,句柄是存储在哪里的呢?</p>
<p>通过前面的讲解很明显Process拥有内核对象句柄也就是说句柄存储在Process中所以我们先来实现一个Process</p>
<h3 id="实现空的process对象"><a class="header" href="#实现空的process对象">实现空的process对象</a></h3>
<pre><code class="language-rust noplaypen">// src/task/process.rs
/// 进程对象
pub struct Process {
base: KObjectBase,
inner: Mutex&lt;ProcessInner&gt;,
}
// 宏的作用:补充
impl_kobject!(Process);
struct ProcessInner {
handles: BTreeMap&lt;HandleValue, Handle&gt;,
}
pub type HandleValue = u32;
</code></pre>
<p>handles使用BTreeMap存储的key是HandleValuevalue就是句柄。通过HandleValue实现对句柄的增删操作。HandleValue实际上就是u32类型是别名。</p>
<p>把内部对象ProcessInner用自旋锁Mutex包起来保证了互斥访问因为Mutex会帮我们处理好并发问题这一点已经在1.1节中详细说明。</p>
<p>接下来我们实现创建一个Process的方法</p>
<pre><code class="language-rust noplaypen">impl Process {
/// 创建一个新的进程对象
pub fn new() -&gt; Arc&lt;Self&gt; {
Arc::new(Process {
base: KObjectBase::default(),
inner: Mutex::new(ProcessInner {
handles: BTreeMap::default(),
}),
})
}
}
</code></pre>
<h4 id="单元测试"><a class="header" href="#单元测试">单元测试</a></h4>
<p>我们已经实现了创建一个Process的方法下面我们写一个单元测试</p>
<pre><code class="language-rust noplaypen">#[test]
fn new_proc() {
let proc = Process::new();
assert_eq!(proc.type_name(), &quot;Process&quot;);
assert_eq!(proc.name(), &quot;&quot;);
proc.set_name(&quot;proc1&quot;);
assert_eq!(proc.name(), &quot;proc1&quot;);
assert_eq!(
format!(&quot;{:?}&quot;, proc),
format!(&quot;Process({}, \&quot;proc1\&quot;)&quot;, proc.id())
);
let obj: Arc&lt;dyn KernelObject&gt; = proc;
assert_eq!(obj.type_name(), &quot;Process&quot;);
assert_eq!(obj.name(), &quot;proc1&quot;);
obj.set_name(&quot;proc2&quot;);
assert_eq!(obj.name(), &quot;proc2&quot;);
assert_eq!(
format!(&quot;{:?}&quot;, obj),
format!(&quot;Process({}, \&quot;proc2\&quot;)&quot;, obj.id())
);
}
</code></pre>
<h3 id="process相关方法"><a class="header" href="#process相关方法">Process相关方法</a></h3>
<h4 id="插入句柄"><a class="header" href="#插入句柄">插入句柄</a></h4>
<p>在Process中添加一个新的handle返回值是一个handleValue也就是u32</p>
<pre><code class="language-rust noplaypen">pub fn add_handle(&amp;self, handle: Handle) -&gt; HandleValue {
let mut inner = self.inner.lock();
let value = (0 as HandleValue..)
.find(|idx| !inner.handles.contains_key(idx))
.unwrap();
// 插入BTreeMap
inner.handles.insert(value, handle);
value
}
</code></pre>
<h4 id="移除句柄"><a class="header" href="#移除句柄">移除句柄</a></h4>
<p>删除Process中的一个句柄</p>
<pre><code class="language-rust noplaypen">pub fn remove_handle(&amp;self, handle_value: HandleValue) {
self.inner.lock().handles.remove(&amp;handle_value);
}
</code></pre>
<h4 id="根据句柄查找内核对象"><a class="header" href="#根据句柄查找内核对象">根据句柄查找内核对象</a></h4>
<pre><code class="language-rust noplaypen">// src/task/process.rs
impl Process {
/// 根据句柄值查找内核对象,并检查权限
pub fn get_object_with_rights&lt;T: KernelObject&gt;(
&amp;self,
handle_value: HandleValue,
desired_rights: Rights,
) -&gt; ZxResult&lt;Arc&lt;T&gt;&gt; {
let handle = self
.inner
.lock()
.handles
.get(&amp;handle_value)
.ok_or(ZxError::BAD_HANDLE)?
.clone();
// check type before rights
let object = handle
.object
.downcast_arc::&lt;T&gt;()
.map_err(|_| ZxError::WRONG_TYPE)?;
if !handle.rights.contains(desired_rights) {
return Err(ZxError::ACCESS_DENIED);
}
Ok(object)
}
}
</code></pre>
<h4 id="zxresult"><a class="header" href="#zxresult">ZxResult</a></h4>
<p>ZxResult是表示Zircon状态的i32值值空间划分如下</p>
<ul>
<li>0:ok</li>
<li>负值:由系统定义(也就是这个文件)</li>
<li>正值:被保留,用于协议特定的错误值,永远不会被系统定义。</li>
</ul>
<pre><code class="language-rust noplaypen">pub type ZxResult&lt;T&gt; = Result&lt;T, ZxError&gt;;
#[allow(non_camel_case_types, dead_code)]
#[repr(i32)]
#[derive(Debug, Clone, Copy)]
pub enum ZxError {
OK = 0,
...
/// 一个不指向handle的特定的handle value
BAD_HANDLE = -11,
/// 操作主体对于执行这个操作来说是错误的类型
/// 例如: 尝试执行 message_read 在 thread handle.
WRONG_TYPE = -12,
// 权限检查错误
// 调用者没有执行该操作的权限
ACCESS_DENIED = -30,
}
</code></pre>
<p>ZxResult<T>相当于Result&lt;T, ZxError&gt;,也就相当于我们自己定义了一种错误。</p>
<h3 id="单元测试-1"><a class="header" href="#单元测试-1">单元测试</a></h3>
<p>目前为止我们已经实现了Process最基础的方法下面我们来运行一个单元测试</p>
<pre><code class="language-rust noplaypen">fn proc_handle() {
let proc = Process::new();
let handle = Handle::new(proc.clone(), Rights::DEFAULT_PROCESS);
let handle_value = proc.add_handle(handle);
let object1: Arc&lt;Process&gt; = proc
.get_object_with_rights(handle_value, Rights::DEFAULT_PROCESS)
.expect(&quot;failed to get object&quot;);
assert!(Arc::ptr_eq(&amp;object1, &amp;proc));
proc.remove_handle(handle_value);
}
</code></pre>
<h2 id="总结"><a class="header" href="#总结">总结</a></h2>
<p>在这一节中我们实现了内核对象的两个重要的概念句柄Handle和权限Rights同时实现了句柄存储的载体——Process并且实现了Process的基本方法这将是我们继续探索zCore的基础。</p>
<p>在下一节中我们将介绍内核对象的传输器——管道Channel</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="ch01-01-kernel-object.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="ch01-03-channel-object.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="ch01-01-kernel-object.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="ch01-03-channel-object.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script type="text/javascript">
window.playground_copyable = true;
</script>
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="book.js" type="text/javascript" charset="utf-8"></script>
<!-- Custom JS scripts -->
</body>
</html>