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