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