2 * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
3 * Copyright (c) 2016-2018 The strace developers.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <asm/unistd.h>
41 # include <sys/time.h>
43 # ifndef FUTEX_PRIVATE_FLAG
44 # define FUTEX_PRIVATE_FLAG 128
46 # ifndef FUTEX_CLOCK_REALTIME
47 # define FUTEX_CLOCK_REALTIME 256
49 # ifndef FUTEX_CMD_MASK
50 # define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
54 # include "xlat/futexops.h"
55 # include "xlat/futexwakeops.h"
56 # include "xlat/futexwakecmps.h"
58 void futex_error(int *uaddr, int op, unsigned long val, unsigned long timeout,
59 int *uaddr2, unsigned long val3, int rc, const char *func, int line)
61 perror_msg_and_fail("%s:%d: futex(%p, %#x, %#x, %#lx, %p, %#x) = %d",
62 func, line, uaddr, op, (unsigned) val, timeout, uaddr,
66 # define CHECK_FUTEX_GENERIC(uaddr, op, val, timeout, uaddr2, val3, check, \
70 rc = syscall(__NR_futex, (uaddr), (op), (val), (timeout), \
72 /* It is here due to EPERM on WAKE_OP on AArch64 */ \
73 if ((rc == -1) && (errno == EPERM)) \
75 if (enosys && (rc == -1) && (errno == ENOSYS)) \
78 futex_error((uaddr), (op), (val), \
79 (unsigned long) (timeout), (int *) (uaddr2), \
80 (val3), rc, __func__, __LINE__); \
83 # define CHECK_FUTEX_ENOSYS(uaddr, op, val, timeout, uaddr2, val3, check) \
84 CHECK_FUTEX_GENERIC(uaddr, op, val, timeout, uaddr2, val3, check, 1)
86 # define CHECK_FUTEX(uaddr, op, val, timeout, uaddr2, val3, check) \
87 CHECK_FUTEX_GENERIC(uaddr, op, val, timeout, uaddr2, val3, check, 0)
96 void invalid_op(int *val, int op, uint32_t argmask, ...)
98 static const unsigned long args[] = {
99 (unsigned long) 0xface1e55deadbee1ULL,
100 (unsigned long) 0xface1e56deadbee2ULL,
101 (unsigned long) 0xface1e57deadbee3ULL,
102 (unsigned long) 0xface1e58deadbee4ULL,
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);
119 CHECK_FUTEX(val, op, args[0], valid_timeout ? 0 : args[1], args[2],
120 args[3], (rc == -1) && (errno == ENOSYS));
122 printf("futex(%p, %#x /* FUTEX_??? */", val, op);
124 va_start(ap, argmask);
126 for (i = 0; i < 4; i++) {
127 if (argmask & (1 << i)) {
128 fmt = va_arg(ap, const char *);
132 if (((1 << i) == ARG3) || ((1 << i) == ARG6) ||
133 (((1 << i) == ARG4) && timeout_is_val2))
134 printf(fmt, (unsigned) args[i]);
136 printf(fmt, args[i]);
143 printf(") = -1 ENOSYS (%m)\n");
146 # define CHECK_INVALID_CLOCKRT(op, ...) \
148 invalid_op(uaddr, FUTEX_CLOCK_REALTIME | (op), __VA_ARGS__); \
149 invalid_op(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG | \
150 (op), __VA_ARGS__); \
153 /* Value which differs from one stored in int *val */
154 # define VAL ((unsigned long) 0xbadda7a0facefeedLLU)
155 # define VAL_PR ((unsigned) VAL)
157 # define VALP ((unsigned long) 0xbadda7a01acefeedLLU)
158 # define VALP_PR ((unsigned) VALP)
160 # define VAL2 ((unsigned long) 0xbadda7a0ca7b100dLLU)
161 # define VAL2_PR ((unsigned) VAL2)
163 # define VAL2P ((unsigned long) 0xbadda7a07a7b100dLLU)
164 # define VAL2P_PR ((unsigned) VAL2P)
166 # define VAL3 ((unsigned long) 0xbadda7a09caffee1LLU)
167 # define VAL3_PR ((unsigned) VAL3)
170 main(int argc, char *argv[])
172 TAIL_ALLOC_OBJECT_CONST_PTR(int, uaddr);
173 TAIL_ALLOC_OBJECT_CONST_PTR(int, uaddr2);
178 uaddr[0] = 0x1deadead;
179 uaddr2[0] = 0xbadf00d;
181 TAIL_ALLOC_OBJECT_CONST_PTR(struct timespec, tmout);
183 tmout->tv_nsec = 0xbadc0de;
185 /* FUTEX_WAIT - check whether uaddr == val and sleep
186 * Possible flags: PRIVATE, CLOCK_RT (since 4.5)
187 * 1. uaddr - futex address
189 * 3. val - expected value
190 * 4. timeout - address to timespec with timeout
191 * 5. uaddr2 - not used
196 CHECK_FUTEX(NULL, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3,
197 (rc == -1) && (errno == EFAULT));
198 printf("futex(NULL, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
199 VAL_PR, (long long) tmout->tv_sec,
200 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
202 /* uaddr is faulty */
203 CHECK_FUTEX(uaddr + 1, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3,
204 (rc == -1) && (errno == EFAULT));
205 printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
206 uaddr + 1, VAL_PR, (long long) tmout->tv_sec,
207 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
209 /* timeout is faulty */
210 CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout + 1, uaddr2, VAL3,
211 (rc == -1) && (errno == EFAULT));
212 printf("futex(%p, FUTEX_WAIT, %u, %p) = %s\n",
213 uaddr, 0xfacefeed, tmout + 1, sprintrc(rc));
215 /* timeout is invalid */
216 tmout->tv_sec = 0xdeadbeefU;
217 tmout->tv_nsec = 0xfacefeedU;
219 CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3,
220 (rc == -1) && (errno == EINVAL));
221 printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
222 uaddr, VAL_PR, (long long) tmout->tv_sec,
223 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
225 tmout->tv_sec = (time_t) 0xcafef00ddeadbeefLL;
226 tmout->tv_nsec = (long) 0xbadc0dedfacefeedLL;
228 CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3,
229 (rc == -1) && (errno == EINVAL));
230 printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
231 uaddr, VAL_PR, (long long) tmout->tv_sec,
232 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
235 tmout->tv_nsec = 0xbadc0de;
237 /* uaddr is not as provided; uaddr2 is faulty but ignored */
238 CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout, uaddr2 + 1, VAL3,
239 (rc == -1) && (errno == EAGAIN));
240 printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
241 uaddr, VAL_PR, (long long) tmout->tv_sec,
242 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
244 /* uaddr is not as provided; uaddr2 is faulty but ignored */
245 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAIT, VAL, tmout,
246 uaddr2 + 1, VAL3, (rc == -1) && (errno == EAGAIN));
247 printf("futex(%p, FUTEX_WAIT_PRIVATE, %u, {tv_sec=%lld, tv_nsec=%llu})"
249 uaddr, VAL_PR, (long long) tmout->tv_sec,
250 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
252 /* Next 2 tests are with CLOCKRT bit set */
254 /* Valid after v4.4-rc2-27-g337f130 */
255 CHECK_FUTEX_ENOSYS(uaddr,
256 FUTEX_CLOCK_REALTIME | FUTEX_WAIT,
257 VAL, tmout, uaddr2, VAL3, (rc == -1) && (errno == EAGAIN));
258 printf("futex(%p, FUTEX_WAIT|FUTEX_CLOCK_REALTIME, %u"
259 ", {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
260 uaddr, VAL_PR, (long long) tmout->tv_sec,
261 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
263 CHECK_FUTEX_ENOSYS(uaddr,
264 FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG | FUTEX_WAIT,
265 VAL, tmout, uaddr2, 0, (rc == -1) && (errno == EAGAIN));
266 printf("futex(%p, FUTEX_WAIT_PRIVATE|FUTEX_CLOCK_REALTIME, %u"
267 ", {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
268 uaddr, VAL_PR, (long long) tmout->tv_sec,
269 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
271 /* FUTEX_WAIT_BITSET - FUTEX_WAIT which provides additional bitmask
272 * which should be matched at least in one bit with
273 * wake mask in order to wake.
274 * Possible flags: PRIVATE, CLOCKRT
275 * 1. uaddr - futex address
276 * 2. op - FUTEX_TRYLOCK_PI
277 * 3. val - expected value stored in uaddr
278 * 4. timeout - timeout
279 * 5. uaddr2 - not used
283 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAIT_BITSET, VAL, tmout, uaddr2 + 1,
284 VAL3, (rc == -1) && (errno == EAGAIN));
285 printf("futex(%p, FUTEX_WAIT_BITSET, %u, {tv_sec=%lld, tv_nsec=%llu}"
287 uaddr, VAL_PR, (long long) tmout->tv_sec,
288 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3_PR,
291 /* val3 of 0 is invalid */
292 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAIT_BITSET, VAL, tmout, uaddr2 + 1, 0,
293 (rc == -1) && (errno == EINVAL));
294 printf("futex(%p, FUTEX_WAIT_BITSET, %u, {tv_sec=%lld, tv_nsec=%llu}"
296 uaddr, VAL_PR, (long long) tmout->tv_sec,
297 zero_extend_signed_to_ull(tmout->tv_nsec), 0, sprintrc(rc));
299 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAIT_BITSET, VAL,
300 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EAGAIN));
301 printf("futex(%p, FUTEX_WAIT_BITSET_PRIVATE, %u"
302 ", {tv_sec=%lld, tv_nsec=%llu}, %#x) = %s\n",
303 uaddr, VAL_PR, (long long) tmout->tv_sec,
304 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3_PR,
307 /* Next 3 tests are with CLOCKRT bit set */
309 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_WAIT_BITSET, VAL,
310 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EAGAIN));
311 printf("futex(%p, FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %u"
312 ", {tv_sec=%lld, tv_nsec=%llu}, %#x) = %s\n",
313 uaddr, VAL_PR, (long long) tmout->tv_sec,
314 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3_PR,
317 /* val3 of 0 is invalid */
318 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_WAIT_BITSET, VAL,
319 tmout, uaddr2 + 1, 0, (rc == -1) && (errno == EINVAL));
320 printf("futex(%p, FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %u"
321 ", {tv_sec=%lld, tv_nsec=%llu}, %#x) = %s\n",
322 uaddr, VAL_PR, (long long) tmout->tv_sec,
323 zero_extend_signed_to_ull(tmout->tv_nsec), 0, sprintrc(rc));
325 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG |
326 FUTEX_WAIT_BITSET, VAL, tmout, uaddr2 + 1, VAL3,
327 (rc == -1) && (errno == EAGAIN));
328 printf("futex(%p, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, %u"
329 ", {tv_sec=%lld, tv_nsec=%llu}, %#x) = %s\n",
330 uaddr, VAL_PR, (long long) tmout->tv_sec,
331 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3_PR,
334 /* FUTEX_WAKE - wake val processes waiting for uaddr
335 * Possible flags: PRIVATE
336 * 1. uaddr - futex address
338 * 3. val - how many processes to wake
339 * 4. timeout - not used
340 * 5. uaddr2 - not used
344 /* Zero processes to wake is not a good idea, but it should return 0 */
345 CHECK_FUTEX(uaddr, FUTEX_WAKE, 0, NULL, NULL, 0, (rc == 0));
346 printf("futex(%p, FUTEX_WAKE, %u) = %s\n", uaddr, 0, sprintrc(rc));
348 /* Trying to wake some processes, but there's nothing to wake */
349 CHECK_FUTEX(uaddr, FUTEX_WAKE, 10, NULL, NULL, 0, (rc == 0));
350 printf("futex(%p, FUTEX_WAKE, %u) = %s\n", uaddr, 10, sprintrc(rc));
352 /* Trying to wake some processes, but there's nothing to wake */
353 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAKE, 10, NULL,
355 printf("futex(%p, FUTEX_WAKE_PRIVATE, %u) = %s\n", uaddr, 10,
358 CHECK_INVALID_CLOCKRT(FUTEX_WAKE, ARG3, "%u");
360 /* FUTEX_WAKE_BITSET - wake val processes waiting for uaddr which has at
361 * least one common bit with bitset provided in
363 * Possible flags: PRIVATE
364 * 1. uaddr - futex address
366 * 3. val - how many processes to wake
367 * 4. timeout - not used
368 * 5. uaddr2 - not used
372 /* Trying to wake some processes, but there's nothing to wake */
373 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAKE_BITSET, 10, NULL, NULL,
375 printf("futex(%p, FUTEX_WAKE_BITSET, %u, %#x) = %s\n", uaddr, 10,
376 VAL3_PR, sprintrc(rc));
378 /* bitset 0 is invalid */
379 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAKE_BITSET, 10, NULL, NULL, 0,
380 (rc == -1) && (errno == EINVAL));
381 printf("futex(%p, FUTEX_WAKE_BITSET, %u, %#x) = %s\n", uaddr, 10, 0,
384 /* Trying to wake some processes, but there's nothing to wake */
385 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAKE_BITSET, 10,
386 NULL, NULL, VAL3, (rc == 0));
387 printf("futex(%p, FUTEX_WAKE_BITSET_PRIVATE, %u, %#x) = %s\n", uaddr,
388 10, VAL3_PR, sprintrc(rc));
390 CHECK_INVALID_CLOCKRT(FUTEX_WAKE_BITSET, ARG3 | ARG6, "%u", "%#x");
392 /* FUTEX_FD - deprecated
393 * Possible flags: PRIVATE
394 * 1. uaddr - futex address
396 * 3. val - signal number
397 * 4. timeout - not used
398 * 5. uaddr2 - not used
402 /* FUTEX_FD is not implemented since 2.6.26 */
403 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_FD, VAL, NULL, NULL, VAL3,
404 (rc == -1) && (errno == EINVAL));
405 printf("futex(%p, FUTEX_FD, %u) = %s\n", uaddr, VAL_PR, sprintrc(rc));
407 /* FUTEX_FD is not implemented since 2.6.26 */
408 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_FD, VAL, NULL,
409 NULL, VAL3, (rc == -1) && (errno == EINVAL));
410 printf("futex(%p, FUTEX_FD|FUTEX_PRIVATE_FLAG, %u) = %s\n", uaddr,
411 VAL_PR, sprintrc(rc));
413 CHECK_INVALID_CLOCKRT(FUTEX_FD, ARG3, "%u");
415 /* FUTEX_REQUEUE - wake val processes and re-queue rest on uaddr2
416 * Possible flags: PRIVATE
417 * 1. uaddr - futex address
418 * 2. op - FUTEX_REQUEUE
419 * 3. val - how many processes to wake
420 * 4. val2 - amount of processes to re-queue on uadr2
421 * 5. uaddr2 - another futex address, to re-queue waiting processes on
425 /* Trying to re-queue some processes but there's nothing to re-queue */
426 CHECK_FUTEX(uaddr, FUTEX_REQUEUE, VAL, VAL2, uaddr2, VAL3,
427 (rc == 0) || ((rc == -1) && (errno == EINVAL)));
428 printf("futex(%p, FUTEX_REQUEUE, %u, %u, %p) = %s\n",
429 uaddr, VAL_PR, VAL2_PR, uaddr2, sprintrc(rc));
431 CHECK_FUTEX(uaddr, FUTEX_REQUEUE, VALP, VAL2P, uaddr2, VAL3,
433 printf("futex(%p, FUTEX_REQUEUE, %u, %u, %p) = %s\n",
434 uaddr, VALP_PR, VAL2P_PR, uaddr2, sprintrc(rc));
436 /* Trying to re-queue some processes but there's nothing to re-queue */
437 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_REQUEUE, VAL, VAL2,
438 uaddr2, VAL3, (rc == 0) || ((rc == -1) && (errno == EINVAL)));
439 printf("futex(%p, FUTEX_REQUEUE_PRIVATE, %u, %u, %p) = %s\n",
440 uaddr, VAL_PR, VAL2_PR, uaddr2, sprintrc(rc));
442 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_REQUEUE, VALP,
443 VAL2P, uaddr2, VAL3, (rc == 0));
444 printf("futex(%p, FUTEX_REQUEUE_PRIVATE, %u, %u, %p) = %s\n",
445 uaddr, VALP_PR, VAL2P_PR, uaddr2, sprintrc(rc));
447 CHECK_INVALID_CLOCKRT(FUTEX_REQUEUE, ARG3 | ARG4 | ARG5, "%u", "%u",
450 /* FUTEX_CMP_REQUEUE - wake val processes and re-queue rest on uaddr2
451 * if uaddr has value val3
452 * Possible flags: PRIVATE
453 * 1. uaddr - futex address
454 * 2. op - FUTEX_CMP_REQUEUE
455 * 3. val - how many processes to wake
456 * 4. val2 - amount of processes to re-queue on uadr2
457 * 5. uaddr2 - another futex address, to re-queue waiting processes on
458 * 6. val3 - expected value stored in uaddr
461 /* Comparison re-queue with wrong val value */
462 CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VAL, VAL2, uaddr2, VAL3,
463 (rc == -1) && (errno == EAGAIN || errno == EINVAL));
464 printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n",
465 uaddr, VAL_PR, VAL2_PR, uaddr2, VAL3_PR, sprintrc(rc));
467 CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VALP, VAL2P, uaddr2, VAL3,
468 (rc == -1) && (errno == EAGAIN));
469 printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n",
470 uaddr, VALP_PR, VAL2P_PR, uaddr2, VAL3_PR, sprintrc(rc));
472 /* Successful comparison re-queue */
473 CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VAL, VAL2, uaddr2, *uaddr,
474 (rc == 0) || ((rc == -1) && (errno == EINVAL)));
475 printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n",
476 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
478 CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VALP, VAL2P, uaddr2, *uaddr,
480 printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n",
481 uaddr, VALP_PR, VAL2P_PR, uaddr2, *uaddr, sprintrc(rc));
483 /* Successful comparison re-queue */
484 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE, VAL,
485 VAL2, uaddr2, *uaddr,
486 (rc == 0) || ((rc == -1) && (errno == EINVAL)));
487 printf("futex(%p, FUTEX_CMP_REQUEUE_PRIVATE, %u, %u, %p, %u) = %s\n",
488 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
490 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE, VALP,
491 VAL2P, uaddr2, *uaddr, (rc == 0));
492 printf("futex(%p, FUTEX_CMP_REQUEUE_PRIVATE, %u, %u, %p, %u) = %s\n",
493 uaddr, VALP_PR, VAL2P_PR, uaddr2, *uaddr, sprintrc(rc));
495 CHECK_INVALID_CLOCKRT(FUTEX_CMP_REQUEUE, ARG3 | ARG4 | ARG5 | ARG6,
496 "%u", "%u", "%#lx", "%u");
498 /* FUTEX_WAKE_OP - wake val processes waiting for uaddr, additionally
499 * wake val2 processes waiting for uaddr2 in case
500 * operation encoded in val3 (change of value at uaddr2
501 * and comparison of previous value against provided
502 * constant) succeedes with value at uaddr2. Operation
503 * result is written to value of uaddr2 (in any case).
504 * 1. uaddr - futex address
505 * 2. op - FUTEX_WAKE_OP
506 * 3. val - how many processes to wake
507 * 4. val2 - amount of processes to wake in case operation encoded in
509 * 5. uaddr2 - another futex address, for conditional wake of
510 * additional processes
511 * 6. val3 - encoded operation:
512 * 1. bit 31 - if 1 then value stored in field field 4
513 * should be interpreted as power of 2.
514 * 2. 28..30 - arithmetic operation which should be
515 * applied to previous value stored in
516 * uaddr2. Values available (from 2005 up to
517 * 2016): SET. ADD, OR, ANDN, XOR.
518 * 3. 24..29 - comparison operation which should be
519 * applied to the old value stored in uaddr2
520 * (before arithmetic operation is applied).
521 * Possible values: EQ, NE, LT, LE, GT, GE.
522 * 4. 12..23 - Second operand for arithmetic operation.
523 * If bit 31 is set, it is interpreted as
525 * 5. 00..11 - Value against which old value stored in
526 * uaddr2 is compared.
529 static const struct {
534 * Peculiar semantics:
535 * * err == 0 and err2 != 0 => expect both either the absence
536 * of error or presence of err2
537 * * err != 0 and err2 == 0 => expect err only, no success
543 { 0x00000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
544 { 0x00fff000, "FUTEX_OP_SET<<28|0xfff<<12|FUTEX_OP_CMP_EQ<<24|"
546 { 0x00000fff, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_EQ<<24|"
548 { 0x00ffffff, "FUTEX_OP_SET<<28|0xfff<<12|FUTEX_OP_CMP_EQ<<24|"
550 { 0x10000000, "FUTEX_OP_ADD<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
551 { 0x20000000, "FUTEX_OP_OR<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
552 { 0x30000000, "FUTEX_OP_ANDN<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
553 { 0x40000000, "FUTEX_OP_XOR<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
554 { 0x50000000, "0x5<<28 /* FUTEX_OP_??? */|0<<12|"
555 "FUTEX_OP_CMP_EQ<<24|0", ENOSYS },
556 { 0x70000000, "0x7<<28 /* FUTEX_OP_??? */|0<<12|"
557 "FUTEX_OP_CMP_EQ<<24|0", ENOSYS },
558 { 0x80000000, "FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_SET<<28|0<<12|"
559 "FUTEX_OP_CMP_EQ<<24|0" },
560 { 0xa0caffee, "FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_OR<<28|"
561 "0xcaf<<12|FUTEX_OP_CMP_EQ<<24|0xfee", 0, EINVAL },
562 { 0x01000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_NE<<24|0" },
563 { 0x01234567, "FUTEX_OP_SET<<28|0x234<<12|FUTEX_OP_CMP_NE<<24|"
565 { 0x02000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_LT<<24|0" },
566 { 0x03000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_LE<<24|0" },
567 { 0x04000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_GT<<24|0" },
568 { 0x05000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_GE<<24|0" },
569 { 0x06000000, "FUTEX_OP_SET<<28|0<<12|"
570 "0x6<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS },
571 { 0x07000000, "FUTEX_OP_SET<<28|0<<12|"
572 "0x7<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS },
573 { 0x08000000, "FUTEX_OP_SET<<28|0<<12|"
574 "0x8<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS },
575 { 0x0f000000, "FUTEX_OP_SET<<28|0<<12|"
576 "0xf<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS },
577 { 0xbadfaced, "FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_ANDN<<28|"
578 "0xdfa<<12|0xa<<24 /* FUTEX_OP_CMP_??? */|0xced",
580 { 0xffffffff, "FUTEX_OP_OPARG_SHIFT<<28|"
581 "0x7<<28 /* FUTEX_OP_??? */|0xfff<<12|"
582 "0xf<<24 /* FUTEX_OP_CMP_??? */|0xfff",
586 for (i = 0; i < ARRAY_SIZE(wake_ops); i++) {
587 for (j = 0; j < 2; j++) {
588 CHECK_FUTEX_ENOSYS(uaddr,
589 j ? FUTEX_WAKE_OP_PRIVATE : FUTEX_WAKE_OP,
590 VAL, i, uaddr2, wake_ops[i].val,
592 * Either one of errs is 0 or rc == 0 is not
595 ((!wake_ops[i].err || !wake_ops[i].err2 ||
597 ((!wake_ops[i].err && (rc == 0)) ||
598 (wake_ops[i].err && (rc == -1) &&
599 (errno == wake_ops[i].err)) ||
600 (wake_ops[i].err2 && (rc == -1) &&
601 (errno == wake_ops[i].err2)))));
602 printf("futex(%p, FUTEX_WAKE_OP%s, %u, %u, %p, %s)"
603 " = %s\n", uaddr, j ? "_PRIVATE" : "", VAL_PR,
604 i, uaddr2, wake_ops[i].str, sprintrc(rc));
608 CHECK_INVALID_CLOCKRT(FUTEX_WAKE_OP, ARG3 | ARG4 | ARG5 | ARG6,
610 /* Decoding of the 0xdeadbee4 value */
611 "FUTEX_OP_OPARG_SHIFT<<28|0x5<<28 /* FUTEX_OP_??? */|0xadb<<12|"
612 "0xe<<24 /* FUTEX_OP_CMP_??? */|0xee4");
614 /* FUTEX_LOCK_PI - slow path for mutex lock with process inheritance
615 * support. Expect that futex has 0 in unlocked case and
616 * TID of owning process in locked case. Value can also
617 * contain FUTEX_WAITERS bit signalling the presence of
619 * Possible flags: PRIVATE
620 * 1. uaddr - futex address
621 * 2. op - FUTEX_LOCK_PI
623 * 4. timeout - timeout
624 * 5. uaddr2 - not used
630 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_LOCK_PI, VAL, tmout, uaddr2 + 1,
631 VAL3, (rc == -1) && (errno == EFAULT));
632 printf("futex(%p, FUTEX_LOCK_PI, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
633 uaddr + 1, (long long) tmout->tv_sec,
634 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
636 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_PRIVATE_FLAG | FUTEX_LOCK_PI, VAL,
637 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EFAULT));
638 printf("futex(%p, FUTEX_LOCK_PI_PRIVATE, {tv_sec=%lld, tv_nsec=%llu})"
640 uaddr + 1, (long long) tmout->tv_sec,
641 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
643 /* NULL is passed by invalid_op() in cases valid timeout address is
645 CHECK_INVALID_CLOCKRT(FUTEX_LOCK_PI, ARG4, "NULL");
647 /* FUTEX_UNLOCK_PI - slow path for mutex unlock with process inheritance
648 * support. Expected to be called by process in case
649 * it failed to execute fast path (it usually means
650 * that FUTEX_WAITERS flag had been set while the lock
652 * Possible flags: PRIVATE
653 * 1. uaddr - futex address
654 * 2. op - FUTEX_UNLOCK_PI
656 * 4. timeout - not used
657 * 5. uaddr2 - not used
661 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_UNLOCK_PI, VAL, tmout, uaddr2 + 1,
662 VAL3, (rc == -1) && (errno == EFAULT));
663 printf("futex(%p, FUTEX_UNLOCK_PI) = %s\n", uaddr + 1, sprintrc(rc));
665 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_PRIVATE_FLAG | FUTEX_UNLOCK_PI, VAL,
666 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EFAULT));
667 printf("futex(%p, FUTEX_UNLOCK_PI_PRIVATE) = %s\n", uaddr + 1,
670 CHECK_INVALID_CLOCKRT(FUTEX_UNLOCK_PI, 0);
672 /* FUTEX_TRYLOCK_PI - slow path for mutex trylock with process
673 * inheritance support.
674 * Possible flags: PRIVATE
675 * 1. uaddr - futex address
676 * 2. op - FUTEX_TRYLOCK_PI
678 * 4. timeout - not used
679 * 5. uaddr2 - not used
683 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_TRYLOCK_PI, VAL, tmout, uaddr2 + 1,
684 VAL3, (rc == -1) && (errno == EFAULT));
685 printf("futex(%p, FUTEX_TRYLOCK_PI) = %s\n", uaddr + 1, sprintrc(rc));
687 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_PRIVATE_FLAG | FUTEX_TRYLOCK_PI,
688 VAL, tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EFAULT));
689 printf("futex(%p, FUTEX_TRYLOCK_PI_PRIVATE) = %s\n", uaddr + 1,
692 CHECK_INVALID_CLOCKRT(FUTEX_TRYLOCK_PI, 0);
694 /* FUTEX_WAIT_REQUEUE_PI - kernel-side handling of special case when
695 * processes should be re-queued on PI-aware
696 * futexes. This is so special since PI futexes
697 * utilize rt_mutex and it should be at no time
698 * left free with a wait queue, so this should
699 * be performed atomically in-kernel.
700 * Possible flags: PRIVATE, CLOCKRT
701 * 1. uaddr - futex address
702 * 2. op - FUTEX_WAIT_REQUEUE_PI
703 * 3. val - expected value stored in uaddr
704 * 4. timeout - timeout
705 * 5. uaddr2 - (PI-aware) futex address to requeue process on
706 * 6. val3 - not used (in kernel, it always initialized to
707 * FUTEX_BITSET_MATCH_ANY and passed to
708 * futex_wait_requeue_pi())
711 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAIT_REQUEUE_PI, VAL, tmout, uaddr2,
712 VAL3, (rc == -1) && (errno == EAGAIN));
713 printf("futex(%p, FUTEX_WAIT_REQUEUE_PI, %u"
714 ", {tv_sec=%lld, tv_nsec=%llu}, %p) = %s\n",
715 uaddr, VAL_PR, (long long) tmout->tv_sec,
716 zero_extend_signed_to_ull(tmout->tv_nsec), uaddr2, sprintrc(rc));
718 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAIT_REQUEUE_PI,
719 VAL, tmout, uaddr2, VAL3, (rc == -1) && (errno == EAGAIN));
720 printf("futex(%p, FUTEX_WAIT_REQUEUE_PI_PRIVATE, %u"
721 ", {tv_sec=%lld, tv_nsec=%llu}, %p) = %s\n",
722 uaddr, VAL_PR, (long long) tmout->tv_sec,
723 zero_extend_signed_to_ull(tmout->tv_nsec), uaddr2, sprintrc(rc));
725 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_WAIT_REQUEUE_PI,
726 VAL, tmout, uaddr2, VAL3, (rc == -1) && (errno == EAGAIN));
727 printf("futex(%p, FUTEX_WAIT_REQUEUE_PI|FUTEX_CLOCK_REALTIME, %u"
728 ", {tv_sec=%lld, tv_nsec=%llu}, %p) = %s\n",
729 uaddr, VAL_PR, (long long) tmout->tv_sec,
730 zero_extend_signed_to_ull(tmout->tv_nsec), uaddr2, sprintrc(rc));
732 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG |
733 FUTEX_WAIT_REQUEUE_PI, VAL, tmout, uaddr2, VAL3,
734 (rc == -1) && (errno == EAGAIN));
735 printf("futex(%p, FUTEX_WAIT_REQUEUE_PI_PRIVATE|FUTEX_CLOCK_REALTIME"
736 ", %u, {tv_sec=%lld, tv_nsec=%llu}, %p) = %s\n",
737 uaddr, VAL_PR, (long long) tmout->tv_sec,
738 zero_extend_signed_to_ull(tmout->tv_nsec), uaddr2, sprintrc(rc));
740 /* FUTEX_CMP_REQUEUE_PI - version of FUTEX_CMP_REQUEUE which re-queues
742 * Possible flags: PRIVATE
743 * 1. uaddr - futex address
744 * 2. op - FUTEX_CMP_REQUEUE
745 * 3. val - how many processes to wake
746 * 4. val2 - amount of processes to re-queue on uadr2
747 * 5. uaddr2 - (PI-aware) futex address, to re-queue waiting processes
749 * 6. val3 - expected value stored in uaddr
752 /* All these should fail with EINVAL since we try to re-queue to non-PI
756 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CMP_REQUEUE_PI, VAL, VAL2, uaddr2, VAL3,
757 (rc == -1) && (errno == EINVAL));
758 printf("futex(%p, FUTEX_CMP_REQUEUE_PI, %u, %u, %p, %u) = %s\n",
759 uaddr, VAL_PR, VAL2_PR, uaddr2, VAL3_PR, sprintrc(rc));
761 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CMP_REQUEUE_PI, VAL, VAL2, uaddr2,
762 *uaddr, (rc == -1) && (errno == EINVAL));
763 printf("futex(%p, FUTEX_CMP_REQUEUE_PI, %u, %u, %p, %u) = %s\n",
764 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
766 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE_PI,
767 VAL, VAL2, uaddr2, *uaddr, (rc == -1) && (errno == EINVAL));
768 printf("futex(%p, FUTEX_CMP_REQUEUE_PI_PRIVATE, %u, %u, %p, %u) = %s\n",
769 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
771 CHECK_INVALID_CLOCKRT(FUTEX_CMP_REQUEUE_PI, ARG3 | ARG4 | ARG5 | ARG6,
772 "%u", "%u", "%#lx", "%u");
778 CHECK_FUTEX(uaddr, 0xd, VAL, tmout + 1, uaddr2 + 1, VAL3,
779 (rc == -1) && (errno == ENOSYS));
780 printf("futex(%p, 0xd /* FUTEX_??? */, %u, %p, %p, %#x) = %s\n",
781 uaddr, VAL_PR, tmout + 1, uaddr2 + 1, VAL3_PR, sprintrc(rc));
783 CHECK_FUTEX(uaddr, 0xbefeeded, VAL, tmout + 1, uaddr2, VAL3,
784 (rc == -1) && (errno == ENOSYS));
785 printf("futex(%p, 0xbefeeded /* FUTEX_??? */, %u, %p, %p, %#x) = %s\n",
786 uaddr, VAL_PR, tmout + 1, uaddr2, VAL3_PR, sprintrc(rc));
788 puts("+++ exited with 0 +++");
795 SKIP_MAIN_UNDEFINED("__NR_futex")