2 * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
30 #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 static struct timespec *tmout;
60 void futex_error(int *uaddr, int op, unsigned long val, unsigned long timeout,
61 int *uaddr2, unsigned long val3, int rc)
63 perror_msg_and_fail("futex(%p, %#x, %#x, %#lx, %p, %#x) = %d",
64 uaddr, op, (unsigned) val, timeout, uaddr, (unsigned) val3, rc);
67 # 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), \
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 VAL2 ((unsigned long) 0xbadda7a0ca7b100dLLU)
158 # define VAL2_PR ((unsigned) VAL2)
160 # define VAL3 ((unsigned long) 0xbadda7a09caffee1LLU)
161 # define VAL3_PR ((unsigned) VAL3)
164 main(int argc, char *argv[])
166 TAIL_ALLOC_OBJECT_CONST_PTR(int, uaddr);
167 TAIL_ALLOC_OBJECT_CONST_PTR(int, uaddr2);
172 uaddr[0] = 0x1deadead;
173 uaddr2[0] = 0xbadf00d;
175 tmout = tail_alloc(sizeof(*tmout));
177 tmout->tv_nsec = 0xbadc0de;
179 /* FUTEX_WAIT - check whether uaddr == val and sleep
180 * Possible flags: PRIVATE, CLOCK_RT (since 4.5)
181 * 1. uaddr - futex address
183 * 3. val - expected value
184 * 4. timeout - address to timespec with timeout
185 * 5. uaddr2 - not used
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,
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));
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));
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));
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}) = "
221 uaddr, VAL_PR, (intmax_t) tmout->tv_sec,
222 (intmax_t) tmout->tv_nsec, sprintrc(rc));
224 /* Next 2 tests are with CLOCKRT bit set */
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,
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,
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
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}, "
259 uaddr, VAL_PR, (intmax_t) tmout->tv_sec,
260 (intmax_t) tmout->tv_nsec, VAL3_PR, sprintrc(rc));
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}, "
267 uaddr, VAL_PR, (intmax_t) tmout->tv_sec,
268 (intmax_t) tmout->tv_nsec, 0, sprintrc(rc));
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));
277 /* Next 3 tests are with CLOCKRT bit set */
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,
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,
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,
302 /* FUTEX_WAKE - wake val processes waiting for uaddr
303 * Possible flags: PRIVATE
304 * 1. uaddr - futex address
306 * 3. val - how many processes to wake
307 * 4. timeout - not used
308 * 5. uaddr2 - not used
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));
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));
320 /* Trying to wake some processes, but there's nothing to wake */
321 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAKE, 10, NULL,
323 printf("futex(%p, FUTEX_WAKE_PRIVATE, %u) = %s\n", uaddr, 10,
326 CHECK_INVALID_CLOCKRT(FUTEX_WAKE, ARG3, "%u");
328 /* FUTEX_WAKE_BITSET - wake val processes waiting for uaddr which has at
329 * least one common bit with bitset provided in
331 * Possible flags: PRIVATE
332 * 1. uaddr - futex address
334 * 3. val - how many processes to wake
335 * 4. timeout - not used
336 * 5. uaddr2 - not used
340 /* Trying to wake some processes, but there's nothing to wake */
341 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAKE_BITSET, 10, NULL, NULL,
343 printf("futex(%p, FUTEX_WAKE_BITSET, %u, %#x) = %s\n", uaddr, 10,
344 VAL3_PR, sprintrc(rc));
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,
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));
358 CHECK_INVALID_CLOCKRT(FUTEX_WAKE_BITSET, ARG3 | ARG6, "%u", "%#x");
360 /* FUTEX_FD - deprecated
361 * Possible flags: PRIVATE
362 * 1. uaddr - futex address
364 * 3. val - signal number
365 * 4. timeout - not used
366 * 5. uaddr2 - not used
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));
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));
381 CHECK_INVALID_CLOCKRT(FUTEX_FD, ARG3, "%u");
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
393 /* Trying to re-queue some processes but there's nothing to re-queue */
394 CHECK_FUTEX(uaddr, FUTEX_REQUEUE, VAL, VAL2, uaddr2, VAL3,
396 printf("futex(%p, FUTEX_REQUEUE, %u, %u, %p) = %s\n",
397 uaddr, VAL_PR, VAL2_PR, uaddr2, sprintrc(rc));
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));
405 CHECK_INVALID_CLOCKRT(FUTEX_REQUEUE, ARG3 | ARG4 | ARG5, "%u", "%u",
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
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));
425 /* Successful comparison re-queue */
426 CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VAL, VAL2, uaddr2, *uaddr,
428 printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n",
429 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
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));
437 CHECK_INVALID_CLOCKRT(FUTEX_CMP_REQUEUE, ARG3 | ARG4 | ARG5 | ARG6,
438 "%u", "%u", "%#lx", "%u");
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
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
467 * 5. 00..11 - Value against which old value stored in
468 * uaddr2 is compared.
471 static const struct {
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|"
480 { 0x00000fff, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_EQ<<24|"
482 { 0x00ffffff, "FUTEX_OP_SET<<28|0xfff<<12|FUTEX_OP_CMP_EQ<<24|"
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|"
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",
514 { 0xffffffff, "FUTEX_OP_OPARG_SHIFT<<28|"
515 "0x7<<28 /* FUTEX_OP_??? */|0xfff<<12|"
516 "0xf<<24 /* FUTEX_OP_CMP_??? */|0xfff",
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));
531 CHECK_INVALID_CLOCKRT(FUTEX_WAKE_OP, ARG3 | ARG4 | ARG5 | ARG6,
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");
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
542 * Possible flags: PRIVATE
543 * 1. uaddr - futex address
544 * 2. op - FUTEX_LOCK_PI
546 * 4. timeout - timeout
547 * 5. uaddr2 - not used
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,
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}) = "
563 uaddr + 1, (intmax_t) tmout->tv_sec, (intmax_t) tmout->tv_nsec,
566 /* NULL is passed by invalid_op() in cases valid timeout address is
568 CHECK_INVALID_CLOCKRT(FUTEX_LOCK_PI, ARG4, "NULL");
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
575 * Possible flags: PRIVATE
576 * 1. uaddr - futex address
577 * 2. op - FUTEX_UNLOCK_PI
579 * 4. timeout - not used
580 * 5. uaddr2 - not used
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));
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,
593 CHECK_INVALID_CLOCKRT(FUTEX_UNLOCK_PI, 0);
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
601 * 4. timeout - not used
602 * 5. uaddr2 - not used
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));
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,
615 CHECK_INVALID_CLOCKRT(FUTEX_TRYLOCK_PI, 0);
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())
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));
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));
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,
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,
663 /* FUTEX_CMP_REQUEUE_PI - version of FUTEX_CMP_REQUEUE which re-queues
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
672 * 6. val3 - expected value stored in uaddr
675 /* All these should fail with EINVAL since we try to re-queue to non-PI
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));
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));
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));
694 CHECK_INVALID_CLOCKRT(FUTEX_CMP_REQUEUE_PI, ARG3 | ARG4 | ARG5 | ARG6,
695 "%u", "%u", "%#lx", "%u");
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));
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));
711 puts("+++ exited with 0 +++");
718 SKIP_MAIN_UNDEFINED("__NR_futex")