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 的大小。__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 可以是私有的或共享的。私有用于共享同一内存空间的进程,所有进程的 futex 的虚拟地址将相同。这允许内核进行优化。要使用私有 futex,需要在 futex 标志中指定 FUTEX_PRIVATE_FLAG。对于不共享同一内存空间,因此同一 futex 可能具有不同虚拟地址的进程(例如,使用文件支持的共享内存),需要不同的内部机制才能正确排队。这是默认行为,它适用于私有和共享 futex。

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