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