xref: /linux/tools/perf/bench/futex.h (revision b3570b00dc3062c5a5e8d9602b923618d679636a)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Glibc independent futex library for testing kernel functionality.
4  * Shamelessly stolen from Darren Hart <dvhltc@us.ibm.com>
5  *    http://git.kernel.org/cgit/linux/kernel/git/dvhart/futextest.git/
6  */
7 
8 #ifndef _FUTEX_H
9 #define _FUTEX_H
10 
11 #include <unistd.h>
12 #include <sys/syscall.h>
13 #include <sys/types.h>
14 #include <linux/futex.h>
15 
16 struct bench_futex_parameters {
17 	bool silent;
18 	bool fshared;
19 	bool mlockall;
20 	bool multi; /* lock-pi */
21 	bool pi; /* requeue-pi */
22 	bool broadcast; /* requeue */
23 	unsigned int runtime; /* seconds*/
24 	unsigned int nthreads;
25 	unsigned int nfutexes;
26 	unsigned int nwakes;
27 	unsigned int nrequeue;
28 	int nbuckets;
29 	bool buckets_immutable;
30 };
31 
32 /**
33  * futex_syscall() - SYS_futex syscall wrapper
34  * @uaddr:	address of first futex
35  * @op:		futex op code
36  * @val:	typically expected value of uaddr, but varies by op
37  * @timeout:	typically an absolute struct timespec (except where noted
38  *		otherwise). Overloaded by some ops
39  * @uaddr2:	address of second futex for some ops
40  * @val3:	varies by op
41  * @opflags:	flags to be bitwise OR'd with op, such as FUTEX_PRIVATE_FLAG
42  *
43  * futex_syscall() is used by all the following futex op wrappers. It can also be
44  * used for misuse and abuse testing. Generally, the specific op wrappers
45  * should be used instead.
46  *
47  * These argument descriptions are the defaults for all
48  * like-named arguments in the following wrappers except where noted below.
49  */
50 static inline int
51 futex_syscall(volatile u_int32_t *uaddr, int op, u_int32_t val, struct timespec *timeout,
52 	      volatile u_int32_t *uaddr2, int val3, int opflags)
53 {
54 	return syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3);
55 }
56 
57 static inline int
58 futex_syscall_nr_requeue(volatile u_int32_t *uaddr, int op, u_int32_t val, int nr_requeue,
59 			 volatile u_int32_t *uaddr2, int val3, int opflags)
60 {
61 	return syscall(SYS_futex, uaddr, op | opflags, val, nr_requeue, uaddr2, val3);
62 }
63 
64 /**
65  * futex_wait() - block on uaddr with optional timeout
66  * @timeout:	relative timeout
67  */
68 static inline int
69 futex_wait(u_int32_t *uaddr, u_int32_t val, struct timespec *timeout, int opflags)
70 {
71 	return futex_syscall(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags);
72 }
73 
74 /**
75  * futex_wake() - wake one or more tasks blocked on uaddr
76  * @nr_wake:	wake up to this many tasks
77  */
78 static inline int
79 futex_wake(u_int32_t *uaddr, int nr_wake, int opflags)
80 {
81 	return futex_syscall(uaddr, FUTEX_WAKE, nr_wake, NULL, NULL, 0, opflags);
82 }
83 
84 /**
85  * futex_lock_pi() - block on uaddr as a PI mutex
86  */
87 static inline int
88 futex_lock_pi(u_int32_t *uaddr, struct timespec *timeout, int opflags)
89 {
90 	return futex_syscall(uaddr, FUTEX_LOCK_PI, 0, timeout, NULL, 0, opflags);
91 }
92 
93 /**
94  * futex_unlock_pi() - release uaddr as a PI mutex, waking the top waiter
95  */
96 static inline int
97 futex_unlock_pi(u_int32_t *uaddr, int opflags)
98 {
99 	return futex_syscall(uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0, opflags);
100 }
101 
102 /**
103 * futex_cmp_requeue() - requeue tasks from uaddr to uaddr2
104 * @nr_wake:        wake up to this many tasks
105 * @nr_requeue:     requeue up to this many tasks
106 */
107 static inline int
108 futex_cmp_requeue(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2, int nr_wake,
109 		 int nr_requeue, int opflags)
110 {
111 	return futex_syscall_nr_requeue(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2,
112 					val, opflags);
113 }
114 
115 /**
116  * futex_wait_requeue_pi() - block on uaddr and prepare to requeue to uaddr2
117  * @uaddr:	non-PI futex source
118  * @uaddr2:	PI futex target
119  *
120  * This is the first half of the requeue_pi mechanism. It shall always be
121  * paired with futex_cmp_requeue_pi().
122  */
123 static inline int
124 futex_wait_requeue_pi(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2,
125 		      struct timespec *timeout, int opflags)
126 {
127 	return futex_syscall(uaddr, FUTEX_WAIT_REQUEUE_PI, val, timeout, uaddr2, 0,
128 			     opflags);
129 }
130 
131 /**
132  * futex_cmp_requeue_pi() - requeue tasks from uaddr to uaddr2
133  * @uaddr:	non-PI futex source
134  * @uaddr2:	PI futex target
135  * @nr_requeue:	requeue up to this many tasks
136  *
137  * This is the second half of the requeue_pi mechanism. It shall always be
138  * paired with futex_wait_requeue_pi(). The first waker is always awoken.
139  */
140 static inline int
141 futex_cmp_requeue_pi(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2,
142 		     int nr_requeue, int opflags)
143 {
144 	return futex_syscall_nr_requeue(uaddr, FUTEX_CMP_REQUEUE_PI, 1, nr_requeue, uaddr2,
145 					val, opflags);
146 }
147 
148 void futex_set_nbuckets_param(struct bench_futex_parameters *params);
149 void futex_print_nbuckets(struct bench_futex_parameters *params);
150 
151 #endif /* _FUTEX_H */
152