Zircon 系统接口评分准则

Zircon 系统接口表示为 libzircon.so vDSO API 接口。

属于接口的函数必须具有以 zx_ 开头的名称,而预处理器宏必须具有以 ZX_ 开头的名称。作为接口的一部分定义的类型,其名称必须以 zx_ 开头,并以 _t 结尾。

属于接口的每个函数都必须在 /docs/zircon/syscalls/ 中使用 Markdown 文件进行记录,并从 /docs/zircon/syscalls.md 链接。

函数名称

函数的名称必须完全由小写字母和下划线组成,并且符合以下语法:

zx_<noun>_<verb>{_<direct-object>}

例如:

zx_handle_close, zx_channel_write, zx_object_signal_peer

通常,名词是内核对象类型,但也可以是其他名词,例如没有对应内核对象的 clock 或 ticks。其他函数则使用更抽象的名词,例如 system 或 status。

名词和动词不得包含下划线(以免混淆语法)。名词和动词应各为一个英文单词,但如果没有合适的单词或单词太长,则可以使用首字母缩略词(或缩写词)。

直接宾语可能包含下划线。

有些函数会执行复合运算。在这种情况下,可以通过串联组件操作的名称来命名函数。

某些函数会针对多种类型的内核对象执行操作,在这种情况下,名词是更抽象的对象类型。例如,带有名词 object 的函数可对大多数内核对象执行操作,而带有名词 task 的函数可对作业、进程和线程执行操作。

类型

使用 zx_status_t 表示成功和失败。

使用固定大小的整数类型。函数不得使用 short、int 或 unsigned long(或类似类型)。请改用 int16_t、int32_t 和 uint64_t 等类型。

对缓冲区长度、元素大小和元素计数使用 size_t。

使用 void* 指向调用方地址空间中的任意类型。对于可能位于其他地址空间中的地址,请使用 zx_vaddr_t / zx_paddr_t。

使用 zx_time_t 设置超时,超时必须以系统单调时钟时基中的绝对截止时间(以纳秒为单位)表示。在绝对截止时间没有意义的情况下(例如,计时器松弛),请使用 zx_duration_t 表示以纳秒为单位的时间量,不使用特定时基。

参数

接收器

绝大多数函数都作用于句柄,句柄是对内核对象的引用,其类型与函数名称中的名词相匹配。此句柄是此类函数的第一个参数,称为接收器。

将接收器命名为 handle。

对象创建函数(例如 zx_channel_create、zx_event_create)可能不接受句柄参数。这些函数会隐式地对当前进程执行操作。

选项参数

函数通常包含一个 options 参数,以便允许使用影响操作的标志,并留出空间以便在未来修订 API 时添加更多标志。

对 options 参数使用类型 uint32_t 和名称 options。

如果存在 options 参数,则该参数必须是接收器句柄之后的第一个实参;如果函数没有接收器,则该参数必须是第一个实参。

并非所有函数都需要 options 参数。

各个选项值必须定义为预处理器宏,用于将数字字面量转换为 uint32_t。这些选项必须是可以使用按位 | 运算符组合的位标志。

对结构体进行版本编号

跨越系统调用边界的结构是 ABI 的一部分,无法就地更改。接受或返回结构体的函数必须具有一个参数,以便调用方指定结构体的版本,例如 topic 参数或 options 参数中预留的版本位。请勿向结构体本身添加版本字段。

如需更改现有结构体,请按照对系统调用结构体进行版本控制中所述添加新的版本化结构体。

句柄

当函数将句柄作为形参时,该函数必须始终使用句柄或从不使用句柄,但以下情况除外:

  • 如果函数接受 options 参数,则该函数可能具有非默认选项,以避免在各种错误条件下消耗句柄。

  • 如果函数不接受 options 参数,则在返回 ZX_ERR_SHOULD_WAIT 时,函数可能会避免使用句柄。

包含数据、计数/大小和/或实际值的缓冲区

始终为数组或缓冲区(包括字符串)提供计数或大小(类型为 size_t)。如果缓冲区由函数写入,则函数必须具有一个 out 参数,用于返回所写入数据的计数或大小。

对于读写样式操作,指向缓冲区的指针后跟缓冲区计数或大小,如果可能发生短读或短写,则输出参数会在成功时提供实际计数或大小:

zx_status_t zx_socket_write(zx_handle_t handle, uint32_t options,
                            const void* buffer, size_t size, size_t* actual);

当存在多个缓冲区时,缓冲区、长度和输出参数会以一致的顺序交错显示。例如,请参阅 zx_channel_read:

zx_status_t zx_channel_read(zx_handle_t handle, uint32_t options,
                            void* bytes, zx_handle_t* handles,
                            uint32_t num_bytes, uint32_t num_handles,
                            uint32_t* actual_bytes, uint32_t* actual_handles);

输出

out 参数是由函数写入的标量值。例如,通过写入 uint32_t 来返回 CPU 数量的函数具有 out 参数。如果函数填充了客户端提供的缓冲区,则该缓冲区不是 out 参数。

输出参数始终位于参数列表的末尾。

out 参数不得同时也是 in 参数。例如,如果某个函数具有一个 out 形参,该形参用于返回写入缓冲区的字节数,则该函数不得同时使用该形参从调用方接收缓冲区的长度。

返回值类型

绝大多数函数的返回值类型为 zx_status_t,成功时为 ZX_OK,失败时为 ZX_ERR_...。

请勿通过 zx_status_t 返回其他值,例如使用正值范围。请改用 out 参数。

其他返回值类型可用于不会失败的函数。例如,zx_thread_exit 始终会成功退出线程,并且返回值类型为 void。同样,zx_clock_get_monotonic 无法获取当前时间,其返回值类型为 zx_time_t。

特定于函数的规则

zx_object_get_property 与 zx_object_get_info

有两种类似的机制可用于公开对象的相关数据:zx_object_get_property 和 zx_object_get_info。如果 (a) 可以使用 zx_object_set_property 设置属性,或者 (b) 属性存在于多种类型的对象中,则最好通过 zx_object_get_property 公开数据。在其他情况下,请考虑将数据包含在具有该属性的对象类型的常规 zx_object_get_info 主题中。