xref: /linux/tools/testing/selftests/futex/include/futextest.h (revision 6b3f7af57881f6d6250c6dcc4d910fe8e855a607)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /******************************************************************************
3  *
4  *   Copyright © International Business Machines  Corp., 2009
5  *
6  * DESCRIPTION
7  *      Glibc independent futex library for testing kernel functionality.
8  *
9  * AUTHOR
10  *      Darren Hart <dvhart@linux.intel.com>
11  *
12  * HISTORY
13  *      2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com>
14  *
15  *****************************************************************************/
16 
17 #ifndef _FUTEXTEST_H
18 #define _FUTEXTEST_H
19 
20 #include <unistd.h>
21 #include <sys/syscall.h>
22 #include <sys/types.h>
23 #include <linux/futex.h>
24 
25 typedef volatile u_int32_t futex_t;
26 #define FUTEX_INITIALIZER 0
27 
28 /* Define the newer op codes if the system header file is not up to date. */
29 #ifndef FUTEX_WAIT_BITSET
30 #define FUTEX_WAIT_BITSET		9
31 #endif
32 #ifndef FUTEX_WAKE_BITSET
33 #define FUTEX_WAKE_BITSET		10
34 #endif
35 #ifndef FUTEX_WAIT_REQUEUE_PI
36 #define FUTEX_WAIT_REQUEUE_PI		11
37 #endif
38 #ifndef FUTEX_CMP_REQUEUE_PI
39 #define FUTEX_CMP_REQUEUE_PI		12
40 #endif
41 #ifndef FUTEX_ROBUST_UNLOCK
42 #define FUTEX_ROBUST_UNLOCK		512
43 #endif
44 #ifndef FUTEX_ROBUST_LIST32
45 #define FUTEX_ROBUST_LIST32		1024
46 #endif
47 #ifndef FUTEX_WAIT_REQUEUE_PI_PRIVATE
48 #define FUTEX_WAIT_REQUEUE_PI_PRIVATE	(FUTEX_WAIT_REQUEUE_PI | \
49 					 FUTEX_PRIVATE_FLAG)
50 #endif
51 #ifndef FUTEX_REQUEUE_PI_PRIVATE
52 #define FUTEX_CMP_REQUEUE_PI_PRIVATE	(FUTEX_CMP_REQUEUE_PI | \
53 					 FUTEX_PRIVATE_FLAG)
54 #endif
55 
56 /*
57  * SYS_futex is expected from system C library, in glibc some 32-bit
58  * architectures (e.g. RV32) are using 64-bit time_t, therefore it doesn't have
59  * SYS_futex defined but just SYS_futex_time64. Define SYS_futex as
60  * SYS_futex_time64 in this situation to ensure the compilation and the
61  * compatibility.
62  */
63 #if !defined(SYS_futex) && defined(SYS_futex_time64)
64 #define SYS_futex SYS_futex_time64
65 #endif
66 
67 /*
68  * On 32bit systems if we use "-D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64" or if
69  * we are using a newer compiler then the size of the timestamps will be 64bit,
70  * however, the SYS_futex will still point to the 32bit futex system call.
71  */
72 #if __SIZEOF_POINTER__ == 4 && defined(SYS_futex_time64) && \
73 	defined(_TIME_BITS) && _TIME_BITS == 64
74 # undef SYS_futex
75 # define SYS_futex SYS_futex_time64
76 #endif
77 
78 /**
79  * futex() - SYS_futex syscall wrapper
80  * @uaddr:	address of first futex
81  * @op:		futex op code
82  * @val:	typically expected value of uaddr, but varies by op
83  * @timeout:	typically an absolute struct timespec (except where noted
84  *              otherwise). Overloaded by some ops
85  * @uaddr2:	address of second futex for some ops\
86  * @val3:	varies by op
87  * @opflags:	flags to be bitwise OR'd with op, such as FUTEX_PRIVATE_FLAG
88  *
89  * futex() is used by all the following futex op wrappers. It can also be
90  * used for misuse and abuse testing. Generally, the specific op wrappers
91  * should be used instead. It is a macro instead of an static inline function as
92  * some of the types over overloaded (timeout is used for nr_requeue for
93  * example).
94  *
95  * These argument descriptions are the defaults for all
96  * like-named arguments in the following wrappers except where noted below.
97  */
98 #define futex(uaddr, op, val, timeout, uaddr2, val3, opflags) \
99 	syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3)
100 
101 /**
102  * futex_wait() - block on uaddr with optional timeout
103  * @timeout:	relative timeout
104  */
105 static inline int
106 futex_wait(futex_t *uaddr, futex_t val, struct timespec *timeout, int opflags)
107 {
108 	return futex(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags);
109 }
110 
111 /**
112  * futex_wake() - wake one or more tasks blocked on uaddr
113  * @nr_wake:	wake up to this many tasks
114  */
115 static inline int
116 futex_wake(futex_t *uaddr, int nr_wake, int opflags)
117 {
118 	return futex(uaddr, FUTEX_WAKE, nr_wake, NULL, NULL, 0, opflags);
119 }
120 
121 /**
122  * futex_wait_bitset() - block on uaddr with bitset
123  * @bitset:	bitset to be used with futex_wake_bitset
124  */
125 static inline int
126 futex_wait_bitset(futex_t *uaddr, futex_t val, struct timespec *timeout,
127 		  u_int32_t bitset, int opflags)
128 {
129 	return futex(uaddr, FUTEX_WAIT_BITSET, val, timeout, NULL, bitset,
130 		     opflags);
131 }
132 
133 /**
134  * futex_wake_bitset() - wake one or more tasks blocked on uaddr with bitset
135  * @bitset:	bitset to compare with that used in futex_wait_bitset
136  */
137 static inline int
138 futex_wake_bitset(futex_t *uaddr, int nr_wake, u_int32_t bitset, int opflags)
139 {
140 	return futex(uaddr, FUTEX_WAKE_BITSET, nr_wake, NULL, NULL, bitset,
141 		     opflags);
142 }
143 
144 /**
145  * futex_lock_pi() - block on uaddr as a PI mutex
146  * @detect:	whether (1) or not (0) to perform deadlock detection
147  */
148 static inline int
149 futex_lock_pi(futex_t *uaddr, struct timespec *timeout, int detect,
150 	      int opflags)
151 {
152 	return futex(uaddr, FUTEX_LOCK_PI, detect, timeout, NULL, 0, opflags);
153 }
154 
155 /**
156  * futex_unlock_pi() - release uaddr as a PI mutex, waking the top waiter
157  */
158 static inline int
159 futex_unlock_pi(futex_t *uaddr, int opflags)
160 {
161 	return futex(uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0, opflags);
162 }
163 
164 /**
165  * futex_wake_op() - FIXME: COME UP WITH A GOOD ONE LINE DESCRIPTION
166  */
167 static inline int
168 futex_wake_op(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_wake2,
169 	      int wake_op, int opflags)
170 {
171 	return futex(uaddr, FUTEX_WAKE_OP, nr_wake, nr_wake2, uaddr2, wake_op,
172 		     opflags);
173 }
174 
175 /**
176  * futex_requeue() - requeue without expected value comparison, deprecated
177  * @nr_wake:	wake up to this many tasks
178  * @nr_requeue:	requeue up to this many tasks
179  *
180  * Due to its inherently racy implementation, futex_requeue() is deprecated in
181  * favor of futex_cmp_requeue().
182  */
183 static inline int
184 futex_requeue(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_requeue,
185 	      int opflags)
186 {
187 	return futex(uaddr, FUTEX_REQUEUE, nr_wake, nr_requeue, uaddr2, 0,
188 		     opflags);
189 }
190 
191 /**
192  * futex_cmp_requeue() - requeue tasks from uaddr to uaddr2
193  * @nr_wake:	wake up to this many tasks
194  * @nr_requeue:	requeue up to this many tasks
195  */
196 static inline int
197 futex_cmp_requeue(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake,
198 		  int nr_requeue, int opflags)
199 {
200 	return futex(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2,
201 		     val, opflags);
202 }
203 
204 /**
205  * futex_wait_requeue_pi() - block on uaddr and prepare to requeue to uaddr2
206  * @uaddr:	non-PI futex source
207  * @uaddr2:	PI futex target
208  *
209  * This is the first half of the requeue_pi mechanism. It shall always be
210  * paired with futex_cmp_requeue_pi().
211  */
212 static inline int
213 futex_wait_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2,
214 		      struct timespec *timeout, int opflags)
215 {
216 	return futex(uaddr, FUTEX_WAIT_REQUEUE_PI, val, timeout, uaddr2, 0,
217 		     opflags);
218 }
219 
220 /**
221  * futex_cmp_requeue_pi() - requeue tasks from uaddr to uaddr2 (PI aware)
222  * @uaddr:	non-PI futex source
223  * @uaddr2:	PI futex target
224  * @nr_wake:	wake up to this many tasks
225  * @nr_requeue:	requeue up to this many tasks
226  */
227 static inline int
228 futex_cmp_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake,
229 		     int nr_requeue, int opflags)
230 {
231 	return futex(uaddr, FUTEX_CMP_REQUEUE_PI, nr_wake, nr_requeue, uaddr2,
232 		     val, opflags);
233 }
234 
235 /**
236  * futex_cmpxchg() - atomic compare and exchange
237  * @uaddr:	The address of the futex to be modified
238  * @oldval:	The expected value of the futex
239  * @newval:	The new value to try and assign the futex
240  *
241  * Implement cmpxchg using gcc atomic builtins.
242  * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
243  *
244  * Return the old futex value.
245  */
246 static inline u_int32_t
247 futex_cmpxchg(futex_t *uaddr, u_int32_t oldval, u_int32_t newval)
248 {
249 	return __sync_val_compare_and_swap(uaddr, oldval, newval);
250 }
251 
252 /**
253  * futex_dec() - atomic decrement of the futex value
254  * @uaddr:	The address of the futex to be modified
255  *
256  * Return the new futex value.
257  */
258 static inline u_int32_t
259 futex_dec(futex_t *uaddr)
260 {
261 	return __sync_sub_and_fetch(uaddr, 1);
262 }
263 
264 /**
265  * futex_inc() - atomic increment of the futex value
266  * @uaddr:	the address of the futex to be modified
267  *
268  * Return the new futex value.
269  */
270 static inline u_int32_t
271 futex_inc(futex_t *uaddr)
272 {
273 	return __sync_add_and_fetch(uaddr, 1);
274 }
275 
276 /**
277  * futex_set() - atomic decrement of the futex value
278  * @uaddr:	the address of the futex to be modified
279  * @newval:	New value for the atomic_t
280  *
281  * Return the new futex value.
282  */
283 static inline u_int32_t
284 futex_set(futex_t *uaddr, u_int32_t newval)
285 {
286 	*uaddr = newval;
287 	return newval;
288 }
289 
290 #endif
291