|
|
|
|
@ -1,5 +1,27 @@
|
|
|
|
|
# 对象传送器:Channel 对象
|
|
|
|
|
|
|
|
|
|
## 概要
|
|
|
|
|
|
|
|
|
|
通道(Channel)是由一定数量的字节数据和一定数量的句柄组成的双向消息传输。
|
|
|
|
|
|
|
|
|
|
## 描述
|
|
|
|
|
|
|
|
|
|
通道有两个端点(endpoints)。从逻辑上讲,每个端点都维护要读取的有序消息队列。写入一个端点会将消息排入另一个端点的队列中。当端点的最后一个句柄关闭时,该端点队列中的未读消息将被销毁。因为销毁消息会关闭消息包含的所有句柄,关闭通道端点可能会产生递归效果(例如,通道包含一条消息,它包含一个通道,它包含一条消息,等等)。
|
|
|
|
|
|
|
|
|
|
关闭通道的最后一个句柄对先前写入该通道的消息的生命周期没有影响。这为通道提供了“即发即忘”的语义。
|
|
|
|
|
|
|
|
|
|
一条消息由一定数量的数据和一定数量的句柄组成。调用[`channel_write()`](https://fuchsia.dev/docs/reference/syscalls/channel_write)使一条消息入队,调用[`channel_read()`](https://fuchsia.dev/docs/reference/syscalls/channel_read) 使一条消息出列(如果有队列)。线程可以阻塞,直到消息通过[`object_wait_one()`](https://fuchsia.dev/docs/reference/syscalls/object_wait_one)或其他等待机制挂起。
|
|
|
|
|
|
|
|
|
|
或者,调用[`channel_call()`](https://fuchsia.dev/docs/reference/syscalls/channel_call)在通道的一个方向上将消息入队,等待相应的响应,然后将响应消息出队。在调用模式(call mode)下,相应的响应通过消息的前 4 个字节标识,称为事务 ID(transaction ID)。内核使用[`channel_call()`](https://fuchsia.dev/docs/reference/syscalls/channel_call),为消息提供唯一的事务 ID.
|
|
|
|
|
|
|
|
|
|
通过通道发送消息的过程有两个步骤。第一步是原子地将数据写入通道并将消息中所有句柄的所有权移到此通道中。此操作始终消耗句柄:在调用结束时,所有句柄要么全部在通道中,要么全部丢弃。第二步操作,通道读取(channel read),与第一步类似:成功后,下一条消息中的所有句柄都被原子地移动到接收进程的句柄表中。失败时,通道将保留所有权,然后它们将被删除。
|
|
|
|
|
|
|
|
|
|
与许多其他内核对象类型不同,通道是不可复制的。因此,只有一个句柄与通道端点相关联,持有该句柄的进程被视为所有者(owner)。只有所有者可以读取或写入消息或将通道端点发送到另一个进程。
|
|
|
|
|
|
|
|
|
|
当通道端点的所有权从一个进程转移到另一个进程时,即使消息正在进行写入,消息也不会被重新排序或截断。转移事件之前的消息属于以前的所有者,转移之后的消息属于新的所有者。如果在传输端点时,正在进行消息读取,则之前描述的所有权转移方式同样适用。
|
|
|
|
|
|
|
|
|
|
即使最后剩余的句柄被剥夺了**DUPLICATE**权限,也不为其他内核对象提供上述顺序保证。
|
|
|
|
|
|
|
|
|
|
## 创建一对内核对象
|
|
|
|
|
|
|
|
|
|
> 实现 Channel::create
|
|
|
|
|
|