xref: /linux/tools/testing/selftests/futex/include/futex2test.h (revision 59e6295fac26b8e85c1ea859cdd89fa1e47519d7)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * Futex2 library addons for futex tests
4  *
5  * Copyright 2021 Collabora Ltd.
6  */
7 #include <linux/time_types.h>
8 #include <errno.h>
9 #include <stdint.h>
10 #include <stdbool.h>
11 
12 #define u64_to_ptr(x) ((void *)(uintptr_t)(x))
13 
14 #ifndef __NR_futex_waitv
15 #define __NR_futex_waitv 449
16 struct futex_waitv {
17 	__u64 val;
18 	__u64 uaddr;
19 	__u32 flags;
20 	__u32 __reserved;
21 };
22 #endif
23 
24 #ifndef __NR_futex_wake
25 #define __NR_futex_wake 454
26 #endif
27 
28 #ifndef __NR_futex_wait
29 #define __NR_futex_wait 455
30 #endif
31 
32 #ifndef FUTEX2_SIZE_U32
33 #define FUTEX2_SIZE_U32 0x02
34 #endif
35 
36 #ifndef FUTEX2_NUMA
37 #define FUTEX2_NUMA 0x04
38 #endif
39 
40 #ifndef FUTEX2_MPOL
41 #define FUTEX2_MPOL 0x08
42 #endif
43 
44 #ifndef FUTEX2_PRIVATE
45 #define FUTEX2_PRIVATE FUTEX_PRIVATE_FLAG
46 #endif
47 
48 #ifndef FUTEX2_NO_NODE
49 #define FUTEX_NO_NODE (-1)
50 #endif
51 
52 #ifndef FUTEX_32
53 #define FUTEX_32 FUTEX2_SIZE_U32
54 #endif
55 
56 struct futex32_numa {
57 	futex_t futex;
58 	futex_t numa;
59 };
60 
61 /**
62  * futex_waitv - Wait at multiple futexes, wake on any
63  * @waiters:    Array of waiters
64  * @nr_waiters: Length of waiters array
65  * @flags: Operation flags
66  * @timo:  Optional timeout for operation
67  */
68 static inline int futex_waitv(volatile struct futex_waitv *waiters, unsigned long nr_waiters,
69 			      unsigned long flags, struct timespec *timo, clockid_t clockid)
70 {
71 		struct __kernel_timespec ts = {
72 			.tv_sec = timo->tv_sec,
73 			.tv_nsec = timo->tv_nsec,
74 		};
75 
76 		return syscall(__NR_futex_waitv, waiters, nr_waiters, flags, &ts, clockid);
77 }
78 
79 /*
80  * futex_wait() - block on uaddr with optional timeout
81  * @val:	Expected value
82  * @flags:	FUTEX2 flags
83  * @timeout:	Relative timeout
84  * @clockid:	Clock id for the timeout
85  */
86 static inline int futex2_wait(void *uaddr, long val, unsigned int flags,
87 			      struct timespec *timeout, clockid_t clockid)
88 {
89 	return syscall(__NR_futex_wait, uaddr, val, ~0U, flags, timeout, clockid);
90 }
91 
92 /*
93  * futex2_wake() - Wake a number of futexes
94  * @nr:		Number of threads to wake at most
95  * @flags:	FUTEX2 flags
96  */
97 static inline int futex2_wake(void *uaddr, int nr, unsigned int flags)
98 {
99 	return syscall(__NR_futex_wake, uaddr, ~0U, nr, flags);
100 }
101 
102 static inline bool is_futex_waitv_supported(void)
103 {
104 	struct timespec ts = {0, 0};
105 	int res = futex_waitv(NULL, 0, 0, &ts, CLOCK_MONOTONIC);
106 
107 	return !(res < 0 && errno == ENOSYS);
108 }
109