Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr (at) 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 
     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 
     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
    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