Fuchsia | Zircon Handles

306 阅读9分钟
  1. 本文写于2021年6月末,可能官方文档会继续更新,因此不能保证在将来本文依然对大家有帮助。
  2. 英文原文使用了非常长的定语从句,由于能力有限,尽量拆分为小段句子,并尽量能让中文读起来顺畅。
  3. 尽量保留专业术语&词汇,以免引起二义性。
  4. 由于目前对 Fuchsia 和 Zircon 不熟悉,难免有翻译失误的地方,欢迎斧正。
  5. 一边翻译一边学习,暂时不能理解的地方留了 TODO,争取以后补上。对暂时不知如何翻译的单词会用【 xxx 】做翻译参考。
  6. 上班996,下班有空做翻译,不能保证更新速度。
  7. 谢绝转载
  8. 谢绝转载
  9. 谢绝转载

基础知识 | Basics

Handles are kernel constructs that allow user-mode programs to reference a kernel object. A handle can be thought of as a session or connection to a particular kernel object.

Handle 是 kernel 的组成部分,它允许 user-mode 的程序能引用 kernel object。Handle 可以被认为是与一个特定 kernel object 的会话或连接。

It is often the case that multiple processes concurrently access the same object via different handles. However, a single handle can only be either bound to a single process or be bound to the kernel.

通常情况下,多个 process 通过多个 handle 同时访问同一个 object。但单个 handle 只能被绑定到单个 process 或 kernel。

When it is bound to the kernel we say it's ‘in-transit’.

当其被绑定到 kernel,我们称它是 in-transit 【传输中】

In user mode a handle is simply a specific number returned by some syscall. Only handles that are not in-transit are visible to user-mode.

在 user mode 中,handle 是一个由某个 syscall 返回的确定数值。只有那些非 in-transit 的 handle 才对 user-mode 可见。

The integer that represents a handle is only meaningful for that process. The same number in another process might not map to any handle or it might map to a handle pointing to a completely different kernel object.

这个整型数字所代表的 handle 仅对这个 process 有意义。在其他 process 中的同一数字可能不会映射到任何 handle,或者可能映射到指向完全不同 kernel object 的 handle。

The integer value for a handle is any 32-bit number except the value corresponding toZX_HANDLE_INVALID which will always have the value of 0. In addition to this, the integer value of a valid handle will always have two least significant bits of the handle set. The mask representing these bits may be accessed using ZX_HANDLE_FIXED_BITS_MASK

Handle 的整型数值是任意32位数字,值永远为 0 的 ZX_HANDLE_INVALID 除外。除此之外,有效 handle 的整型数值总是将2个最低有效位置位。这些位的掩码可以通过 (掘金:摩卡Code)ZX_HANDLE_FIXED_BITS_MASK 获取。

【注: #define ZX_HANDLE_INVALID ((zx_handle_t)0) #define ZX_HANDLE_FIXED_BITS_MASK ((zx_handle_t)0x3) 】

