英语

futex2

作者:

André Almeida <andrealmeid@collabora.com>

futex,或快速用户互斥锁,是一组系统调用,允许用户空间创建高性能的同步机制,例如用户空间中的互斥锁、信号量和条件变量。 C标准库(如glibc)使用它作为实现更高级接口(如pthreads)的一种手段。

futex2是初始futex系统调用的后续版本,旨在克服原始接口的限制。

用户API

futex_waitv()

等待 futex 数组,在任何一个上唤醒

futex_waitv(struct futex_waitv *waiters, unsigned int nr_futexes,
            unsigned int flags, struct timespec *timeout, clockid_t clockid)

struct futex_waitv {
      __u64 val;
      __u64 uaddr;
      __u32 flags;
      __u32 __reserved;
};

用户空间设置一个 struct futex_waitv 数组(最多 128 个条目),使用 uaddr 作为等待的地址,val 作为期望的值,以及 flags 来指定 futex 的类型(例如 private)和大小。 __reserved 需要为 0,但可以用于将来的扩展。 数组第一个项目的指针作为 waiters 传递。 waiters 或任何 uaddr 的无效地址返回 -EFAULT

如果用户空间有 32 位指针,它应该进行显式转换以确保高位为零。uintptr_t 做了巧妙的处理,它适用于 32/64 位指针。

nr_futexes 指定数组的大小。超出 [1, 128] 区间的数字将使系统调用返回 -EINVAL

系统调用的 flags 参数需要为 0,但可以用于将来的扩展。

对于 waiters 数组中的每个条目,将 uaddr 处的当前值与 val 进行比较。如果不同,系统调用将撤消到目前为止所做的所有工作并返回 -EAGAIN。如果所有测试和验证都成功,系统调用将等待直到发生以下情况之一

  • 超时到期,返回 -ETIMEOUT

  • 向睡眠任务发送了一个信号,返回 -ERESTARTSYS

  • 列表中的某个 futex 被唤醒,返回某个被唤醒的 futex 的索引。

可以在 tools/testing/selftests/futex/functional/futex_waitv.c 找到如何使用该接口的示例。

超时

struct timespec *timeout 参数是一个可选参数,指向绝对超时。您需要在 clockid 参数中指定正在使用的时钟类型。 支持 CLOCK_MONOTONICCLOCK_REALTIME。 此系统调用仅接受 64 位 timespec 结构。

futex 的类型

futex 可以是 private 或 shared。 Private 用于共享相同内存空间的进程,并且 futex 的虚拟地址对于所有进程都是相同的。 这允许内核中的优化。 要使用 private futex,需要在 futex 标志中指定 FUTEX_PRIVATE_FLAG。 对于不共享相同内存空间,因此对于同一个 futex 可以有不同的虚拟地址的进程(例如,使用文件支持的共享内存),需要不同的内部机制才能正确排队。 这是默认行为,它适用于 private 和 shared futex。

Futex 可以是不同的大小:8、16、32 或 64 位。 目前,唯一支持的是 32 位大小的 futex,它需要使用 FUTEX_32 标志指定。