对象传送器:Channel 对象

概要

通道(Channel)是由一定数量的字节数据和一定数量的句柄组成的双向消息传输。

描述

通道有两个端点(endpoints)。从逻辑上讲,每个端点都维护要读取的有序消息队列。写入一个端点会将消息排入另一个端点的队列中。当端点的最后一个句柄关闭时,该端点队列中的未读消息将被销毁。因为销毁消息会关闭消息包含的所有句柄,关闭通道端点可能会产生递归效果(例如,通道包含一条消息,它包含一个通道,它包含一条消息,等等)。

关闭通道的最后一个句柄对先前写入该通道的消息的生命周期没有影响。这为通道提供了“即发即忘”的语义。

一条消息由一定数量的数据和一定数量的句柄组成。调用channel_write()使一条消息入队,调用channel_read() 使一条消息出列(如果有队列)。线程可以阻塞,直到消息通过object_wait_one()或其他等待机制挂起。

或者,调用channel_call()在通道的一个方向上将消息入队,等待相应的响应,然后将响应消息出队。在调用模式(call mode)下,相应的响应通过消息的前 4 个字节标识,称为事务 ID(transaction ID)。内核使用channel_call(),为消息提供唯一的事务 ID.

通过通道发送消息的过程有两个步骤。第一步是原子地将数据写入通道并将消息中所有句柄的所有权移到此通道中。此操作始终消耗句柄:在调用结束时,所有句柄要么全部在通道中,要么全部丢弃。第二步操作,通道读取(channel read),与第一步类似:成功后,下一条消息中的所有句柄都被原子地移动到接收进程的句柄表中。失败时,通道将保留所有权,然后它们将被删除。

与许多其他内核对象类型不同,通道是不可复制的。因此,只有一个句柄与通道端点相关联,持有该句柄的进程被视为所有者(owner)。只有所有者可以读取或写入消息或将通道端点发送到另一个进程。

当通道端点的所有权从一个进程转移到另一个进程时,即使消息正在进行写入,消息也不会被重新排序或截断。转移事件之前的消息属于以前的所有者,转移之后的消息属于新的所有者。如果在传输端点时,正在进行消息读取,则之前描述的所有权转移方式同样适用。

即使最后剩余的句柄被剥夺了DUPLICATE权限,也不为其他内核对象提供上述顺序保证。

创建一对内核对象

创建通道

创建 Channel 将返回两个句柄,一个指向对象的每个端点。

实现 Channel::create

讲一下互相持有对方 Weak 指针的目的,这里有不可避免的 unsafe

实现数据传输

当句柄被写入通道时,它们会从发送进程中删除。当从通道读取带有句柄的消息时,句柄被添加到接收进程中。在这两个事件之间,句柄继续存在(确保它们所指的对象继续存在),除非它们写入的通道的末端关闭——此时发送到该端点的消息被丢弃并且它们包含的任何句柄都已关闭。

实现 read, write 函数,read_write 单元测试