channel_call —— 向channel发送消息并等待响应
#include <zircon/syscalls.h>
typedef struct {
void* wr_bytes;
zx_handle_t* wr_handles;
void *rd_bytes;
zx_handle_t* rd_handles;
uint32_t wr_num_bytes;
uint32_t wr_num_handles;
uint32_t rd_num_bytes;
uint32_t rd_num_handles;
} zx_channel_call_args_t;
zx_status_t zx_channel_call(zx_handle_t handle, uint32_t options,
zx_time_t deadline, zx_channel_call_args_t* args,
uint32_t* actual_bytes, uint32_t* actual_handles);
channel_call() 类似于channel_write(),object_wait_one() 和channel_read() 三者的组合。只是在此基础上添加了一个功能——消息有效负载字节前面的事务id用于匹配回复消息和发送消息,并启用多个调用线程来共享同一channel,而无需任何额外的用户空间记录。
此操作的在写入和读取阶段的行为类似于channel_write() 和channel_read(),区别在于它们的参数是通过zx_channel_call_args_t结构体提供的。
写入和回读消息的前四个字节被当作类型是zx_txid_t 的事务ID。内核为写入的消息生成txid,并将消息的那部分替换为从用户空间读取的消息。内核生成的txid值处于0x80000000和0xFFFFFFFF之间,并且不会与来自此channel端点的任何其他channel_call() 的任何txid发生冲突。如果写入的消息的长度少于四个字节,则会报告错误。
当写入传出消息的同时,同一txid的传入消息的兴趣会被同时注册上。
在deadline尚未到来时,如果传入消息在到达时txid匹配,则不会添加到常规传入消息队列的尾部,而是直接将其传递给在zx_channel_call() 中等待的线程。
如果在deadline之后回复到达,它将到达常规的传入消息队列,并导致ZX_CHANNEL_READABLE信号被触发,等等。
在这种情况下,将丢弃太大而不适合rd_num_bytes和rd_num_handles的传入消息,并返回ZX_ERR_BUFFER_TOO_SMALL。
与zx_channel_write() 一样,handles中的句柄始终由zx_channel_call() 持有,并不再存在于调用进程中。
TODO(ZX-2399)
channel_call() 调用成功则返回ZX_OK,并分别通过actual_bytes和actual_handles返回消息中的字节数和句柄数。
ZX_ERR_BAD_HANDLE:handle是无效句柄,handles中存在无效句柄,或handles数组中的句柄存在重复项。
ZX_ERR_WRONG_TYPE:handle不是channel类型句柄。
ZX_ERR_INVALID_ARGS:提供的指针存在无效或为null的,或wr_num_bytes小于4,或者options为非零。
ZX_ERR_ACCESS_DENIED:handle没有ZX_RIGHT_WRITE权限,或handles中的存在没有ZX_RIGHT_TRANSFER权限的元素。
ZX_ERR_PEER_CLOSED:在等待回复时,channel的另一侧已关闭或将要被关闭。
ZX_ERR_CANCELED:handle在等待回复时被关闭。
ZX_ERR_NO_MEMORY:由于内存不足导致的失败。而用户空间无法处理这个(不太可能发生的)错误。在将来的构建版本中,将不再出现此错误。
ZX_ERR_OUT_OF_RANGE: wr_num_bytes或wr_num_handles大于channel最大允许的消息大小。
ZX_ERR_BUFFER_TOO_SMALL:rd_num_bytes或rd_num_handles太小而无法存放回复消息。
ZX_ERR_NOT_SUPPORTED: handles中的一个句柄是(正在被写入的通道句柄的)handle本身。
如果遵循以下规则,channel_call() 提供的工具可以直接与使用channel_read() 和channel_write() 的消息调度程序进行互操作:
- 通过channel_read() 接收同步消息的服务端应确保传入消息的txid通过channel_write() 反映在传出响应中,以便使用channel_call() 的客户端可以正确路由到回复消息。
- 通过channel_write() 发送消息的客户端确保它仅使用介于0和0x7FFFFFFF之间的txid,以避免与通过channel_call() 通信的其他线程发生冲突。
如果channel_call() 由于ZX_ERR_TIMED_OUT 原因而返回,如果服务端在将来的某个时刻最终回复消息,则回复可能会匹配到另一个传出请求上(自原先请求以来已经经历了大约2^31个channel_call())。但这在我们的设计中,这是安全的,因为此系统调用的设计期望是,超时通常是致命错误导致的,所以客户端不太可能在超时的通道上继续通信。
handle_close,handle_duplicate,handle_replace,object_wait_one,object_wait_many,channel_create,channel_read,channel_write。