2 * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
3 * Copyright (c) 2016-2017 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>
42 # include <sys/time.h>
44 # ifndef FUTEX_PRIVATE_FLAG
45 # define FUTEX_PRIVATE_FLAG 128
47 # ifndef FUTEX_CLOCK_REALTIME
48 # define FUTEX_CLOCK_REALTIME 256
50 # ifndef FUTEX_CMD_MASK
51 # define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
55 # include "xlat/futexops.h"
56 # include "xlat/futexwakeops.h"
57 # include "xlat/futexwakecmps.h"
59 void futex_error(int *uaddr, int op, unsigned long val, unsigned long timeout,
60 int *uaddr2, unsigned long val3, int rc)
62 perror_msg_and_fail("futex(%p, %#x, %#x, %#lx, %p, %#x) = %d",
63 uaddr, op, (unsigned) val, timeout, uaddr, (unsigned) val3, rc);
66 # define CHECK_FUTEX_GENERIC(uaddr, op, val, timeout, uaddr2, val3, check, \
69 rc = syscall(__NR_futex, (uaddr), (op), (val), (timeout), \
71 /* It is here due to EPERM on WAKE_OP on AArch64 */ \
72 if ((rc == -1) && (errno == EPERM)) \
74 if (enosys && (rc == -1) && (errno == ENOSYS)) \
77 futex_error((uaddr), (op), (val), \
78 (unsigned long) (timeout), (int *) (uaddr2), \
82 # define CHECK_FUTEX_ENOSYS(uaddr, op, val, timeout, uaddr2, val3, check) \
83 CHECK_FUTEX_GENERIC(uaddr, op, val, timeout, uaddr2, val3, check, 1)
85 # define CHECK_FUTEX(uaddr, op, val, timeout, uaddr2, val3, check) \
86 CHECK_FUTEX_GENERIC(uaddr, op, val, timeout, uaddr2, val3, check, 0)
95 void invalid_op(int *val, int op, uint32_t argmask, ...)
97 static const unsigned long args[] = {
98 (unsigned long) 0xface1e55deadbee1ULL,
99 (unsigned long) 0xface1e56deadbee2ULL,
100 (unsigned long) 0xface1e57deadbee3ULL,
101 (unsigned long) 0xface1e58deadbee4ULL,
103 /* Since timeout value is copied before full op check, we should provide
104 * some valid timeout address or NULL */
105 int cmd = op & FUTEX_CMD_MASK;
106 bool valid_timeout = (cmd == FUTEX_WAIT) || (cmd == FUTEX_LOCK_PI) ||
107 (cmd == FUTEX_WAIT_BITSET) || (cmd == FUTEX_WAIT_REQUEUE_PI);
108 bool timeout_is_val2 = (cmd == FUTEX_REQUEUE) ||
109 (cmd == FUTEX_CMP_REQUEUE) || (cmd == FUTEX_WAKE_OP) ||
110 (cmd == FUTEX_CMP_REQUEUE_PI);
118 CHECK_FUTEX(val, op, args[0], valid_timeout ? 0 : args[1], args[2],
119 args[3], (rc == -1) && (errno == ENOSYS));
121 printf("futex(%p, %#x /* FUTEX_??? */", val, op);
123 va_start(ap, argmask);
125 for (i = 0; i < 4; i++) {
126 if (argmask & (1 << i)) {
127 fmt = va_arg(ap, const char *);
131 if (((1 << i) == ARG3) || ((1 << i) == ARG6) ||
132 (((1 << i) == ARG4) && timeout_is_val2))
133 printf(fmt, (unsigned) args[i]);
135 printf(fmt, args[i]);
142 printf(") = -1 ENOSYS (%m)\n");
145 # define CHECK_INVALID_CLOCKRT(op, ...) \
147 invalid_op(uaddr, FUTEX_CLOCK_REALTIME | (op), __VA_ARGS__); \
148 invalid_op(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG | \
149 (op), __VA_ARGS__); \
152 /* Value which differs from one stored in int *val */
153 # define VAL ((unsigned long) 0xbadda7a0facefeedLLU)
154 # define VAL_PR ((unsigned) VAL)
156 # define VAL2 ((unsigned long) 0xbadda7a0ca7b100dLLU)
157 # define VAL2_PR ((unsigned) VAL2)
159 # define VAL3 ((unsigned long) 0xbadda7a09caffee1LLU)
160 # define VAL3_PR ((unsigned) VAL3)
163 main(int argc, char *argv[])
165 TAIL_ALLOC_OBJECT_CONST_PTR(int, uaddr);
166 TAIL_ALLOC_OBJECT_CONST_PTR(int, uaddr2);
171 uaddr[0] = 0x1deadead;
172 uaddr2[0] = 0xbadf00d;
174 TAIL_ALLOC_OBJECT_CONST_PTR(struct timespec, tmout);
176 tmout->tv_nsec = 0xbadc0de;
178 /* FUTEX_WAIT - check whether uaddr == val and sleep
179 * Possible flags: PRIVATE, CLOCK_RT (since 4.5)
180 * 1. uaddr - futex address
182 * 3. val - expected value
183 * 4. timeout - address to timespec with timeout
184 * 5. uaddr2 - not used
189 CHECK_FUTEX(NULL, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3,
190 (rc == -1) && (errno == EFAULT));
191 printf("futex(NULL, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
192 VAL_PR, (long long) tmout->tv_sec,
193 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
195 /* uaddr is faulty */
196 CHECK_FUTEX(uaddr + 1, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3,
197 (rc == -1) && (errno == EFAULT));
198 printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
199 uaddr + 1, VAL_PR, (long long) tmout->tv_sec,
200 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
202 /* timeout is faulty */
203 CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout + 1, uaddr2, VAL3,
204 (rc == -1) && (errno == EFAULT));
205 printf("futex(%p, FUTEX_WAIT, %u, %p) = %s\n",
206 uaddr, 0xfacefeed, tmout + 1, sprintrc(rc));
208 /* timeout is invalid */
209 tmout->tv_sec = 0xdeadbeefU;
210 tmout->tv_nsec = 0xfacefeedU;
212 CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3,
213 (rc == -1) && (errno == EINVAL));
214 printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
215 uaddr, VAL_PR, (long long) tmout->tv_sec,
216 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
218 tmout->tv_sec = (time_t) 0xcafef00ddeadbeefLL;
219 tmout->tv_nsec = (long) 0xbadc0dedfacefeedLL;
221 CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3,
222 (rc == -1) && (errno == EINVAL));
223 printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
224 uaddr, VAL_PR, (long long) tmout->tv_sec,
225 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
228 tmout->tv_nsec = 0xbadc0de;
230 /* uaddr is not as provided; uaddr2 is faulty but ignored */
231 CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout, uaddr2 + 1, VAL3,
232 (rc == -1) && (errno == EAGAIN));
233 printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
234 uaddr, VAL_PR, (long long) tmout->tv_sec,
235 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
237 /* uaddr is not as provided; uaddr2 is faulty but ignored */
238 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAIT, VAL, tmout,
239 uaddr2 + 1, VAL3, (rc == -1) && (errno == EAGAIN));
240 printf("futex(%p, FUTEX_WAIT_PRIVATE, %u, {tv_sec=%lld, tv_nsec=%llu})"
242 uaddr, VAL_PR, (long long) tmout->tv_sec,
243 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
245 /* Next 2 tests are with CLOCKRT bit set */
247 /* Valid after v4.4-rc2-27-g337f130 */
248 CHECK_FUTEX_ENOSYS(uaddr,
249 FUTEX_CLOCK_REALTIME | FUTEX_WAIT,
250 VAL, tmout, uaddr2, VAL3, (rc == -1) && (errno == EAGAIN));
251 printf("futex(%p, FUTEX_WAIT|FUTEX_CLOCK_REALTIME, %u"
252 ", {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
253 uaddr, VAL_PR, (long long) tmout->tv_sec,
254 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
256 CHECK_FUTEX_ENOSYS(uaddr,
257 FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG | FUTEX_WAIT,
258 VAL, tmout, uaddr2, 0, (rc == -1) && (errno == EAGAIN));
259 printf("futex(%p, FUTEX_WAIT_PRIVATE|FUTEX_CLOCK_REALTIME, %u"
260 ", {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
261 uaddr, VAL_PR, (long long) tmout->tv_sec,
262 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
264 /* FUTEX_WAIT_BITSET - FUTEX_WAIT which provides additional bitmask
265 * which should be matched at least in one bit with
266 * wake mask in order to wake.
267 * Possible flags: PRIVATE, CLOCKRT
268 * 1. uaddr - futex address
269 * 2. op - FUTEX_TRYLOCK_PI
270 * 3. val - expected value stored in uaddr
271 * 4. timeout - timeout
272 * 5. uaddr2 - not used
276 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAIT_BITSET, VAL, tmout, uaddr2 + 1,
277 VAL3, (rc == -1) && (errno == EAGAIN));
278 printf("futex(%p, FUTEX_WAIT_BITSET, %u, {tv_sec=%lld, tv_nsec=%llu}"
280 uaddr, VAL_PR, (long long) tmout->tv_sec,
281 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3_PR,
284 /* val3 of 0 is invalid */
285 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAIT_BITSET, VAL, tmout, uaddr2 + 1, 0,
286 (rc == -1) && (errno == EINVAL));
287 printf("futex(%p, FUTEX_WAIT_BITSET, %u, {tv_sec=%lld, tv_nsec=%llu}"
289 uaddr, VAL_PR, (long long) tmout->tv_sec,
290 zero_extend_signed_to_ull(tmout->tv_nsec), 0, sprintrc(rc));
292 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAIT_BITSET, VAL,
293 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EAGAIN));
294 printf("futex(%p, FUTEX_WAIT_BITSET_PRIVATE, %u"
295 ", {tv_sec=%lld, tv_nsec=%llu}, %#x) = %s\n",
296 uaddr, VAL_PR, (long long) tmout->tv_sec,
297 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3_PR,
300 /* Next 3 tests are with CLOCKRT bit set */
302 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_WAIT_BITSET, VAL,
303 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EAGAIN));
304 printf("futex(%p, FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %u"
305 ", {tv_sec=%lld, tv_nsec=%llu}, %#x) = %s\n",
306 uaddr, VAL_PR, (long long) tmout->tv_sec,
307 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3_PR,
310 /* val3 of 0 is invalid */
311 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_WAIT_BITSET, VAL,
312 tmout, uaddr2 + 1, 0, (rc == -1) && (errno == EINVAL));
313 printf("futex(%p, FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %u"
314 ", {tv_sec=%lld, tv_nsec=%llu}, %#x) = %s\n",
315 uaddr, VAL_PR, (long long) tmout->tv_sec,
316 zero_extend_signed_to_ull(tmout->tv_nsec), 0, sprintrc(rc));
318 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG |
319 FUTEX_WAIT_BITSET, VAL, tmout, uaddr2 + 1, VAL3,
320 (rc == -1) && (errno == EAGAIN));
321 printf("futex(%p, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, %u"
322 ", {tv_sec=%lld, tv_nsec=%llu}, %#x) = %s\n",
323 uaddr, VAL_PR, (long long) tmout->tv_sec,
324 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3_PR,
327 /* FUTEX_WAKE - wake val processes waiting for uaddr
328 * Possible flags: PRIVATE
329 * 1. uaddr - futex address
331 * 3. val - how many processes to wake
332 * 4. timeout - not used
333 * 5. uaddr2 - not used
337 /* Zero processes to wake is not a good idea, but it should return 0 */
338 CHECK_FUTEX(uaddr, FUTEX_WAKE, 0, NULL, NULL, 0, (rc == 0));
339 printf("futex(%p, FUTEX_WAKE, %u) = %s\n", uaddr, 0, sprintrc(rc));
341 /* Trying to wake some processes, but there's nothing to wake */
342 CHECK_FUTEX(uaddr, FUTEX_WAKE, 10, NULL, NULL, 0, (rc == 0));
343 printf("futex(%p, FUTEX_WAKE, %u) = %s\n", uaddr, 10, sprintrc(rc));
345 /* Trying to wake some processes, but there's nothing to wake */
346 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAKE, 10, NULL,
348 printf("futex(%p, FUTEX_WAKE_PRIVATE, %u) = %s\n", uaddr, 10,
351 CHECK_INVALID_CLOCKRT(FUTEX_WAKE, ARG3, "%u");
353 /* FUTEX_WAKE_BITSET - wake val processes waiting for uaddr which has at
354 * least one common bit with bitset provided in
356 * Possible flags: PRIVATE
357 * 1. uaddr - futex address
359 * 3. val - how many processes to wake
360 * 4. timeout - not used
361 * 5. uaddr2 - not used
365 /* Trying to wake some processes, but there's nothing to wake */
366 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAKE_BITSET, 10, NULL, NULL,
368 printf("futex(%p, FUTEX_WAKE_BITSET, %u, %#x) = %s\n", uaddr, 10,
369 VAL3_PR, sprintrc(rc));
371 /* bitset 0 is invalid */
372 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAKE_BITSET, 10, NULL, NULL, 0,
373 (rc == -1) && (errno == EINVAL));
374 printf("futex(%p, FUTEX_WAKE_BITSET, %u, %#x) = %s\n", uaddr, 10, 0,
377 /* Trying to wake some processes, but there's nothing to wake */
378 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAKE_BITSET, 10,
379 NULL, NULL, VAL3, (rc == 0));
380 printf("futex(%p, FUTEX_WAKE_BITSET_PRIVATE, %u, %#x) = %s\n", uaddr,
381 10, VAL3_PR, sprintrc(rc));
383 CHECK_INVALID_CLOCKRT(FUTEX_WAKE_BITSET, ARG3 | ARG6, "%u", "%#x");
385 /* FUTEX_FD - deprecated
386 * Possible flags: PRIVATE
387 * 1. uaddr - futex address
389 * 3. val - signal number
390 * 4. timeout - not used
391 * 5. uaddr2 - not used
395 /* FUTEX_FD is not implemented since 2.6.26 */
396 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_FD, VAL, NULL, NULL, VAL3,
397 (rc == -1) && (errno == EINVAL));
398 printf("futex(%p, FUTEX_FD, %u) = %s\n", uaddr, VAL_PR, sprintrc(rc));
400 /* FUTEX_FD is not implemented since 2.6.26 */
401 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_FD, VAL, NULL,
402 NULL, VAL3, (rc == -1) && (errno == EINVAL));
403 printf("futex(%p, FUTEX_FD|FUTEX_PRIVATE_FLAG, %u) = %s\n", uaddr,
404 VAL_PR, sprintrc(rc));
406 CHECK_INVALID_CLOCKRT(FUTEX_FD, ARG3, "%u");
408 /* FUTEX_REQUEUE - wake val processes and re-queue rest on uaddr2
409 * Possible flags: PRIVATE
410 * 1. uaddr - futex address
411 * 2. op - FUTEX_REQUEUE
412 * 3. val - how many processes to wake
413 * 4. val2 - amount of processes to re-queue on uadr2
414 * 5. uaddr2 - another futex address, to re-queue waiting processes on
418 /* Trying to re-queue some processes but there's nothing to re-queue */
419 CHECK_FUTEX(uaddr, FUTEX_REQUEUE, VAL, VAL2, uaddr2, VAL3,
421 printf("futex(%p, FUTEX_REQUEUE, %u, %u, %p) = %s\n",
422 uaddr, VAL_PR, VAL2_PR, uaddr2, sprintrc(rc));
424 /* Trying to re-queue some processes but there's nothing to re-queue */
425 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_REQUEUE, VAL, VAL2,
426 uaddr2, VAL3, (rc == 0));
427 printf("futex(%p, FUTEX_REQUEUE_PRIVATE, %u, %u, %p) = %s\n",
428 uaddr, VAL_PR, VAL2_PR, uaddr2, sprintrc(rc));
430 CHECK_INVALID_CLOCKRT(FUTEX_REQUEUE, ARG3 | ARG4 | ARG5, "%u", "%u",
433 /* FUTEX_CMP_REQUEUE - wake val processes and re-queue rest on uaddr2
434 * if uaddr has value val3
435 * Possible flags: PRIVATE
436 * 1. uaddr - futex address
437 * 2. op - FUTEX_CMP_REQUEUE
438 * 3. val - how many processes to wake
439 * 4. val2 - amount of processes to re-queue on uadr2
440 * 5. uaddr2 - another futex address, to re-queue waiting processes on
441 * 6. val3 - expected value stored in uaddr
444 /* Comparison re-queue with wrong val value */
445 CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VAL, VAL2, uaddr2, VAL3,
446 (rc == -1) && (errno == EAGAIN));
447 printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n",
448 uaddr, VAL_PR, VAL2_PR, uaddr2, VAL3_PR, sprintrc(rc));
450 /* Successful comparison re-queue */
451 CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VAL, VAL2, uaddr2, *uaddr,
453 printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n",
454 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
456 /* Successful comparison re-queue */
457 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE, VAL,
458 VAL2, uaddr2, *uaddr, (rc == 0));
459 printf("futex(%p, FUTEX_CMP_REQUEUE_PRIVATE, %u, %u, %p, %u) = %s\n",
460 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
462 CHECK_INVALID_CLOCKRT(FUTEX_CMP_REQUEUE, ARG3 | ARG4 | ARG5 | ARG6,
463 "%u", "%u", "%#lx", "%u");
465 /* FUTEX_WAKE_OP - wake val processes waiting for uaddr, additionally
466 * wake val2 processes waiting for uaddr2 in case
467 * operation encoded in val3 (change of value at uaddr2
468 * and comparison of previous value against provided
469 * constant) succeedes with value at uaddr2. Operation
470 * result is written to value of uaddr2 (in any case).
471 * 1. uaddr - futex address
472 * 2. op - FUTEX_WAKE_OP
473 * 3. val - how many processes to wake
474 * 4. val2 - amount of processes to wake in case operation encoded in
476 * 5. uaddr2 - another futex address, for conditional wake of
477 * additional processes
478 * 6. val3 - encoded operation:
479 * 1. bit 31 - if 1 then value stored in field field 4
480 * should be interpreted as power of 2.
481 * 2. 28..30 - arithmetic operation which should be
482 * applied to previous value stored in
483 * uaddr2. Values available (from 2005 up to
484 * 2016): SET. ADD, OR, ANDN, XOR.
485 * 3. 24..29 - comparison operation which should be
486 * applied to the old value stored in uaddr2
487 * (before arithmetic operation is applied).
488 * Possible values: EQ, NE, LT, LE, GT, GE.
489 * 4. 12..23 - Second operand for arithmetic operation.
490 * If bit 31 is set, it is interpreted as
492 * 5. 00..11 - Value against which old value stored in
493 * uaddr2 is compared.
496 static const struct {
502 { 0x00000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
503 { 0x00fff000, "FUTEX_OP_SET<<28|0xfff<<12|FUTEX_OP_CMP_EQ<<24|"
505 { 0x00000fff, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_EQ<<24|"
507 { 0x00ffffff, "FUTEX_OP_SET<<28|0xfff<<12|FUTEX_OP_CMP_EQ<<24|"
509 { 0x10000000, "FUTEX_OP_ADD<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
510 { 0x20000000, "FUTEX_OP_OR<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
511 { 0x30000000, "FUTEX_OP_ANDN<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
512 { 0x40000000, "FUTEX_OP_XOR<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
513 { 0x50000000, "0x5<<28 /* FUTEX_OP_??? */|0<<12|"
514 "FUTEX_OP_CMP_EQ<<24|0", ENOSYS, "ENOSYS" },
515 { 0x70000000, "0x7<<28 /* FUTEX_OP_??? */|0<<12|"
516 "FUTEX_OP_CMP_EQ<<24|0", ENOSYS, "ENOSYS" },
517 { 0x80000000, "FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_SET<<28|0<<12|"
518 "FUTEX_OP_CMP_EQ<<24|0" },
519 { 0xa0caffee, "FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_OR<<28|"
520 "0xcaf<<12|FUTEX_OP_CMP_EQ<<24|0xfee" },
521 { 0x01000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_NE<<24|0" },
522 { 0x01234567, "FUTEX_OP_SET<<28|0x234<<12|FUTEX_OP_CMP_NE<<24|"
524 { 0x02000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_LT<<24|0" },
525 { 0x03000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_LE<<24|0" },
526 { 0x04000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_GT<<24|0" },
527 { 0x05000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_GE<<24|0" },
528 { 0x06000000, "FUTEX_OP_SET<<28|0<<12|"
529 "0x6<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS, "ENOSYS" },
530 { 0x07000000, "FUTEX_OP_SET<<28|0<<12|"
531 "0x7<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS, "ENOSYS" },
532 { 0x08000000, "FUTEX_OP_SET<<28|0<<12|"
533 "0x8<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS, "ENOSYS" },
534 { 0x0f000000, "FUTEX_OP_SET<<28|0<<12|"
535 "0xf<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS, "ENOSYS" },
536 { 0xbadfaced, "FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_ANDN<<28|"
537 "0xdfa<<12|0xa<<24 /* FUTEX_OP_CMP_??? */|0xced",
539 { 0xffffffff, "FUTEX_OP_OPARG_SHIFT<<28|"
540 "0x7<<28 /* FUTEX_OP_??? */|0xfff<<12|"
541 "0xf<<24 /* FUTEX_OP_CMP_??? */|0xfff",
545 for (i = 0; i < ARRAY_SIZE(wake_ops); i++) {
546 for (j = 0; j < 2; j++) {
547 CHECK_FUTEX_ENOSYS(uaddr,
548 j ? FUTEX_WAKE_OP_PRIVATE : FUTEX_WAKE_OP,
549 VAL, i, uaddr2, wake_ops[i].val, (rc == 0));
550 printf("futex(%p, FUTEX_WAKE_OP%s, %u, %u, %p, %s)"
551 " = %s\n", uaddr, j ? "_PRIVATE" : "", VAL_PR,
552 i, uaddr2, wake_ops[i].str, sprintrc(rc));
556 CHECK_INVALID_CLOCKRT(FUTEX_WAKE_OP, ARG3 | ARG4 | ARG5 | ARG6,
558 /* Decoding of the 0xdeadbee4 value */
559 "FUTEX_OP_OPARG_SHIFT<<28|0x5<<28 /* FUTEX_OP_??? */|0xadb<<12|"
560 "0xe<<24 /* FUTEX_OP_CMP_??? */|0xee4");
562 /* FUTEX_LOCK_PI - slow path for mutex lock with process inheritance
563 * support. Expect that futex has 0 in unlocked case and
564 * TID of owning process in locked case. Value can also
565 * contain FUTEX_WAITERS bit signalling the presence of
567 * Possible flags: PRIVATE
568 * 1. uaddr - futex address
569 * 2. op - FUTEX_LOCK_PI
571 * 4. timeout - timeout
572 * 5. uaddr2 - not used
578 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_LOCK_PI, VAL, tmout, uaddr2 + 1,
579 VAL3, (rc == -1) && (errno == EFAULT));
580 printf("futex(%p, FUTEX_LOCK_PI, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
581 uaddr + 1, (long long) tmout->tv_sec,
582 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
584 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_PRIVATE_FLAG | FUTEX_LOCK_PI, VAL,
585 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EFAULT));
586 printf("futex(%p, FUTEX_LOCK_PI_PRIVATE, {tv_sec=%lld, tv_nsec=%llu})"
588 uaddr + 1, (long long) tmout->tv_sec,
589 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
591 /* NULL is passed by invalid_op() in cases valid timeout address is
593 CHECK_INVALID_CLOCKRT(FUTEX_LOCK_PI, ARG4, "NULL");
595 /* FUTEX_UNLOCK_PI - slow path for mutex unlock with process inheritance
596 * support. Expected to be called by process in case
597 * it failed to execute fast path (it usually means
598 * that FUTEX_WAITERS flag had been set while the lock
600 * Possible flags: PRIVATE
601 * 1. uaddr - futex address
602 * 2. op - FUTEX_UNLOCK_PI
604 * 4. timeout - not used
605 * 5. uaddr2 - not used
609 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_UNLOCK_PI, VAL, tmout, uaddr2 + 1,
610 VAL3, (rc == -1) && (errno == EFAULT));
611 printf("futex(%p, FUTEX_UNLOCK_PI) = %s\n", uaddr + 1, sprintrc(rc));
613 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_PRIVATE_FLAG | FUTEX_UNLOCK_PI, VAL,
614 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EFAULT));
615 printf("futex(%p, FUTEX_UNLOCK_PI_PRIVATE) = %s\n", uaddr + 1,
618 CHECK_INVALID_CLOCKRT(FUTEX_UNLOCK_PI, 0);
620 /* FUTEX_TRYLOCK_PI - slow path for mutex trylock with process
621 * inheritance support.
622 * Possible flags: PRIVATE
623 * 1. uaddr - futex address
624 * 2. op - FUTEX_TRYLOCK_PI
626 * 4. timeout - not used
627 * 5. uaddr2 - not used
631 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_TRYLOCK_PI, VAL, tmout, uaddr2 + 1,
632 VAL3, (rc == -1) && (errno == EFAULT));
633 printf("futex(%p, FUTEX_TRYLOCK_PI) = %s\n", uaddr + 1, sprintrc(rc));
635 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_PRIVATE_FLAG | FUTEX_TRYLOCK_PI,
636 VAL, tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EFAULT));
637 printf("futex(%p, FUTEX_TRYLOCK_PI_PRIVATE) = %s\n", uaddr + 1,
640 CHECK_INVALID_CLOCKRT(FUTEX_TRYLOCK_PI, 0);
642 /* FUTEX_WAIT_REQUEUE_PI - kernel-side handling of special case when
643 * processes should be re-queued on PI-aware
644 * futexes. This is so special since PI futexes
645 * utilize rt_mutex and it should be at no time
646 * left free with a wait queue, so this should
647 * be performed atomically in-kernel.
648 * Possible flags: PRIVATE, CLOCKRT
649 * 1. uaddr - futex address
650 * 2. op - FUTEX_WAIT_REQUEUE_PI
651 * 3. val - expected value stored in uaddr
652 * 4. timeout - timeout
653 * 5. uaddr2 - (PI-aware) futex address to requeue process on
654 * 6. val3 - not used (in kernel, it always initialized to
655 * FUTEX_BITSET_MATCH_ANY and passed to
656 * futex_wait_requeue_pi())
659 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAIT_REQUEUE_PI, VAL, tmout, uaddr2,
660 VAL3, (rc == -1) && (errno == EAGAIN));
661 printf("futex(%p, FUTEX_WAIT_REQUEUE_PI, %u"
662 ", {tv_sec=%lld, tv_nsec=%llu}, %p) = %s\n",
663 uaddr, VAL_PR, (long long) tmout->tv_sec,
664 zero_extend_signed_to_ull(tmout->tv_nsec), uaddr2, sprintrc(rc));
666 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAIT_REQUEUE_PI,
667 VAL, tmout, uaddr2, VAL3, (rc == -1) && (errno == EAGAIN));
668 printf("futex(%p, FUTEX_WAIT_REQUEUE_PI_PRIVATE, %u"
669 ", {tv_sec=%lld, tv_nsec=%llu}, %p) = %s\n",
670 uaddr, VAL_PR, (long long) tmout->tv_sec,
671 zero_extend_signed_to_ull(tmout->tv_nsec), uaddr2, sprintrc(rc));
673 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_WAIT_REQUEUE_PI,
674 VAL, tmout, uaddr2, VAL3, (rc == -1) && (errno == EAGAIN));
675 printf("futex(%p, FUTEX_WAIT_REQUEUE_PI|FUTEX_CLOCK_REALTIME, %u"
676 ", {tv_sec=%lld, tv_nsec=%llu}, %p) = %s\n",
677 uaddr, VAL_PR, (long long) tmout->tv_sec,
678 zero_extend_signed_to_ull(tmout->tv_nsec), uaddr2, sprintrc(rc));
680 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG |
681 FUTEX_WAIT_REQUEUE_PI, VAL, tmout, uaddr2, VAL3,
682 (rc == -1) && (errno == EAGAIN));
683 printf("futex(%p, FUTEX_WAIT_REQUEUE_PI_PRIVATE|FUTEX_CLOCK_REALTIME"
684 ", %u, {tv_sec=%lld, tv_nsec=%llu}, %p) = %s\n",
685 uaddr, VAL_PR, (long long) tmout->tv_sec,
686 zero_extend_signed_to_ull(tmout->tv_nsec), uaddr2, sprintrc(rc));
688 /* FUTEX_CMP_REQUEUE_PI - version of FUTEX_CMP_REQUEUE which re-queues
690 * Possible flags: PRIVATE
691 * 1. uaddr - futex address
692 * 2. op - FUTEX_CMP_REQUEUE
693 * 3. val - how many processes to wake
694 * 4. val2 - amount of processes to re-queue on uadr2
695 * 5. uaddr2 - (PI-aware) futex address, to re-queue waiting processes
697 * 6. val3 - expected value stored in uaddr
700 /* All these should fail with EINVAL since we try to re-queue to non-PI
704 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CMP_REQUEUE_PI, VAL, VAL2, uaddr2, VAL3,
705 (rc == -1) && (errno == EINVAL));
706 printf("futex(%p, FUTEX_CMP_REQUEUE_PI, %u, %u, %p, %u) = %s\n",
707 uaddr, VAL_PR, VAL2_PR, uaddr2, VAL3_PR, sprintrc(rc));
709 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CMP_REQUEUE_PI, VAL, VAL2, uaddr2,
710 *uaddr, (rc == -1) && (errno == EINVAL));
711 printf("futex(%p, FUTEX_CMP_REQUEUE_PI, %u, %u, %p, %u) = %s\n",
712 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
714 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE_PI,
715 VAL, VAL2, uaddr2, *uaddr, (rc == -1) && (errno == EINVAL));
716 printf("futex(%p, FUTEX_CMP_REQUEUE_PI_PRIVATE, %u, %u, %p, %u) = %s\n",
717 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
719 CHECK_INVALID_CLOCKRT(FUTEX_CMP_REQUEUE_PI, ARG3 | ARG4 | ARG5 | ARG6,
720 "%u", "%u", "%#lx", "%u");
726 CHECK_FUTEX(uaddr, 0xd, VAL, tmout + 1, uaddr2 + 1, VAL3,
727 (rc == -1) && (errno == ENOSYS));
728 printf("futex(%p, 0xd /* FUTEX_??? */, %u, %p, %p, %#x) = %s\n",
729 uaddr, VAL_PR, tmout + 1, uaddr2 + 1, VAL3_PR, sprintrc(rc));
731 CHECK_FUTEX(uaddr, 0xbefeeded, VAL, tmout + 1, uaddr2, VAL3,
732 (rc == -1) && (errno == ENOSYS));
733 printf("futex(%p, 0xbefeeded /* FUTEX_??? */, %u, %p, %p, %#x) = %s\n",
734 uaddr, VAL_PR, tmout + 1, uaddr2, VAL3_PR, sprintrc(rc));
736 puts("+++ exited with 0 +++");
743 SKIP_MAIN_UNDEFINED("__NR_futex")