同步文件 API 指南

作者:

Gustavo Padovan <gustavo at padovan dot org>

本文档旨在指导设备驱动程序编写者了解同步文件 API 是什么,以及驱动程序如何支持它。同步文件是围栏(struct dma_fence)的载体,这些围栏是在驱动程序之间或跨进程边界进行同步所必需的。

同步文件 API 旨在用于向/从用户空间发送和接收围栏信息。它使用户空间能够进行显式围栏,其中生产者驱动程序(例如 GPU 或 V4L 驱动程序)不是将围栏附加到缓冲区,而是通过同步文件将与缓冲区相关的围栏发送到用户空间。

然后,可以将同步文件发送到消费者(例如 DRM 驱动程序),在围栏发出信号之前,它不会使用该缓冲区进行任何操作,即,发出围栏的驱动程序不再使用/处理缓冲区,因此它会发出信号,表明该缓冲区已准备好使用。对于消费者 -> 生产者循环的另一部分也是如此。

同步文件使用户空间能够了解驱动程序之间缓冲区共享的同步情况。

同步文件最初是在 Android 内核中添加的,但当前的 Linux 桌面可以从中受益匪浅。

输入围栏和输出围栏

同步文件可以从用户空间发送到驱动程序,也可以从驱动程序发送到用户空间。当同步文件从驱动程序发送到用户空间时,我们将其包含的围栏称为“输出围栏”。它们与驱动程序正在处理或将要处理的缓冲区相关,因此驱动程序会创建一个输出围栏,以便在完成使用(或处理)该缓冲区时,通过 dma_fence_signal() 发出通知。输出围栏是驱动程序创建的围栏。

另一方面,如果驱动程序通过用户空间的同步文件接收围栏,我们将其称为“输入围栏”。接收输入围栏意味着我们需要等待围栏发出信号,然后才能使用与输入围栏相关的任何缓冲区。

创建同步文件

当驱动程序需要将输出围栏发送到用户空间时,它会创建一个同步文件。

接口

struct sync_file *sync_file_create(struct dma_fence *fence);

调用者传递输出围栏并返回同步文件。这只是第一步,接下来需要在 sync_file->file 上安装一个 fd。所以它获得一个 fd

fd = get_unused_fd_flags(O_CLOEXEC);

并将其安装在 sync_file->file 上

fd_install(fd, sync_file->file);

现在可以将同步文件 fd 发送到用户空间。

如果创建过程失败,或者由于任何其他原因需要释放同步文件,则应使用 fput(sync_file->file)。

从用户空间接收同步文件

当用户空间需要将输入围栏发送到驱动程序时,它会将同步文件的文件描述符传递给内核。然后,内核可以从中检索围栏。

接口

struct dma_fence *sync_file_get_fence(int fd);

返回的引用由调用者拥有,之后必须使用 dma_fence_put() 释放。如果发生错误,则返回 NULL。

参考

  1. struct sync_file 在 include/linux/sync_file.h 中

  2. 上面提到的所有接口都在 include/linux/sync_file.h 中定义