• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "tests.h"
29 
30 #include <asm/unistd.h>
31 
32 #ifdef __NR_futex
33 
34 # include <errno.h>
35 # include <stdarg.h>
36 # include <stdbool.h>
37 # include <stdio.h>
38 # include <stdint.h>
39 # include <unistd.h>
40 
41 # include <sys/time.h>
42 
43 # ifndef FUTEX_PRIVATE_FLAG
44 #  define FUTEX_PRIVATE_FLAG 128
45 # endif
46 # ifndef FUTEX_CLOCK_REALTIME
47 #  define FUTEX_CLOCK_REALTIME 256
48 # endif
49 # ifndef FUTEX_CMD_MASK
50 #  define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
51 # endif
52 
53 # include "xlat.h"
54 # include "xlat/futexops.h"
55 # include "xlat/futexwakeops.h"
56 # include "xlat/futexwakecmps.h"
57 
58 static struct timespec *tmout;
59 
futex_error(int * uaddr,int op,unsigned long val,unsigned long timeout,int * uaddr2,unsigned long val3,int rc)60 void futex_error(int *uaddr, int op, unsigned long val, unsigned long timeout,
61 	int *uaddr2, unsigned long val3, int rc)
62 {
63 	perror_msg_and_fail("futex(%p, %#x, %#x, %#lx, %p, %#x) = %d",
64 		uaddr, op, (unsigned) val, timeout, uaddr, (unsigned) val3, rc);
65 }
66 
67 # define CHECK_FUTEX_GENERIC(uaddr, op, val, timeout, uaddr2, val3, check, \
68 	enosys) \
69 	do { \
70 		rc = syscall(__NR_futex, (uaddr), (op), (val), (timeout), \
71 			(uaddr2), (val3)); \
72 		/* It is here due to EPERM on WAKE_OP on AArch64 */ \
73 		if ((rc == -1) && (errno == EPERM)) \
74 			break; \
75 		if (enosys && (rc == -1) && (errno == ENOSYS)) \
76 			break; \
77 		if (!(check)) \
78 			futex_error((uaddr), (op), (val), \
79 				(unsigned long) (timeout), (int *) (uaddr2), \
80 				(val3), rc); \
81 	} while (0)
82 
83 # define CHECK_FUTEX_ENOSYS(uaddr, op, val, timeout, uaddr2, val3, check) \
84 	CHECK_FUTEX_GENERIC(uaddr, op, val, timeout, uaddr2, val3, check, 1)
85 
86 # define CHECK_FUTEX(uaddr, op, val, timeout, uaddr2, val3, check) \
87 	CHECK_FUTEX_GENERIC(uaddr, op, val, timeout, uaddr2, val3, check, 0)
88 
89 enum argmask {
90 	ARG3 = 1 << 0,
91 	ARG4 = 1 << 1,
92 	ARG5 = 1 << 2,
93 	ARG6 = 1 << 3,
94 };
95 
invalid_op(int * val,int op,uint32_t argmask,...)96 void invalid_op(int *val, int op, uint32_t argmask, ...)
97 {
98 	static const unsigned long args[] = {
99 		(unsigned long) 0xface1e55deadbee1ULL,
100 		(unsigned long) 0xface1e56deadbee2ULL,
101 		(unsigned long) 0xface1e57deadbee3ULL,
102 		(unsigned long) 0xface1e58deadbee4ULL,
103 	};
104 	/* Since timeout value is copied before full op check, we should provide
105 	 * some valid timeout address or NULL */
106 	int cmd = op & FUTEX_CMD_MASK;
107 	bool valid_timeout = (cmd == FUTEX_WAIT) || (cmd == FUTEX_LOCK_PI) ||
108 		(cmd == FUTEX_WAIT_BITSET) || (cmd == FUTEX_WAIT_REQUEUE_PI);
109 	bool timeout_is_val2 = (cmd == FUTEX_REQUEUE) ||
110 		(cmd == FUTEX_CMP_REQUEUE) || (cmd == FUTEX_WAKE_OP) ||
111 		(cmd == FUTEX_CMP_REQUEUE_PI);
112 	const char *fmt;
113 	int saved_errno;
114 	int rc;
115 	int i;
116 	va_list ap;
117 
118 
119 	CHECK_FUTEX(val, op, args[0], valid_timeout ? 0 : args[1], args[2],
120 		args[3], (rc == -1) && (errno == ENOSYS));
121 	saved_errno = errno;
122 	printf("futex(%p, %#x /* FUTEX_??? */", val, op);
123 
124 	va_start(ap, argmask);
125 
126 	for (i = 0; i < 4; i++) {
127 		if (argmask & (1 << i)) {
128 			fmt = va_arg(ap, const char *);
129 
130 			printf(", ");
131 
132 			if (((1 << i) == ARG3) || ((1 << i) == ARG6) ||
133 			    (((1 << i) == ARG4) && timeout_is_val2))
134 				printf(fmt, (unsigned) args[i]);
135 			else
136 				printf(fmt, args[i]);
137 		}
138 	}
139 
140 	va_end(ap);
141 
142 	errno = saved_errno;
143 	printf(") = -1 ENOSYS (%m)\n");
144 }
145 
146 # define CHECK_INVALID_CLOCKRT(op, ...) \
147 	do { \
148 		invalid_op(uaddr, FUTEX_CLOCK_REALTIME | (op), __VA_ARGS__); \
149 		invalid_op(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG | \
150 			(op), __VA_ARGS__); \
151 	} while (0)
152 
153 /* Value which differs from one stored in int *val */
154 # define VAL     ((unsigned long) 0xbadda7a0facefeedLLU)
155 # define VAL_PR  ((unsigned) VAL)
156 
157 # define VAL2    ((unsigned long) 0xbadda7a0ca7b100dLLU)
158 # define VAL2_PR ((unsigned) VAL2)
159 
160 # define VAL3    ((unsigned long) 0xbadda7a09caffee1LLU)
161 # define VAL3_PR ((unsigned) VAL3)
162 
163 int
main(int argc,char * argv[])164 main(int argc, char *argv[])
165 {
166 	int *uaddr = tail_alloc(sizeof(*uaddr));
167 	int *uaddr2 = tail_alloc(sizeof(*uaddr2));
168 	int rc;
169 	unsigned i;
170 	unsigned j;
171 
172 	uaddr[0] = 0x1deadead;
173 	uaddr2[0] = 0xbadf00d;
174 
175 	tmout = tail_alloc(sizeof(*tmout));
176 	tmout->tv_sec = 123;
177 	tmout->tv_nsec = 0xbadc0de;
178 
179 	/* FUTEX_WAIT - check whether uaddr == val and sleep
180 	 * Possible flags: PRIVATE, CLOCK_RT (since 4.5)
181 	 * 1. uaddr   - futex address
182 	 * 2. op      - FUTEX_WAIT
183 	 * 3. val     - expected value
184 	 * 4. timeout - address to timespec with timeout
185 	 * 5. uaddr2  - not used
186 	 * 6. val3    - not used
187 	 */
188 
189 	/* uaddr is NULL */
190 	CHECK_FUTEX(NULL, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3,
191 		(rc == -1) && (errno == EFAULT));
192 	printf("futex(NULL, FUTEX_WAIT, %u, {tv_sec=%jd, tv_nsec=%jd}) = %s\n",
193 		VAL_PR, (intmax_t) tmout->tv_sec, (intmax_t) tmout->tv_nsec,
194 		sprintrc(rc));
195 
196 	/* uaddr is faulty */
197 	CHECK_FUTEX(uaddr + 1, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3,
198 		(rc == -1) && (errno == EFAULT));
199 	printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%jd, tv_nsec=%jd}) = %s\n",
200 		uaddr + 1, VAL_PR, (intmax_t) tmout->tv_sec,
201 		(intmax_t) tmout->tv_nsec, sprintrc(rc));
202 
203 	/* timeout is faulty */
204 	CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout + 1, uaddr2, VAL3,
205 		(rc == -1) && (errno == EFAULT));
206 	printf("futex(%p, FUTEX_WAIT, %u, %p) = %s\n",
207 		uaddr, 0xfacefeed, tmout + 1, sprintrc(rc));
208 
209 	/* uaddr is not as provided; uaddr2 is faulty but ignored */
210 	CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout, uaddr2 + 1, VAL3,
211 		(rc == -1) && (errno == EAGAIN));
212 	printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%jd, tv_nsec=%jd}) = %s\n",
213 		uaddr, VAL_PR, (intmax_t) tmout->tv_sec,
214 		(intmax_t) tmout->tv_nsec, sprintrc(rc));
215 
216 	/* uaddr is not as provided; uaddr2 is faulty but ignored */
217 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAIT, VAL, tmout,
218 		uaddr2 + 1, VAL3, (rc == -1) && (errno == EAGAIN));
219 	printf("futex(%p, FUTEX_WAIT_PRIVATE, %u, {tv_sec=%jd, tv_nsec=%jd}) = "
220 		"%s\n",
221 		uaddr, VAL_PR, (intmax_t) tmout->tv_sec,
222 		(intmax_t) tmout->tv_nsec, sprintrc(rc));
223 
224 	/* Next 2 tests are with CLOCKRT bit set */
225 
226 	/* Valid after v4.4-rc2-27-g337f130 */
227 	CHECK_FUTEX_ENOSYS(uaddr,
228 		FUTEX_CLOCK_REALTIME | FUTEX_WAIT,
229 		VAL, tmout, uaddr2, VAL3, (rc == -1) && (errno == EAGAIN));
230 	printf("futex(%p, FUTEX_WAIT|FUTEX_CLOCK_REALTIME, %u, "
231 		"{tv_sec=%jd, tv_nsec=%jd}) = %s\n", uaddr, VAL_PR,
232 		(intmax_t) tmout->tv_sec, (intmax_t) tmout->tv_nsec,
233 		sprintrc(rc));
234 
235 	CHECK_FUTEX_ENOSYS(uaddr,
236 		FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG | FUTEX_WAIT ,
237 		VAL, tmout, uaddr2, 0, (rc == -1) && (errno == EAGAIN));
238 	printf("futex(%p, FUTEX_WAIT_PRIVATE|FUTEX_CLOCK_REALTIME, %u, "
239 		"{tv_sec=%jd, tv_nsec=%jd}) = %s\n", uaddr, VAL_PR,
240 		(intmax_t) tmout->tv_sec, (intmax_t) tmout->tv_nsec,
241 		sprintrc(rc));
242 
243 	/* FUTEX_WAIT_BITSET - FUTEX_WAIT which provides additional bitmask
244 	 *                     which should be matched at least in one bit with
245 	 *                     wake mask in order to wake.
246 	 * Possible flags: PRIVATE, CLOCKRT
247 	 * 1. uaddr   - futex address
248 	 * 2. op      - FUTEX_TRYLOCK_PI
249 	 * 3. val     - expected value stored in uaddr
250 	 * 4. timeout - timeout
251 	 * 5. uaddr2  - not used
252 	 * 6. val3    - bitmask
253 	 */
254 
255 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAIT_BITSET, VAL, tmout, uaddr2 + 1,
256 		VAL3, (rc == -1) && (errno == EAGAIN));
257 	printf("futex(%p, FUTEX_WAIT_BITSET, %u, {tv_sec=%jd, tv_nsec=%jd}, "
258 		"%#x) = %s\n",
259 		uaddr, VAL_PR, (intmax_t) tmout->tv_sec,
260 		(intmax_t) tmout->tv_nsec, VAL3_PR, sprintrc(rc));
261 
262 	/* val3 of 0 is invalid  */
263 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAIT_BITSET, VAL, tmout, uaddr2 + 1, 0,
264 		(rc == -1) && (errno == EINVAL));
265 	printf("futex(%p, FUTEX_WAIT_BITSET, %u, {tv_sec=%jd, tv_nsec=%jd}, "
266 		"%#x) = %s\n",
267 		uaddr, VAL_PR, (intmax_t) tmout->tv_sec,
268 		(intmax_t) tmout->tv_nsec, 0, sprintrc(rc));
269 
270 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAIT_BITSET, VAL,
271 		tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EAGAIN));
272 	printf("futex(%p, FUTEX_WAIT_BITSET_PRIVATE, %u, "
273 		"{tv_sec=%jd, tv_nsec=%jd}, %#x) = %s\n",
274 		uaddr, VAL_PR, (intmax_t) tmout->tv_sec,
275 		(intmax_t) tmout->tv_nsec, VAL3_PR, sprintrc(rc));
276 
277 	/* Next 3 tests are with CLOCKRT bit set */
278 
279 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_WAIT_BITSET, VAL,
280 		tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EAGAIN));
281 	printf("futex(%p, FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %u, "
282 		"{tv_sec=%jd, tv_nsec=%jd}, %#x) = %s\n", uaddr, VAL_PR,
283 		(intmax_t) tmout->tv_sec, (intmax_t) tmout->tv_nsec, VAL3_PR,
284 		sprintrc(rc));
285 
286 	/* val3 of 0 is invalid  */
287 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_WAIT_BITSET, VAL,
288 		tmout, uaddr2 + 1, 0, (rc == -1) && (errno == EINVAL));
289 	printf("futex(%p, FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %u, "
290 		"{tv_sec=%jd, tv_nsec=%jd}, %#x) = %s\n", uaddr, VAL_PR,
291 		(intmax_t) tmout->tv_sec, (intmax_t) tmout->tv_nsec, 0,
292 		sprintrc(rc));
293 
294 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG |
295 		FUTEX_WAIT_BITSET, VAL, tmout, uaddr2 + 1, VAL3,
296 		(rc == -1) && (errno == EAGAIN));
297 	printf("futex(%p, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, %u, "
298 		"{tv_sec=%jd, tv_nsec=%jd}, %#x) = %s\n", uaddr, VAL_PR,
299 		(intmax_t) tmout->tv_sec, (intmax_t) tmout->tv_nsec, VAL3_PR,
300 		sprintrc(rc));
301 
302 	/* FUTEX_WAKE - wake val processes waiting for uaddr
303 	 * Possible flags: PRIVATE
304 	 * 1. uaddr   - futex address
305 	 * 2. op      - FUTEX_WAKE
306 	 * 3. val     - how many processes to wake
307 	 * 4. timeout - not used
308 	 * 5. uaddr2  - not used
309 	 * 6. val3    - not used
310 	 */
311 
312 	/* Zero processes to wake is not a good idea, but it should return 0 */
313 	CHECK_FUTEX(uaddr, FUTEX_WAKE, 0, NULL, NULL, 0, (rc == 0));
314 	printf("futex(%p, FUTEX_WAKE, %u) = %s\n", uaddr, 0, sprintrc(rc));
315 
316 	/* Trying to wake some processes, but there's nothing to wake */
317 	CHECK_FUTEX(uaddr, FUTEX_WAKE, 10, NULL, NULL, 0, (rc == 0));
318 	printf("futex(%p, FUTEX_WAKE, %u) = %s\n", uaddr, 10, sprintrc(rc));
319 
320 	/* Trying to wake some processes, but there's nothing to wake */
321 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAKE, 10, NULL,
322 		NULL, 0, (rc == 0));
323 	printf("futex(%p, FUTEX_WAKE_PRIVATE, %u) = %s\n", uaddr, 10,
324 		sprintrc(rc));
325 
326 	CHECK_INVALID_CLOCKRT(FUTEX_WAKE, ARG3, "%u");
327 
328 	/* FUTEX_WAKE_BITSET - wake val processes waiting for uaddr which has at
329 	 *                     least one common bit with bitset provided in
330 	 *                     val3.
331 	 * Possible flags: PRIVATE
332 	 * 1. uaddr   - futex address
333 	 * 2. op      - FUTEX_WAKE
334 	 * 3. val     - how many processes to wake
335 	 * 4. timeout - not used
336 	 * 5. uaddr2  - not used
337 	 * 6. val3    - bitmask
338 	 */
339 
340 	/* Trying to wake some processes, but there's nothing to wake */
341 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAKE_BITSET, 10, NULL, NULL,
342 		VAL3, (rc == 0));
343 	printf("futex(%p, FUTEX_WAKE_BITSET, %u, %#x) = %s\n", uaddr, 10,
344 		VAL3_PR, sprintrc(rc));
345 
346 	/* bitset 0 is invalid */
347 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAKE_BITSET, 10, NULL, NULL, 0,
348 		(rc == -1) && (errno == EINVAL));
349 	printf("futex(%p, FUTEX_WAKE_BITSET, %u, %#x) = %s\n", uaddr, 10, 0,
350 		sprintrc(rc));
351 
352 	/* Trying to wake some processes, but there's nothing to wake */
353 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAKE_BITSET, 10,
354 		NULL, NULL, VAL3, (rc == 0));
355 	printf("futex(%p, FUTEX_WAKE_BITSET_PRIVATE, %u, %#x) = %s\n", uaddr,
356 		10, VAL3_PR, sprintrc(rc));
357 
358 	CHECK_INVALID_CLOCKRT(FUTEX_WAKE_BITSET, ARG3 | ARG6, "%u", "%#x");
359 
360 	/* FUTEX_FD - deprecated
361 	 * Possible flags: PRIVATE
362 	 * 1. uaddr   - futex address
363 	 * 2. op      - FUTEX_FD
364 	 * 3. val     - signal number
365 	 * 4. timeout - not used
366 	 * 5. uaddr2  - not used
367 	 * 6. val3    - not used
368 	 */
369 
370 	/* FUTEX_FD is not implemented since 2.6.26 */
371 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_FD, VAL, NULL, NULL, VAL3,
372 		(rc == -1) && (errno == EINVAL));
373 	printf("futex(%p, FUTEX_FD, %u) = %s\n", uaddr, VAL_PR, sprintrc(rc));
374 
375 	/* FUTEX_FD is not implemented since 2.6.26 */
376 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_FD, VAL, NULL,
377 		NULL, VAL3, (rc == -1) && (errno == EINVAL));
378 	printf("futex(%p, FUTEX_FD|FUTEX_PRIVATE_FLAG, %u) = %s\n", uaddr,
379 		VAL_PR, sprintrc(rc));
380 
381 	CHECK_INVALID_CLOCKRT(FUTEX_FD, ARG3, "%u");
382 
383 	/* FUTEX_REQUEUE - wake val processes and re-queue rest on uaddr2
384 	 * Possible flags: PRIVATE
385 	 * 1. uaddr   - futex address
386 	 * 2. op      - FUTEX_REQUEUE
387 	 * 3. val     - how many processes to wake
388 	 * 4. val2    - amount of processes to re-queue on uadr2
389 	 * 5. uaddr2  - another futex address, to re-queue waiting processes on
390 	 * 6. val3    - not used
391 	 */
392 
393 	/* Trying to re-queue some processes but there's nothing to re-queue */
394 	CHECK_FUTEX(uaddr, FUTEX_REQUEUE, VAL, VAL2, uaddr2, VAL3,
395 		(rc == 0));
396 	printf("futex(%p, FUTEX_REQUEUE, %u, %u, %p) = %s\n",
397 		uaddr, VAL_PR, VAL2_PR, uaddr2, sprintrc(rc));
398 
399 	/* Trying to re-queue some processes but there's nothing to re-queue */
400 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_REQUEUE, VAL, VAL2,
401 		uaddr2, VAL3, (rc == 0));
402 	printf("futex(%p, FUTEX_REQUEUE_PRIVATE, %u, %u, %p) = %s\n",
403 		uaddr, VAL_PR, VAL2_PR, uaddr2, sprintrc(rc));
404 
405 	CHECK_INVALID_CLOCKRT(FUTEX_REQUEUE, ARG3 | ARG4 | ARG5, "%u", "%u",
406 		"%#lx");
407 
408 	/* FUTEX_CMP_REQUEUE - wake val processes and re-queue rest on uaddr2
409 	 *                     if uaddr has value val3
410 	 * Possible flags: PRIVATE
411 	 * 1. uaddr   - futex address
412 	 * 2. op      - FUTEX_CMP_REQUEUE
413 	 * 3. val     - how many processes to wake
414 	 * 4. val2    - amount of processes to re-queue on uadr2
415 	 * 5. uaddr2  - another futex address, to re-queue waiting processes on
416 	 * 6. val3    - expected value stored in uaddr
417 	 */
418 
419 	/* Comparison re-queue with wrong val value */
420 	CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VAL, VAL2, uaddr2, VAL3,
421 		(rc == -1) && (errno == EAGAIN));
422 	printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n",
423 		uaddr, VAL_PR, VAL2_PR, uaddr2, VAL3_PR, sprintrc(rc));
424 
425 	/* Successful comparison re-queue */
426 	CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VAL, VAL2, uaddr2, *uaddr,
427 		(rc == 0));
428 	printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n",
429 		uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
430 
431 	/* Successful comparison re-queue */
432 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE, VAL,
433 		VAL2, uaddr2, *uaddr, (rc == 0));
434 	printf("futex(%p, FUTEX_CMP_REQUEUE_PRIVATE, %u, %u, %p, %u) = %s\n",
435 		uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
436 
437 	CHECK_INVALID_CLOCKRT(FUTEX_CMP_REQUEUE, ARG3 | ARG4 | ARG5 | ARG6,
438 		"%u", "%u", "%#lx", "%u");
439 
440 	/* FUTEX_WAKE_OP - wake val processes waiting for uaddr, additionally
441 	 *                 wake val2 processes waiting for uaddr2 in case
442 	 *                 operation encoded in val3 (change of value at uaddr2
443 	 *                 and comparison of previous value against provided
444 	 *                 constant) succeedes with value at uaddr2. Operation
445 	 *                 result is written to value of uaddr2 (in any case).
446 	 * 1. uaddr   - futex address
447 	 * 2. op      - FUTEX_WAKE_OP
448 	 * 3. val     - how many processes to wake
449 	 * 4. val2    - amount of processes to wake in case operation encoded in
450 	 *              val3 returns true
451 	 * 5. uaddr2  - another futex address, for conditional wake of
452 	 *              additional processes
453 	 * 6. val3    - encoded operation:
454 	 *                1. bit 31 - if 1 then value stored in field field 4
455 	 *                            should be interpreted as power of 2.
456 	 *                2. 28..30 - arithmetic operation which should be
457 	 *                            applied to previous value stored in
458 	 *                            uaddr2. Values available (from 2005 up to
459 	 *                            2016): SET. ADD, OR, ANDN, XOR.
460 	 *                3. 24..29 - comparison operation which should be
461 	 *                            applied to the old value stored in uaddr2
462 	 *                            (before arithmetic operation is applied).
463 	 *                            Possible values: EQ, NE, LT, LE, GT, GE.
464 	 *                4. 12..23 - Second operand for arithmetic operation.
465 	 *                            If bit 31 is set, it is interpreted as
466 	 *                            power of 2.
467 	 *                5. 00..11 - Value against which old value stored in
468 	 *                            uaddr2 is compared.
469 	 */
470 
471 	static const struct {
472 		uint32_t val;
473 		const char *str;
474 		int err;
475 		const char *errstr;
476 	} wake_ops[] = {
477 		{ 0x00000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
478 		{ 0x00fff000, "FUTEX_OP_SET<<28|0xfff<<12|FUTEX_OP_CMP_EQ<<24|"
479 			"0" },
480 		{ 0x00000fff, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_EQ<<24|"
481 			"0xfff" },
482 		{ 0x00ffffff, "FUTEX_OP_SET<<28|0xfff<<12|FUTEX_OP_CMP_EQ<<24|"
483 			"0xfff" },
484 		{ 0x10000000, "FUTEX_OP_ADD<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
485 		{ 0x20000000, "FUTEX_OP_OR<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
486 		{ 0x30000000, "FUTEX_OP_ANDN<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
487 		{ 0x40000000, "FUTEX_OP_XOR<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
488 		{ 0x50000000, "0x5<<28 /* FUTEX_OP_??? */|0<<12|"
489 			"FUTEX_OP_CMP_EQ<<24|0", ENOSYS, "ENOSYS" },
490 		{ 0x70000000, "0x7<<28 /* FUTEX_OP_??? */|0<<12|"
491 			"FUTEX_OP_CMP_EQ<<24|0", ENOSYS, "ENOSYS" },
492 		{ 0x80000000, "FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_SET<<28|0<<12|"
493 			"FUTEX_OP_CMP_EQ<<24|0" },
494 		{ 0xa0caffee, "FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_OR<<28|"
495 			"0xcaf<<12|FUTEX_OP_CMP_EQ<<24|0xfee" },
496 		{ 0x01000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_NE<<24|0" },
497 		{ 0x01234567, "FUTEX_OP_SET<<28|0x234<<12|FUTEX_OP_CMP_NE<<24|"
498 			"0x567" },
499 		{ 0x02000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_LT<<24|0" },
500 		{ 0x03000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_LE<<24|0" },
501 		{ 0x04000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_GT<<24|0" },
502 		{ 0x05000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_GE<<24|0" },
503 		{ 0x06000000, "FUTEX_OP_SET<<28|0<<12|"
504 			"0x6<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS, "ENOSYS" },
505 		{ 0x07000000, "FUTEX_OP_SET<<28|0<<12|"
506 			"0x7<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS, "ENOSYS" },
507 		{ 0x08000000, "FUTEX_OP_SET<<28|0<<12|"
508 			"0x8<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS, "ENOSYS" },
509 		{ 0x0f000000, "FUTEX_OP_SET<<28|0<<12|"
510 			"0xf<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS, "ENOSYS" },
511 		{ 0xbadfaced, "FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_ANDN<<28|"
512 			"0xdfa<<12|0xa<<24 /* FUTEX_OP_CMP_??? */|0xced",
513 			ENOSYS, "ENOSYS" },
514 		{ 0xffffffff, "FUTEX_OP_OPARG_SHIFT<<28|"
515 			"0x7<<28 /* FUTEX_OP_??? */|0xfff<<12|"
516 			"0xf<<24 /* FUTEX_OP_CMP_??? */|0xfff",
517 			ENOSYS, "ENOSYS" },
518 	};
519 
520 	for (i = 0; i < ARRAY_SIZE(wake_ops); i++) {
521 		for (j = 0; j < 2; j++) {
522 			CHECK_FUTEX_ENOSYS(uaddr,
523 				j ? FUTEX_WAKE_OP_PRIVATE : FUTEX_WAKE_OP,
524 				VAL, i, uaddr2, wake_ops[i].val, (rc == 0));
525 			printf("futex(%p, FUTEX_WAKE_OP%s, %u, %u, %p, %s) = "
526 				"%s\n", uaddr, j ? "_PRIVATE" : "", VAL_PR, i,
527 				uaddr2, wake_ops[i].str, sprintrc(rc));
528 		}
529 	}
530 
531 	CHECK_INVALID_CLOCKRT(FUTEX_WAKE_OP, ARG3 | ARG4 | ARG5 | ARG6,
532 		"%u", "%u", "%#lx",
533 		/* Decoding of the 0xdeadbee4 value */
534 		"FUTEX_OP_OPARG_SHIFT<<28|0x5<<28 /* FUTEX_OP_??? */|0xadb<<12|"
535 		"0xe<<24 /* FUTEX_OP_CMP_??? */|0xee4");
536 
537 	/* FUTEX_LOCK_PI - slow path for mutex lock with process inheritance
538 	 *                 support. Expect that futex has 0 in unlocked case and
539 	 *                 TID of owning process in locked case. Value can also
540 	 *                 contain FUTEX_WAITERS bit signalling the presence of
541 	 *                 waiters queue.
542 	 * Possible flags: PRIVATE
543 	 * 1. uaddr   - futex address
544 	 * 2. op      - FUTEX_LOCK_PI
545 	 * 3. val     - not used
546 	 * 4. timeout - timeout
547 	 * 5. uaddr2  - not used
548 	 * 6. val3    - not used
549 	 */
550 
551 	*uaddr = getpid();
552 
553 	CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_LOCK_PI, VAL, tmout, uaddr2 + 1,
554 		VAL3, (rc == -1) && (errno == EFAULT));
555 	printf("futex(%p, FUTEX_LOCK_PI, {tv_sec=%jd, tv_nsec=%jd}) = %s\n",
556 		uaddr + 1, (intmax_t) tmout->tv_sec, (intmax_t) tmout->tv_nsec,
557 		sprintrc(rc));
558 
559 	CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_PRIVATE_FLAG | FUTEX_LOCK_PI, VAL,
560 		tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EFAULT));
561 	printf("futex(%p, FUTEX_LOCK_PI_PRIVATE, {tv_sec=%jd, tv_nsec=%jd}) = "
562 		"%s\n",
563 		uaddr + 1, (intmax_t) tmout->tv_sec, (intmax_t) tmout->tv_nsec,
564 		sprintrc(rc));
565 
566 	/* NULL is passed by invalid_op() in cases valid timeout address is
567 	 * needed */
568 	CHECK_INVALID_CLOCKRT(FUTEX_LOCK_PI, ARG4, "NULL");
569 
570 	/* FUTEX_UNLOCK_PI - slow path for mutex unlock with process inheritance
571 	 *                   support. Expected to be called by process in case
572 	 *                   it failed to execute fast path (it usually means
573 	 *                   that FUTEX_WAITERS flag had been set while the lock
574 	 *                   has been held).
575 	 * Possible flags: PRIVATE
576 	 * 1. uaddr   - futex address
577 	 * 2. op      - FUTEX_UNLOCK_PI
578 	 * 3. val     - not used
579 	 * 4. timeout - not used
580 	 * 5. uaddr2  - not used
581 	 * 6. val3    - not used
582 	 */
583 
584 	CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_UNLOCK_PI, VAL, tmout, uaddr2 + 1,
585 		VAL3, (rc == -1) && (errno == EFAULT));
586 	printf("futex(%p, FUTEX_UNLOCK_PI) = %s\n", uaddr + 1, sprintrc(rc));
587 
588 	CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_PRIVATE_FLAG | FUTEX_UNLOCK_PI, VAL,
589 		tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EFAULT));
590 	printf("futex(%p, FUTEX_UNLOCK_PI_PRIVATE) = %s\n", uaddr +1,
591 		sprintrc(rc));
592 
593 	CHECK_INVALID_CLOCKRT(FUTEX_UNLOCK_PI, 0);
594 
595 	/* FUTEX_TRYLOCK_PI - slow path for mutex trylock with process
596 	 *                 inheritance support.
597 	 * Possible flags: PRIVATE
598 	 * 1. uaddr   - futex address
599 	 * 2. op      - FUTEX_TRYLOCK_PI
600 	 * 3. val     - not used
601 	 * 4. timeout - not used
602 	 * 5. uaddr2  - not used
603 	 * 6. val3    - not used
604 	 */
605 
606 	CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_TRYLOCK_PI, VAL, tmout, uaddr2 + 1,
607 		VAL3, (rc == -1) && (errno == EFAULT));
608 	printf("futex(%p, FUTEX_TRYLOCK_PI) = %s\n", uaddr + 1, sprintrc(rc));
609 
610 	CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_PRIVATE_FLAG | FUTEX_TRYLOCK_PI,
611 		VAL, tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EFAULT));
612 	printf("futex(%p, FUTEX_TRYLOCK_PI_PRIVATE) = %s\n", uaddr + 1,
613 		sprintrc(rc));
614 
615 	CHECK_INVALID_CLOCKRT(FUTEX_TRYLOCK_PI, 0);
616 
617 	/* FUTEX_WAIT_REQUEUE_PI - kernel-side handling of special case when
618 	 *                         processes should be re-queued on PI-aware
619 	 *                         futexes. This is so special since PI futexes
620 	 *                         utilize rt_mutex and it should be at no time
621 	 *                         left free with a wait queue, so this should
622 	 *                         be performed atomically in-kernel.
623 	 * Possible flags: PRIVATE, CLOCKRT
624 	 * 1. uaddr   - futex address
625 	 * 2. op      - FUTEX_WAIT_REQUEUE_PI
626 	 * 3. val     - expected value stored in uaddr
627 	 * 4. timeout - timeout
628 	 * 5. uaddr2  - (PI-aware) futex address to requeue process on
629 	 * 6. val3    - not used (in kernel, it always initialized to
630 	 *              FUTEX_BITSET_MATCH_ANY and passed to
631 	 *              futex_wait_requeue_pi())
632 	 */
633 
634 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAIT_REQUEUE_PI, VAL, tmout, uaddr2,
635 		VAL3, (rc == -1) && (errno == EAGAIN));
636 	printf("futex(%p, FUTEX_WAIT_REQUEUE_PI, %u, "
637 		"{tv_sec=%jd, tv_nsec=%jd}, %p) = %s\n",
638 		uaddr, VAL_PR, (intmax_t) tmout->tv_sec,
639 		(intmax_t) tmout->tv_nsec, uaddr2, sprintrc(rc));
640 
641 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAIT_REQUEUE_PI,
642 		VAL, tmout, uaddr2, VAL3, (rc == -1) && (errno == EAGAIN));
643 	printf("futex(%p, FUTEX_WAIT_REQUEUE_PI_PRIVATE, %u, "
644 		"{tv_sec=%jd, tv_nsec=%jd}, %p) "
645 		"= %s\n", uaddr, VAL_PR, (intmax_t) tmout->tv_sec,
646 		(intmax_t) tmout->tv_nsec, uaddr2, sprintrc(rc));
647 
648 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_WAIT_REQUEUE_PI,
649 		VAL, tmout, uaddr2, VAL3, (rc == -1) && (errno == EAGAIN));
650 	printf("futex(%p, FUTEX_WAIT_REQUEUE_PI|FUTEX_CLOCK_REALTIME, %u, "
651 		"{tv_sec=%jd, tv_nsec=%jd}, %p) = %s\n", uaddr, VAL_PR,
652 		(intmax_t) tmout->tv_sec, (intmax_t) tmout->tv_nsec, uaddr2,
653 		sprintrc(rc));
654 
655 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG |
656 		FUTEX_WAIT_REQUEUE_PI, VAL, tmout, uaddr2, VAL3,
657 		(rc == -1) && (errno == EAGAIN));
658 	printf("futex(%p, FUTEX_WAIT_REQUEUE_PI_PRIVATE|FUTEX_CLOCK_REALTIME, "
659 		"%u, {tv_sec=%jd, tv_nsec=%jd}, %p) = %s\n", uaddr, VAL_PR,
660 		(intmax_t) tmout->tv_sec, (intmax_t) tmout->tv_nsec, uaddr2,
661 		sprintrc(rc));
662 
663 	/* FUTEX_CMP_REQUEUE_PI - version of FUTEX_CMP_REQUEUE which re-queues
664 	 *                        on PI-aware futex.
665 	 * Possible flags: PRIVATE
666 	 * 1. uaddr   - futex address
667 	 * 2. op      - FUTEX_CMP_REQUEUE
668 	 * 3. val     - how many processes to wake
669 	 * 4. val2    - amount of processes to re-queue on uadr2
670 	 * 5. uaddr2  - (PI-aware) futex address, to re-queue waiting processes
671 	 *              on
672 	 * 6. val3    - expected value stored in uaddr
673 	 */
674 
675 	/* All these should fail with EINVAL since we try to re-queue to  non-PI
676 	 * futex.
677 	 */
678 
679 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CMP_REQUEUE_PI, VAL, VAL2, uaddr2, VAL3,
680 		(rc == -1) && (errno == EINVAL));
681 	printf("futex(%p, FUTEX_CMP_REQUEUE_PI, %u, %u, %p, %u) = %s\n",
682 		uaddr, VAL_PR, VAL2_PR, uaddr2, VAL3_PR, sprintrc(rc));
683 
684 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CMP_REQUEUE_PI, VAL, VAL2, uaddr2,
685 		*uaddr, (rc == -1) && (errno == EINVAL));
686 	printf("futex(%p, FUTEX_CMP_REQUEUE_PI, %u, %u, %p, %u) = %s\n",
687 		uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
688 
689 	CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE_PI,
690 		VAL, VAL2, uaddr2, *uaddr, (rc == -1) && (errno == EINVAL));
691 	printf("futex(%p, FUTEX_CMP_REQUEUE_PI_PRIVATE, %u, %u, %p, %u) = %s\n",
692 		uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
693 
694 	CHECK_INVALID_CLOCKRT(FUTEX_CMP_REQUEUE_PI, ARG3 | ARG4 | ARG5 | ARG6,
695 		"%u", "%u", "%#lx", "%u");
696 
697 	/*
698 	 * Unknown commands
699 	 */
700 
701 	CHECK_FUTEX(uaddr, 0xd, VAL, tmout + 1, uaddr2 + 1, VAL3,
702 		(rc == -1) && (errno == ENOSYS));
703 	printf("futex(%p, 0xd /* FUTEX_??? */, %u, %p, %p, %#x) = %s\n",
704 		uaddr, VAL_PR, tmout + 1, uaddr2 + 1, VAL3_PR, sprintrc(rc));
705 
706 	CHECK_FUTEX(uaddr, 0xbefeeded, VAL, tmout + 1, uaddr2, VAL3,
707 		(rc == -1) && (errno == ENOSYS));
708 	printf("futex(%p, 0xbefeeded /* FUTEX_??? */, %u, %p, %p, %#x) = %s\n",
709 		uaddr, VAL_PR, tmout + 1, uaddr2, VAL3_PR, sprintrc(rc));
710 
711 	puts("+++ exited with 0 +++");
712 
713 	return 0;
714 }
715 
716 #else
717 
718 SKIP_MAIN_UNDEFINED("__NR_futex")
719 
720 #endif
721