For kernel mode, a handle is a C++ object that contains three logical fields:

  • A reference to a kernel object
  • The rights to the kernel object
  • The process it is bound to (or if it's bound to the kernel)

对于 kernel mode,handle 是一个包含了3个逻辑字段的C++ object:

  • 对 kernel object 的引用
  • 访问 kernel object 的权限
  • 它所绑定的 process 或 kernel

The ‘rights’ specify what operations on the kernel object are allowed. It is possible for a single process to have two different handles to the same kernel object with different rights.

“权限”规定了对 kernel object 能进行哪些操作。对单个 process 中的 2个不同 handle,即使都引用同一个 kernel object,它们也可能有不同的权限。

1.png

Figure 1. A user process starts the creation of a handle.

↑图1:一个用户 process 开始创建 一个 handle。

2.png

Figure 2. The user process creates the kernel object (for example, an event) with a system call and holds an integer reference to the object.

↑图2:用户 process 通过一个 system call 创建了 kernel object(例如 event),并保存了引用该 object 的 整型值【即 handle】。

3.png

Figure 3. Handles are created with a set of basic rights and any additional rights applicable to the kernel object type.

↑图3:创建的 Handle 被赋予了一些基本权限,以及任何适用于 kernel object 的额外权限。

4.png

Figure 4. Handles can be duplicated. Rights can be dropped during this process.

↑图4:Handle 可以被复制。权限可以在复制过程中被删掉。

【注:图中创建的 event 对象,先由 ev0 引用,且 ev0 拥有基本权限和 signaling 权限。当 ev1 被复制出来后,仅赋予其 wait 权限。尽管这两个 Handle 都引用同一个 event 对象。】

使用 Handle | Using Handles

There are many syscalls that create a new kernel object and that return a handle to it. To name a few:

有很多 syscall 能创建新的 kernel object 并且返回一个引用它的 handle。例如:

  • zx_event_create()
  • zx_process_create()
  • zx_thread_create()

These calls create both the kernel object and the first handle pointing to it. The handle is bound to the process that issued the syscall and the rights are the default rights for that type of kernel object.

这些调用既创建了 kernel object 又创建了第一个指向它的 handle。该 handle 被绑定到了调用 syscall 的 process 上,并且被赋予了该 kernel object 类型的默认权限。

There is only one syscall that can make a copy of a handle, which points to the same kernel object and is bound to the same process that issued the syscall:

↓仅有一个 syscall 能复制 handle,复制出来的 handle 引用同一个 kernel object,并且被绑定到调用该 syscall 的 process 上。

  • zx_handle_duplicate()

There is one syscall that creates an equivalent handle (possibly with fewer rights), invalidating the original handle:

↓该 syscall 能创建一个等同的 handle (权限可能减少),并使得原来的 handle 失效。(juejin.cn:摩卡Code)

  • zx_handle_replace()

There is one syscall that just destroys a handle:

↓该 syscall 用于销毁 handle。

  • zx_handle_close()

There is one syscall that takes a handle bound to the calling process and binds it into the kernel (puts the handle in-transit):

↓该 syscall 用于将绑定在调用 process 上的 handle 绑定到 kernel(将 handle in-transit)。

  • zx_channel_write()

There are two syscalls that take an in-transit handle and bind it to the calling process:

↓这两个 syscall 将 in-transit handle 读取出来并绑定到调用 process 中。

  • zx_channel_read()
  • zx_channel_call()

The channel and socket syscalls above are used to transfer a handle from one process to another. For example it is possible to connect two processes with a channel. To transfer a handle the source process calls zx_channel_write or zx_channel_call and then the destination process callszx_channel_read on the same channel.

上面 channel 和 socket 的 syscall 用于将 handle 从一个 process 传输到另一个 process 中。例如用一个 channel 将两个 process 连接起来,源 process 对 channel 调用 zx_channel_write 或 zx_channel_call 来发送一个 handle,目标 process 对相同 channel 调用 zx_channel_read 来读取 handle。

Finally, there is a single syscall that gives a new process its bootstrapping handle, that is, the handle that it can use to request other handles:

↓最后,该 syscall 可以为新 process 提供 bootstrapping【引导】handle,该 handle 能被用于获取其他 handle。

  • zx_process_start()

The bootstrapping handle can be of any transferable kernel object but the most reasonable case is that it points to one end of a channel so this initial channel can be used to send further handles into the new process.

Bootstrapping【引导】handle 可以是任意能被传输的 kernel object,但最合理的情况是,它指向一个 channel 的一端,如此一来该 channel 就能向新 process 中发送更多 handle。

【注:可以查阅下该函数的说明文档,对参数讲的比较细致。】

垃圾回收 | Garbage Collection

If a handle is valid, the kernel object it points to is guaranteed to be valid. This is ensured because kernel objects are ref-counted and each handle holds a reference to its kernel object.

如果一个 handle 是有效的,那么它所引用的 kernel object 也保证是有效的。这个机制能确保有效是由于 kernel object 采用引用计数,而每个 handle 都拥有其对 kernel object 的一个引用计数。

【注:创建一个 object 并使用一个 handle 引用它,此时引用计数默认为1,以后每创建一个引用它的handle,引用计数则加1,反之每销毁一个引用它的 handle,引用计数减1,当所有 handle 都被销毁,引用计数为0,此时销毁该 object。】

The opposite does not hold. When a handle is destroyed it does not mean its object is destroyed. There could be other handles pointing to the object or the kernel itself could be holding a reference to the kernel object. An example of this is a handle to a thread; the fact that the last handle to a thread is closed it does not mean that the thread has been terminated.

反过来并不成立。当一个 handle 被销毁时,并不意味着它引用的 object 也被销毁。可能会有其它的 handle 指向这个 object 或者 kernel 本身引用了这个 kernel object。例如当一个 handle 引用了 thread,事实上当最后一个引用该 thread 的 handle 被销毁时,也并不意味着该 thread 被终止了。

【注:也就是 kernel 依然在引用该 thread。】

When the last reference to a kernel object is released, the kernel object is either destroyed or the kernel marks the object for garbage collection; the object will be destroyed at a later time when the current set of pending operations on it is completed.

当最后一个指向 kernel object 的引用被释放时,该 kernel object 要么被销毁,要么 kernel 将其标记为垃圾回收对象;当在该 object 上挂起的一系列操作完成,稍后一段时间内该 object 就会被销毁。(掘金:摩卡Code)

特例 | Special Cases

When a handle is in-transit and the channel or socket it was written to is destroyed, the handle is closed.

当一个 handle 在 in-transit【传输中】时,并且它被写入的 channel 或者 socket 被销毁了, handle 会被关闭。

Debugging sessions (and debuggers) might have special syscalls to get access to handles.

调试会话(和调试程序)可能会有特殊的 syscall 来访问 handle。

非法 handle 与 handle 重用 | Invalid Handles and handle reuse

It is an error to pass to any syscall except for zx_object_get_info the following values:

  • A handle value that corresponds to a closed handle
  • The ZX_HANDLE_INVALID value, except for zx_handle_close syscall

除 zx_object_get_info 外,对其他任意 syscall 传递下面两种类型的 handle 都是错误的:

  • 已经被关闭 handle 对应的值
  • ZX_HANDLE_INVALID【也就是null 或 0】,该值对 zx_handle_close 例外。

The kernel is free to re-use the integer values of closed handles for newly created objects. Therefore, it is important to make sure that proper handle hygiene is observed:

  • Don't have one thread close a given handle and another thread use the same handle in a racy way. Even if the second thread is also closing it.
  • Don't ignore ZX_ERR_BAD_HANDLE return codes. They usually mean the code has a logic error.

Kernel 可以对新创建的 object 自由重用已经被关闭的 handle 对应的整数值。因此,遵守合适的 handle 规则是非常重要的

  • 不要让一个 thread 去关闭一个给定的 handle,并且在另一个 thread 中以一种不规范的方式使用相同的 handle。即使第二个 thread 也关闭了这个 handle。
  • 不要忽略 ZX_ERR_BAD_HANDLE 返回值。者通常说明代码有逻辑错误。

【注:第一点不是很明白 TODO】

Detecting invalid handle usage can be automated by using the ZX_POL_BAD_HANDLE Job policy with ZX_POL_ACTION_EXCEPTION to generate an exception when a process under such job object attempts any of the mentioned invalid cases.

自动化检查非法 handle 的使用情况,可以通过使用 ZX_POL_BAD_HANDLE 这种 Job 策略,一旦该 Job object 下的任意 process 尝试以上提到的非法使用方式,就会抛出一个 ZX_POL_ACTION_EXCEPTION 异常,

【注:这里可以阅读下代码 zircon/kernel/object/ob_policy.cc】

qrcode_for_gh_bd971a719771_258.jpg

喜欢的话可以关注微信公众号:摩卡Code (MochaCode)