|
|
<!DOCTYPE HTML>
|
|
|
<html lang="cn" class="sidebar-visible no-js light">
|
|
|
<head>
|
|
|
<!-- Book generated using mdBook -->
|
|
|
<meta charset="UTF-8">
|
|
|
<title>🚧 对象传送器:Channel 对象 - 简明 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"><strong aria-hidden="true">1.2.</strong> 🚧 对象管理器:Process 对象</a></li><li class="chapter-item expanded "><a href="ch01-03-channel-object.html" class="active"><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>
|
|
|
<h1 id="对象传送器channel-对象"><a class="header" href="#对象传送器channel-对象">对象传送器:Channel 对象</a></h1>
|
|
|
<h2 id="概要"><a class="header" href="#概要">概要</a></h2>
|
|
|
<p>通道(Channel)是由一定数量的字节数据和一定数量的句柄组成的双向消息传输。</p>
|
|
|
<h2 id="用于ipc的内核对象"><a class="header" href="#用于ipc的内核对象">用于IPC的内核对象</a></h2>
|
|
|
<p>Zircon中用于IPC的内核对象主要有Channel、Socket和FIFO。这里我们主要介绍一下前两个。</p>
|
|
|
<blockquote>
|
|
|
<p><strong>进程间通信</strong>(<strong>IPC</strong>,<em>Inter-Process Communication</em>),指至少两个进程或线程间传送数据或信号的一些技术或方法。进程是计算机系统分配资源的最小单位(进程是分配资源最小的单位,而线程是调度的最小单位,线程共用进程资源)。每个进程都有自己的一部分独立的系统资源,彼此是隔离的。为了能使不同的进程互相访问资源并进行协调工作,才有了进程间通信。举一个典型的例子,使用进程间通信的两个应用可以被分类为客户端和服务器,客户端进程请求数据,服务端回复客户端的数据请求。有一些应用本身既是服务器又是客户端,这在分布式计算中,时常可以见到。这些进程可以运行在同一计算机上或网络连接的不同计算机上。</p>
|
|
|
</blockquote>
|
|
|
<p><code>Socket</code>和<code>Channel</code>都是双向和双端的IPC相关的<code>Object</code>。创建<code>Socket</code>或<code>Channel</code>将返回两个不同的<code>Handle</code>,分别指向<code>Socket</code>或<code>Channel</code>的两端。与channel的不同之处在于,socket仅能传输数据(而不移动句柄),而channel可以传递句柄。</p>
|
|
|
<ul>
|
|
|
<li><code>Socket</code>是面向流的对象,可以通过它读取或写入以一个或多个字节为单位的数据。</li>
|
|
|
<li><code>Channel</code>是面向数据包的对象,并限制消息的大小最多为64K(如果有改变,可能会更小),以及最多1024个<code>Handle</code>挂载到同一消息上(如果有改变,同样可能会更小)。</li>
|
|
|
</ul>
|
|
|
<p>当<code>Handle</code>被写入到<code>Channel</code>中时,在发送端<code>Process</code>中将会移除这些<code>Handle</code>。同时携带<code>Handle</code>的消息从<code>Channel</code>中被读取时,该<code>Handle</code>也将被加入到接收端<code>Process</code>中。在这两个时间点之间时,<code>Handle</code>将同时存在于两端(以保证它们指向的<code>Object</code>继续存在而不被销毁),除非<code>Channel</code>写入方向一端被关闭,这种情况下,指向该端点的正在发送的消息将被丢弃,并且它们包含的任何句柄都将被关闭。</p>
|
|
|
<h2 id="channel"><a class="header" href="#channel">Channel</a></h2>
|
|
|
<p>Channel是唯一一个能传递handle的IPC,其他只能传递消息。通道有两个端点<code>endpoints</code>,对于代码实现来说,<strong>通道是虚拟的,我们实际上是用通道的两个端点来描述一个通道</strong>。两个端点各自要维护一个消息队列,在一个端点写消息,实际上是把消息写入<strong>另一个端点</strong>的消息队列队尾;在一个端点读消息,实际上是从<strong>当前端点</strong>的消息队列的队头读出一个消息。</p>
|
|
|
<p>消息通常含有<code>data</code>和<code>handles</code>两部分,我们这里将消息封装为<code>MessagePacket</code>结构体,结构体中含有上述两个字段:</p>
|
|
|
<pre><code class="language-rust noplaypen">#[derive(Default)]
|
|
|
pub struct MessagePacket {
|
|
|
/// message packet携带的数据data
|
|
|
pub data: Vec<u8>,
|
|
|
/// message packet携带的句柄Handle
|
|
|
pub handles: Vec<Handle>,
|
|
|
}
|
|
|
</code></pre>
|
|
|
<h3 id="实现空的channel对象"><a class="header" href="#实现空的channel对象">实现空的Channel对象</a></h3>
|
|
|
<p>在<code>src</code>目录下创建一个<code>ipc</code>目录,在<code>ipc</code>模块下定义一个子模块<code>channel</code>:</p>
|
|
|
<pre><code class="language-rust noplaypen">// src/ipc/mod.rs
|
|
|
use super::*;
|
|
|
|
|
|
mod channel;
|
|
|
pub use self::channel::*;
|
|
|
</code></pre>
|
|
|
<p>在<code>ipc.rs</code>中引入<code>crate</code>:</p>
|
|
|
<pre><code class="language-rust noplaypen">// src/ipc/channel.rs
|
|
|
|
|
|
use {
|
|
|
super::*,
|
|
|
crate::error::*,
|
|
|
crate::object::*,
|
|
|
alloc::collections::VecDeque,
|
|
|
alloc::sync::{Arc, Weak},
|
|
|
spin::Mutex,
|
|
|
};
|
|
|
</code></pre>
|
|
|
<p>把在上面提到的<code>MessagePacket</code>结构体添加到该文件中。</p>
|
|
|
<p>下面我们添加Channel结构体:</p>
|
|
|
<pre><code class="language-rust noplaypen">// src/ipc/channel.rs
|
|
|
pub struct Channel {
|
|
|
base: KObjectBase,
|
|
|
peer: Weak<Channel>,
|
|
|
recv_queue: Mutex<VecDeque<T>>,
|
|
|
}
|
|
|
|
|
|
type T = MessagePacket;
|
|
|
</code></pre>
|
|
|
<p><code>peer</code>代表当前端点所在管道的另一个端点,两端的结构体分别持有对方的<code>Weak</code>引用,并且两端的结构体将分别通过<code>Arc</code>引用,作为内核对象而被内核中的其他数据结构引用,这一部分我们将在创建Channel实例时提到。</p>
|
|
|
<p><code>recv_queue</code>代表当前端点维护的消息队列,它使用<code>VecDeque</code>来存放<code>MessagePacket</code>,可以通过<code>pop_front()</code>、<code>push_back</code>等方法在队头弹出数据和在队尾压入数据。</p>
|
|
|
<p>用使用宏自动实现 <code>KernelObject</code> trait ,使用channel类型名,并添加两个函数。</p>
|
|
|
<pre><code class="language-rust noplaypen">impl_kobject!(Channel
|
|
|
fn peer(&self) -> ZxResult<Arc<dyn KernelObject>> {
|
|
|
let peer = self.peer.upgrade().ok_or(ZxError::PEER_CLOSED)?;
|
|
|
Ok(peer)
|
|
|
}
|
|
|
fn related_koid(&self) -> KoID {
|
|
|
self.peer.upgrade().map(|p| p.id()).unwrap_or(0)
|
|
|
}
|
|
|
);
|
|
|
</code></pre>
|
|
|
<h3 id="实现创建channel的方法"><a class="header" href="#实现创建channel的方法">实现创建Channel的方法</a></h3>
|
|
|
<p>下面我们来实现创建一个<code>Channel</code>的方法:</p>
|
|
|
<pre><code class="language-rust noplaypen">impl Channel {
|
|
|
|
|
|
#[allow(unsafe_code)]
|
|
|
pub fn create() -> (Arc<Self>, Arc<Self>) {
|
|
|
let mut channel0 = Arc::new(Channel {
|
|
|
base: KObjectBase::default(),
|
|
|
peer: Weak::default(),
|
|
|
recv_queue: Default::default(),
|
|
|
});
|
|
|
let channel1 = Arc::new(Channel {
|
|
|
base: KObjectBase::default(),
|
|
|
peer: Arc::downgrade(&channel0),
|
|
|
recv_queue: Default::default(),
|
|
|
});
|
|
|
// no other reference of `channel0`
|
|
|
unsafe {
|
|
|
Arc::get_mut_unchecked(&mut channel0).peer = Arc::downgrade(&channel1);
|
|
|
}
|
|
|
(channel0, channel1)
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p>该方法的返回值是两端点结构体(Channel)的<code>Arc</code>引用,这将作为内核对象被内核中的其他数据结构引用。两个端点互相持有对方<code>Weak</code>指针,这是因为一个端点无需引用计数为0,只要<code>strong_count</code>为0就可以被清理掉,即使另一个端点指向它。</p>
|
|
|
<blockquote>
|
|
|
<p>rust 语言并没有提供垃圾回收 (GC, Garbage Collection ) 的功能, 不过它提供了最简单的引用计数包装类型 <code>Rc</code>,这种引用计数功能也是早期 GC 常用的方法, 但是引用计数不能解决循环引用。那么如何 fix 这个循环引用呢?答案是 <code>Weak</code> 指针,只增加引用逻辑,不共享所有权,即不增加 strong reference count。由于 <code>Weak</code> 指针指向的对象可能析构了,所以不能直接解引用,要模式匹配,再 upgrade。</p>
|
|
|
</blockquote>
|
|
|
<p>下面我们来分析一下这个<code>unsafe</code>代码块:</p>
|
|
|
<pre><code class="language-rust noplaypen">unsafe {
|
|
|
Arc::get_mut_unchecked(&mut channel0).peer = Arc::downgrade(&channel1);
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p>由于两端的结构体将分别通过 <code>Arc</code> 引用,作为内核对象而被内核中的其他数据结构使用。因此,在同时初始化两端的同时,将必须对某一端的 Arc 指针进行获取可变引用的操作,即<code>get_mut_unchecked</code>接口。当 <code>Arc</code> 指针的引用计数不为 <code>1</code> 时,这一接口是非常不安全的,但是在当前情境下,我们使用这一接口进行<code>IPC</code> 对象的初始化,安全性是可以保证的。</p>
|
|
|
<h3 id="单元测试"><a class="header" href="#单元测试">单元测试</a></h3>
|
|
|
<p>下面我们写一个单元测试,来验证我们写的<code>create</code>方法:</p>
|
|
|
<pre><code class="language-rust noplaypen">#[test]
|
|
|
fn test_basics() {
|
|
|
let (end0, end1) = Channel::create();
|
|
|
assert!(Arc::ptr_eq(
|
|
|
&end0.peer().unwrap().downcast_arc().unwrap(),
|
|
|
&end1
|
|
|
));
|
|
|
assert_eq!(end0.related_koid(), end1.id());
|
|
|
|
|
|
drop(end1);
|
|
|
assert_eq!(end0.peer().unwrap_err(), ZxError::PEER_CLOSED);
|
|
|
assert_eq!(end0.related_koid(), 0);
|
|
|
}
|
|
|
</code></pre>
|
|
|
<h3 id="实现数据传输"><a class="header" href="#实现数据传输">实现数据传输</a></h3>
|
|
|
<p>Channel中的数据传输,可以理解为<code>MessagePacket</code>在两个端点之间的传输,那么谁可以读写消息呢?</p>
|
|
|
<p>有一个句柄与通道端点相关联,持有该句柄的进程被视为所有者(owner)。所以是(持有与通道端点关联句柄的)进程可以读取或写入消息,或将通道端点发送到另一个进程。</p>
|
|
|
<p>当<code>MessagePacket</code>被写入通道时,它们会从发送进程中删除。当从通道读取<code>MessagePacket</code>时,<code>MessagePacket</code>的句柄被添加到接收进程中。</p>
|
|
|
<h4 id="read"><a class="header" href="#read">read</a></h4>
|
|
|
<p>获取当前端点的<code>recv_queue</code>,从队头中读取一条消息,如果能读取到消息,返回<code>Ok</code>,否则返回错误信息。</p>
|
|
|
<pre><code class="language-rust noplaypen">pub fn read(&self) -> ZxResult<T> {
|
|
|
let mut recv_queue = self.recv_queue.lock();
|
|
|
if let Some(_msg) = recv_queue.front() {
|
|
|
let msg = recv_queue.pop_front().unwrap();
|
|
|
return Ok(msg);
|
|
|
}
|
|
|
if self.peer_closed() {
|
|
|
Err(ZxError::PEER_CLOSED)
|
|
|
} else {
|
|
|
Err(ZxError::SHOULD_WAIT)
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<h4 id="write"><a class="header" href="#write">write</a></h4>
|
|
|
<p>先获取当前端点对应的另一个端点的<code>Weak</code>指针,通过<code>upgrade</code>接口升级为<code>Arc</code>指针,从而获取到对应的结构体对象。在它的<code>recv_queue</code>队尾push一个<code>MessagePacket</code>。</p>
|
|
|
<pre><code class="language-rust noplaypen">pub fn write(&self, msg: T) -> ZxResult {
|
|
|
let peer = self.peer.upgrade().ok_or(ZxError::PEER_CLOSED)?;
|
|
|
peer.push_general(msg);
|
|
|
Ok(())
|
|
|
}
|
|
|
fn push_general(&self, msg: T) {
|
|
|
let mut send_queue = self.recv_queue.lock();
|
|
|
send_queue.push_back(msg);
|
|
|
}
|
|
|
</code></pre>
|
|
|
<h3 id="单元测试-1"><a class="header" href="#单元测试-1">单元测试</a></h3>
|
|
|
<p>下面我们写一个单元测试,验证我们上面写的<code>read</code>和<code>write</code>两个方法:</p>
|
|
|
<pre><code class="language-rust noplaypen">#[test]
|
|
|
fn read_write() {
|
|
|
let (channel0, channel1) = Channel::create();
|
|
|
// write a message to each other
|
|
|
channel0
|
|
|
.write(MessagePacket {
|
|
|
data: Vec::from("hello 1"),
|
|
|
handles: Vec::new(),
|
|
|
})
|
|
|
.unwrap();
|
|
|
|
|
|
channel1
|
|
|
.write(MessagePacket {
|
|
|
data: Vec::from("hello 0"),
|
|
|
handles: Vec::new(),
|
|
|
})
|
|
|
.unwrap();
|
|
|
|
|
|
// read message should success
|
|
|
let recv_msg = channel1.read().unwrap();
|
|
|
assert_eq!(recv_msg.data.as_slice(), b"hello 1");
|
|
|
assert!(recv_msg.handles.is_empty());
|
|
|
|
|
|
let recv_msg = channel0.read().unwrap();
|
|
|
assert_eq!(recv_msg.data.as_slice(), b"hello 0");
|
|
|
assert!(recv_msg.handles.is_empty());
|
|
|
|
|
|
// read more message should fail.
|
|
|
assert_eq!(channel0.read().err(), Some(ZxError::SHOULD_WAIT));
|
|
|
assert_eq!(channel1.read().err(), Some(ZxError::SHOULD_WAIT));
|
|
|
}
|
|
|
</code></pre>
|
|
|
<h2 id="总结"><a class="header" href="#总结">总结</a></h2>
|
|
|
<p>在这一节中我们实现了唯一一个可以传递句柄的对象传输器——Channel,我们先了解的Zircon中主要的IPC内核对象,再介绍了Channel如何创建和实现read和write函数的细节。</p>
|
|
|
<p>本章我们学习了中最核心的几个内核对象,在下一章中,我们将学习<code>Zircon</code>的任务管理体系和进程、线程管理的对象。</p>
|
|
|
|
|
|
</main>
|
|
|
|
|
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
|
<!-- Mobile navigation buttons -->
|
|
|
<a rel="prev" href="ch01-02-process-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="ch02-00-task.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-02-process-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="ch02-00-task.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>
|