1 /* 2 * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr (at) gmail.com> 3 * Copyright (c) 2016-2018 The strace developers. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 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. 16 * 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. 27 */ 28 29 #include "tests.h" 30 31 #include <asm/unistd.h> 32 33 #ifdef __NR_futex 34 35 # include <errno.h> 36 # include <stdarg.h> 37 # include <stdbool.h> 38 # include <stdio.h> 39 # include <stdint.h> 40 # include <unistd.h> 41 42 # include <sys/time.h> 43 44 # ifndef FUTEX_PRIVATE_FLAG 45 # define FUTEX_PRIVATE_FLAG 128 46 # endif 47 # ifndef FUTEX_CLOCK_REALTIME 48 # define FUTEX_CLOCK_REALTIME 256 49 # endif 50 # ifndef FUTEX_CMD_MASK 51 # define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME) 52 # endif 53 54 # include "xlat.h" 55 # include "xlat/futexops.h" 56 # include "xlat/futexwakeops.h" 57 # include "xlat/futexwakecmps.h" 58 59 void futex_error(int *uaddr, int op, unsigned long val, unsigned long timeout, 60 int *uaddr2, unsigned long val3, int rc, const char *func, int line) 61 { 62 perror_msg_and_fail("%s:%d: futex(%p, %#x, %#x, %#lx, %p, %#x) = %d", 63 func, line, uaddr, op, (unsigned) val, timeout, uaddr, 64 (unsigned) val3, rc); 65 } 66 67 # define CHECK_FUTEX_GENERIC(uaddr, op, val, timeout, uaddr2, val3, check, \ 68 enosys) \ 69 do { \ 70 errno = 0; \ 71 rc = syscall(__NR_futex, (uaddr), (op), (val), (timeout), \ 72 (uaddr2), (val3)); \ 73 /* It is here due to EPERM on WAKE_OP on AArch64 */ \ 74 if ((rc == -1) && (errno == EPERM)) \ 75 break; \ 76 if (enosys && (rc == -1) && (errno == ENOSYS)) \ 77 break; \ 78 if (!(check)) \ 79 futex_error((uaddr), (op), (val), \ 80 (unsigned long) (timeout), (int *) (uaddr2), \ 81 (val3), rc, __func__, __LINE__); \ 82 } while (0) 83 84 # define CHECK_FUTEX_ENOSYS(uaddr, op, val, timeout, uaddr2, val3, check) \ 85 CHECK_FUTEX_GENERIC(uaddr, op, val, timeout, uaddr2, val3, check, 1) 86 87 # define CHECK_FUTEX(uaddr, op, val, timeout, uaddr2, val3, check) \ 88 CHECK_FUTEX_GENERIC(uaddr, op, val, timeout, uaddr2, val3, check, 0) 89 90 enum argmask { 91 ARG3 = 1 << 0, 92 ARG4 = 1 << 1, 93 ARG5 = 1 << 2, 94 ARG6 = 1 << 3, 95 }; 96 97 void invalid_op(int *val, int op, uint32_t argmask, ...) 98 { 99 static const unsigned long args[] = { 100 (unsigned long) 0xface1e55deadbee1ULL, 101 (unsigned long) 0xface1e56deadbee2ULL, 102 (unsigned long) 0xface1e57deadbee3ULL, 103 (unsigned long) 0xface1e58deadbee4ULL, 104 }; 105 /* Since timeout value is copied before full op check, we should provide 106 * some valid timeout address or NULL */ 107 int cmd = op & FUTEX_CMD_MASK; 108 bool valid_timeout = (cmd == FUTEX_WAIT) || (cmd == FUTEX_LOCK_PI) || 109 (cmd == FUTEX_WAIT_BITSET) || (cmd == FUTEX_WAIT_REQUEUE_PI); 110 bool timeout_is_val2 = (cmd == FUTEX_REQUEUE) || 111 (cmd == FUTEX_CMP_REQUEUE) || (cmd == FUTEX_WAKE_OP) || 112 (cmd == FUTEX_CMP_REQUEUE_PI); 113 const char *fmt; 114 int saved_errno; 115 int rc; 116 int i; 117 va_list ap; 118 119 120 CHECK_FUTEX(val, op, args[0], valid_timeout ? 0 : args[1], args[2], 121 args[3], (rc == -1) && (errno == ENOSYS)); 122 saved_errno = errno; 123 printf("futex(%p, %#x /* FUTEX_??? */", val, op); 124 125 va_start(ap, argmask); 126 127 for (i = 0; i < 4; i++) { 128 if (argmask & (1 << i)) { 129 fmt = va_arg(ap, const char *); 130 131 printf(", "); 132 133 if (((1 << i) == ARG3) || ((1 << i) == ARG6) || 134 (((1 << i) == ARG4) && timeout_is_val2)) 135 printf(fmt, (unsigned) args[i]); 136 else 137 printf(fmt, args[i]); 138 } 139 } 140 141 va_end(ap); 142 143 errno = saved_errno; 144 printf(") = -1 ENOSYS (%m)\n"); 145 } 146 147 # define CHECK_INVALID_CLOCKRT(op, ...) \ 148 do { \ 149 invalid_op(uaddr, FUTEX_CLOCK_REALTIME | (op), __VA_ARGS__); \ 150 invalid_op(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG | \ 151 (op), __VA_ARGS__); \ 152 } while (0) 153 154 /* Value which differs from one stored in int *val */ 155 # define VAL ((unsigned long) 0xbadda7a0facefeedLLU) 156 # define VAL_PR ((unsigned) VAL) 157 158 # define VALP ((unsigned long) 0xbadda7a01acefeedLLU) 159 # define VALP_PR ((unsigned) VALP) 160 161 # define VAL2 ((unsigned long) 0xbadda7a0ca7b100dLLU) 162 # define VAL2_PR ((unsigned) VAL2) 163 164 # define VAL2P ((unsigned long) 0xbadda7a07a7b100dLLU) 165 # define VAL2P_PR ((unsigned) VAL2P) 166 167 # define VAL3 ((unsigned long) 0xbadda7a09caffee1LLU) 168 # define VAL3_PR ((unsigned) VAL3) 169 170 int 171 main(int argc, char *argv[]) 172 { 173 TAIL_ALLOC_OBJECT_CONST_PTR(int, uaddr); 174 TAIL_ALLOC_OBJECT_CONST_PTR(int, uaddr2); 175 int rc; 176 unsigned i; 177 unsigned j; 178 179 uaddr[0] = 0x1deadead; 180 uaddr2[0] = 0xbadf00d; 181 182 TAIL_ALLOC_OBJECT_CONST_PTR(struct timespec, tmout); 183 tmout->tv_sec = 123; 184 tmout->tv_nsec = 0xbadc0de; 185 186 /* FUTEX_WAIT - check whether uaddr == val and sleep 187 * Possible flags: PRIVATE, CLOCK_RT (since 4.5) 188 * 1. uaddr - futex address 189 * 2. op - FUTEX_WAIT 190 * 3. val - expected value 191 * 4. timeout - address to timespec with timeout 192 * 5. uaddr2 - not used 193 * 6. val3 - not used 194 */ 195 196 /* uaddr is NULL */ 197 CHECK_FUTEX(NULL, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3, 198 (rc == -1) && (errno == EFAULT)); 199 printf("futex(NULL, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n", 200 VAL_PR, (long long) tmout->tv_sec, 201 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc)); 202 203 /* uaddr is faulty */ 204 CHECK_FUTEX(uaddr + 1, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3, 205 (rc == -1) && (errno == EFAULT)); 206 printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n", 207 uaddr + 1, VAL_PR, (long long) tmout->tv_sec, 208 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc)); 209 210 /* timeout is faulty */ 211 CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout + 1, uaddr2, VAL3, 212 (rc == -1) && (errno == EFAULT)); 213 printf("futex(%p, FUTEX_WAIT, %u, %p) = %s\n", 214 uaddr, 0xfacefeed, tmout + 1, sprintrc(rc)); 215 216 /* timeout is invalid */ 217 tmout->tv_sec = 0xdeadbeefU; 218 tmout->tv_nsec = 0xfacefeedU; 219 220 CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3, 221 (rc == -1) && (errno == EINVAL)); 222 printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n", 223 uaddr, VAL_PR, (long long) tmout->tv_sec, 224 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc)); 225 226 tmout->tv_sec = (time_t) 0xcafef00ddeadbeefLL; 227 tmout->tv_nsec = (long) 0xbadc0dedfacefeedLL; 228 229 CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3, 230 (rc == -1) && (errno == EINVAL)); 231 printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n", 232 uaddr, VAL_PR, (long long) tmout->tv_sec, 233 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc)); 234 235 tmout->tv_sec = 123; 236 tmout->tv_nsec = 0xbadc0de; 237 238 /* uaddr is not as provided; uaddr2 is faulty but ignored */ 239 CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout, uaddr2 + 1, VAL3, 240 (rc == -1) && (errno == EAGAIN)); 241 printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n", 242 uaddr, VAL_PR, (long long) tmout->tv_sec, 243 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc)); 244 245 /* uaddr is not as provided; uaddr2 is faulty but ignored */ 246 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAIT, VAL, tmout, 247 uaddr2 + 1, VAL3, (rc == -1) && (errno == EAGAIN)); 248 printf("futex(%p, FUTEX_WAIT_PRIVATE, %u, {tv_sec=%lld, tv_nsec=%llu})" 249 " = %s\n", 250 uaddr, VAL_PR, (long long) tmout->tv_sec, 251 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc)); 252 253 /* Next 2 tests are with CLOCKRT bit set */ 254 255 /* Valid after v4.4-rc2-27-g337f130 */ 256 CHECK_FUTEX_ENOSYS(uaddr, 257 FUTEX_CLOCK_REALTIME | FUTEX_WAIT, 258 VAL, tmout, uaddr2, VAL3, (rc == -1) && (errno == EAGAIN)); 259 printf("futex(%p, FUTEX_WAIT|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)); 263 264 CHECK_FUTEX_ENOSYS(uaddr, 265 FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG | FUTEX_WAIT, 266 VAL, tmout, uaddr2, 0, (rc == -1) && (errno == EAGAIN)); 267 printf("futex(%p, FUTEX_WAIT_PRIVATE|FUTEX_CLOCK_REALTIME, %u" 268 ", {tv_sec=%lld, tv_nsec=%llu}) = %s\n", 269 uaddr, VAL_PR, (long long) tmout->tv_sec, 270 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc)); 271 272 /* FUTEX_WAIT_BITSET - FUTEX_WAIT which provides additional bitmask 273 * which should be matched at least in one bit with 274 * wake mask in order to wake. 275 * Possible flags: PRIVATE, CLOCKRT 276 * 1. uaddr - futex address 277 * 2. op - FUTEX_TRYLOCK_PI 278 * 3. val - expected value stored in uaddr 279 * 4. timeout - timeout 280 * 5. uaddr2 - not used 281 * 6. val3 - bitmask 282 */ 283 284 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAIT_BITSET, VAL, tmout, uaddr2 + 1, 285 VAL3, (rc == -1) && (errno == EAGAIN)); 286 printf("futex(%p, FUTEX_WAIT_BITSET, %u, {tv_sec=%lld, tv_nsec=%llu}" 287 ", %#x) = %s\n", 288 uaddr, VAL_PR, (long long) tmout->tv_sec, 289 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3_PR, 290 sprintrc(rc)); 291 292 /* val3 of 0 is invalid */ 293 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAIT_BITSET, VAL, tmout, uaddr2 + 1, 0, 294 (rc == -1) && (errno == EINVAL)); 295 printf("futex(%p, FUTEX_WAIT_BITSET, %u, {tv_sec=%lld, tv_nsec=%llu}" 296 ", %#x) = %s\n", 297 uaddr, VAL_PR, (long long) tmout->tv_sec, 298 zero_extend_signed_to_ull(tmout->tv_nsec), 0, sprintrc(rc)); 299 300 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAIT_BITSET, VAL, 301 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EAGAIN)); 302 printf("futex(%p, FUTEX_WAIT_BITSET_PRIVATE, %u" 303 ", {tv_sec=%lld, tv_nsec=%llu}, %#x) = %s\n", 304 uaddr, VAL_PR, (long long) tmout->tv_sec, 305 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3_PR, 306 sprintrc(rc)); 307 308 /* Next 3 tests are with CLOCKRT bit set */ 309 310 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_WAIT_BITSET, VAL, 311 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EAGAIN)); 312 printf("futex(%p, FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %u" 313 ", {tv_sec=%lld, tv_nsec=%llu}, %#x) = %s\n", 314 uaddr, VAL_PR, (long long) tmout->tv_sec, 315 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3_PR, 316 sprintrc(rc)); 317 318 /* val3 of 0 is invalid */ 319 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_WAIT_BITSET, VAL, 320 tmout, uaddr2 + 1, 0, (rc == -1) && (errno == EINVAL)); 321 printf("futex(%p, FUTEX_WAIT_BITSET|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), 0, sprintrc(rc)); 325 326 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG | 327 FUTEX_WAIT_BITSET, VAL, tmout, uaddr2 + 1, VAL3, 328 (rc == -1) && (errno == EAGAIN)); 329 printf("futex(%p, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, %u" 330 ", {tv_sec=%lld, tv_nsec=%llu}, %#x) = %s\n", 331 uaddr, VAL_PR, (long long) tmout->tv_sec, 332 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3_PR, 333 sprintrc(rc)); 334 335 /* FUTEX_WAKE - wake val processes waiting for uaddr 336 * Possible flags: PRIVATE 337 * 1. uaddr - futex address 338 * 2. op - FUTEX_WAKE 339 * 3. val - how many processes to wake 340 * 4. timeout - not used 341 * 5. uaddr2 - not used 342 * 6. val3 - not used 343 */ 344 345 /* Zero processes to wake is not a good idea, but it should return 0 */ 346 CHECK_FUTEX(uaddr, FUTEX_WAKE, 0, NULL, NULL, 0, (rc == 0)); 347 printf("futex(%p, FUTEX_WAKE, %u) = %s\n", uaddr, 0, sprintrc(rc)); 348 349 /* Trying to wake some processes, but there's nothing to wake */ 350 CHECK_FUTEX(uaddr, FUTEX_WAKE, 10, NULL, NULL, 0, (rc == 0)); 351 printf("futex(%p, FUTEX_WAKE, %u) = %s\n", uaddr, 10, sprintrc(rc)); 352 353 /* Trying to wake some processes, but there's nothing to wake */ 354 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAKE, 10, NULL, 355 NULL, 0, (rc == 0)); 356 printf("futex(%p, FUTEX_WAKE_PRIVATE, %u) = %s\n", uaddr, 10, 357 sprintrc(rc)); 358 359 CHECK_INVALID_CLOCKRT(FUTEX_WAKE, ARG3, "%u"); 360 361 /* FUTEX_WAKE_BITSET - wake val processes waiting for uaddr which has at 362 * least one common bit with bitset provided in 363 * val3. 364 * Possible flags: PRIVATE 365 * 1. uaddr - futex address 366 * 2. op - FUTEX_WAKE 367 * 3. val - how many processes to wake 368 * 4. timeout - not used 369 * 5. uaddr2 - not used 370 * 6. val3 - bitmask 371 */ 372 373 /* Trying to wake some processes, but there's nothing to wake */ 374 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAKE_BITSET, 10, NULL, NULL, 375 VAL3, (rc == 0)); 376 printf("futex(%p, FUTEX_WAKE_BITSET, %u, %#x) = %s\n", uaddr, 10, 377 VAL3_PR, sprintrc(rc)); 378 379 /* bitset 0 is invalid */ 380 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAKE_BITSET, 10, NULL, NULL, 0, 381 (rc == -1) && (errno == EINVAL)); 382 printf("futex(%p, FUTEX_WAKE_BITSET, %u, %#x) = %s\n", uaddr, 10, 0, 383 sprintrc(rc)); 384 385 /* Trying to wake some processes, but there's nothing to wake */ 386 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAKE_BITSET, 10, 387 NULL, NULL, VAL3, (rc == 0)); 388 printf("futex(%p, FUTEX_WAKE_BITSET_PRIVATE, %u, %#x) = %s\n", uaddr, 389 10, VAL3_PR, sprintrc(rc)); 390 391 CHECK_INVALID_CLOCKRT(FUTEX_WAKE_BITSET, ARG3 | ARG6, "%u", "%#x"); 392 393 /* FUTEX_FD - deprecated 394 * Possible flags: PRIVATE 395 * 1. uaddr - futex address 396 * 2. op - FUTEX_FD 397 * 3. val - signal number 398 * 4. timeout - not used 399 * 5. uaddr2 - not used 400 * 6. val3 - not used 401 */ 402 403 /* FUTEX_FD is not implemented since 2.6.26 */ 404 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_FD, VAL, NULL, NULL, VAL3, 405 (rc == -1) && (errno == EINVAL)); 406 printf("futex(%p, FUTEX_FD, %u) = %s\n", uaddr, VAL_PR, sprintrc(rc)); 407 408 /* FUTEX_FD is not implemented since 2.6.26 */ 409 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_FD, VAL, NULL, 410 NULL, VAL3, (rc == -1) && (errno == EINVAL)); 411 printf("futex(%p, FUTEX_FD|FUTEX_PRIVATE_FLAG, %u) = %s\n", uaddr, 412 VAL_PR, sprintrc(rc)); 413 414 CHECK_INVALID_CLOCKRT(FUTEX_FD, ARG3, "%u"); 415 416 /* FUTEX_REQUEUE - wake val processes and re-queue rest on uaddr2 417 * Possible flags: PRIVATE 418 * 1. uaddr - futex address 419 * 2. op - FUTEX_REQUEUE 420 * 3. val - how many processes to wake 421 * 4. val2 - amount of processes to re-queue on uadr2 422 * 5. uaddr2 - another futex address, to re-queue waiting processes on 423 * 6. val3 - not used 424 */ 425 426 /* Trying to re-queue some processes but there's nothing to re-queue */ 427 CHECK_FUTEX(uaddr, FUTEX_REQUEUE, VAL, VAL2, uaddr2, VAL3, 428 (rc == 0) || ((rc == -1) && (errno == EINVAL))); 429 printf("futex(%p, FUTEX_REQUEUE, %u, %u, %p) = %s\n", 430 uaddr, VAL_PR, VAL2_PR, uaddr2, sprintrc(rc)); 431 432 CHECK_FUTEX(uaddr, FUTEX_REQUEUE, VALP, VAL2P, uaddr2, VAL3, 433 (rc == 0)); 434 printf("futex(%p, FUTEX_REQUEUE, %u, %u, %p) = %s\n", 435 uaddr, VALP_PR, VAL2P_PR, uaddr2, sprintrc(rc)); 436 437 /* Trying to re-queue some processes but there's nothing to re-queue */ 438 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_REQUEUE, VAL, VAL2, 439 uaddr2, VAL3, (rc == 0) || ((rc == -1) && (errno == EINVAL))); 440 printf("futex(%p, FUTEX_REQUEUE_PRIVATE, %u, %u, %p) = %s\n", 441 uaddr, VAL_PR, VAL2_PR, uaddr2, sprintrc(rc)); 442 443 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_REQUEUE, VALP, 444 VAL2P, uaddr2, VAL3, (rc == 0)); 445 printf("futex(%p, FUTEX_REQUEUE_PRIVATE, %u, %u, %p) = %s\n", 446 uaddr, VALP_PR, VAL2P_PR, uaddr2, sprintrc(rc)); 447 448 CHECK_INVALID_CLOCKRT(FUTEX_REQUEUE, ARG3 | ARG4 | ARG5, "%u", "%u", 449 "%#lx"); 450 451 /* FUTEX_CMP_REQUEUE - wake val processes and re-queue rest on uaddr2 452 * if uaddr has value val3 453 * Possible flags: PRIVATE 454 * 1. uaddr - futex address 455 * 2. op - FUTEX_CMP_REQUEUE 456 * 3. val - how many processes to wake 457 * 4. val2 - amount of processes to re-queue on uadr2 458 * 5. uaddr2 - another futex address, to re-queue waiting processes on 459 * 6. val3 - expected value stored in uaddr 460 */ 461 462 /* Comparison re-queue with wrong val value */ 463 CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VAL, VAL2, uaddr2, VAL3, 464 (rc == -1) && (errno == EAGAIN || errno == EINVAL)); 465 printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n", 466 uaddr, VAL_PR, VAL2_PR, uaddr2, VAL3_PR, sprintrc(rc)); 467 468 CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VALP, VAL2P, uaddr2, VAL3, 469 (rc == -1) && (errno == EAGAIN)); 470 printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n", 471 uaddr, VALP_PR, VAL2P_PR, uaddr2, VAL3_PR, sprintrc(rc)); 472 473 /* Successful comparison re-queue */ 474 CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VAL, VAL2, uaddr2, *uaddr, 475 (rc == 0) || ((rc == -1) && (errno == EINVAL))); 476 printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n", 477 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc)); 478 479 CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VALP, VAL2P, uaddr2, *uaddr, 480 (rc == 0)); 481 printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n", 482 uaddr, VALP_PR, VAL2P_PR, uaddr2, *uaddr, sprintrc(rc)); 483 484 /* Successful comparison re-queue */ 485 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE, VAL, 486 VAL2, uaddr2, *uaddr, 487 (rc == 0) || ((rc == -1) && (errno == EINVAL))); 488 printf("futex(%p, FUTEX_CMP_REQUEUE_PRIVATE, %u, %u, %p, %u) = %s\n", 489 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc)); 490 491 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE, VALP, 492 VAL2P, uaddr2, *uaddr, (rc == 0)); 493 printf("futex(%p, FUTEX_CMP_REQUEUE_PRIVATE, %u, %u, %p, %u) = %s\n", 494 uaddr, VALP_PR, VAL2P_PR, uaddr2, *uaddr, sprintrc(rc)); 495 496 CHECK_INVALID_CLOCKRT(FUTEX_CMP_REQUEUE, ARG3 | ARG4 | ARG5 | ARG6, 497 "%u", "%u", "%#lx", "%u"); 498 499 /* FUTEX_WAKE_OP - wake val processes waiting for uaddr, additionally 500 * wake val2 processes waiting for uaddr2 in case 501 * operation encoded in val3 (change of value at uaddr2 502 * and comparison of previous value against provided 503 * constant) succeedes with value at uaddr2. Operation 504 * result is written to value of uaddr2 (in any case). 505 * 1. uaddr - futex address 506 * 2. op - FUTEX_WAKE_OP 507 * 3. val - how many processes to wake 508 * 4. val2 - amount of processes to wake in case operation encoded in 509 * val3 returns true 510 * 5. uaddr2 - another futex address, for conditional wake of 511 * additional processes 512 * 6. val3 - encoded operation: 513 * 1. bit 31 - if 1 then value stored in field field 4 514 * should be interpreted as power of 2. 515 * 2. 28..30 - arithmetic operation which should be 516 * applied to previous value stored in 517 * uaddr2. Values available (from 2005 up to 518 * 2016): SET. ADD, OR, ANDN, XOR. 519 * 3. 24..29 - comparison operation which should be 520 * applied to the old value stored in uaddr2 521 * (before arithmetic operation is applied). 522 * Possible values: EQ, NE, LT, LE, GT, GE. 523 * 4. 12..23 - Second operand for arithmetic operation. 524 * If bit 31 is set, it is interpreted as 525 * power of 2. 526 * 5. 00..11 - Value against which old value stored in 527 * uaddr2 is compared. 528 */ 529 530 static const struct { 531 uint32_t val; 532 const char *str; 533 534 /* 535 * Peculiar semantics: 536 * * err == 0 and err2 != 0 => expect both either the absence 537 * of error or presence of err2 538 * * err != 0 and err2 == 0 => expect err only, no success 539 * expected. 540 */ 541 int err; 542 int err2; 543 } wake_ops[] = { 544 { 0x00000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" }, 545 { 0x00fff000, "FUTEX_OP_SET<<28|0xfff<<12|FUTEX_OP_CMP_EQ<<24|" 546 "0" }, 547 { 0x00000fff, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_EQ<<24|" 548 "0xfff" }, 549 { 0x00ffffff, "FUTEX_OP_SET<<28|0xfff<<12|FUTEX_OP_CMP_EQ<<24|" 550 "0xfff" }, 551 { 0x10000000, "FUTEX_OP_ADD<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" }, 552 { 0x20000000, "FUTEX_OP_OR<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" }, 553 { 0x30000000, "FUTEX_OP_ANDN<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" }, 554 { 0x40000000, "FUTEX_OP_XOR<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" }, 555 { 0x50000000, "0x5<<28 /* FUTEX_OP_??? */|0<<12|" 556 "FUTEX_OP_CMP_EQ<<24|0", ENOSYS }, 557 { 0x70000000, "0x7<<28 /* FUTEX_OP_??? */|0<<12|" 558 "FUTEX_OP_CMP_EQ<<24|0", ENOSYS }, 559 { 0x80000000, "FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_SET<<28|0<<12|" 560 "FUTEX_OP_CMP_EQ<<24|0" }, 561 { 0xa0caffee, "FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_OR<<28|" 562 "0xcaf<<12|FUTEX_OP_CMP_EQ<<24|0xfee", 0, EINVAL }, 563 { 0x01000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_NE<<24|0" }, 564 { 0x01234567, "FUTEX_OP_SET<<28|0x234<<12|FUTEX_OP_CMP_NE<<24|" 565 "0x567" }, 566 { 0x02000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_LT<<24|0" }, 567 { 0x03000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_LE<<24|0" }, 568 { 0x04000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_GT<<24|0" }, 569 { 0x05000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_GE<<24|0" }, 570 { 0x06000000, "FUTEX_OP_SET<<28|0<<12|" 571 "0x6<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS }, 572 { 0x07000000, "FUTEX_OP_SET<<28|0<<12|" 573 "0x7<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS }, 574 { 0x08000000, "FUTEX_OP_SET<<28|0<<12|" 575 "0x8<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS }, 576 { 0x0f000000, "FUTEX_OP_SET<<28|0<<12|" 577 "0xf<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS }, 578 { 0xbadfaced, "FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_ANDN<<28|" 579 "0xdfa<<12|0xa<<24 /* FUTEX_OP_CMP_??? */|0xced", 580 ENOSYS, EINVAL }, 581 { 0xffffffff, "FUTEX_OP_OPARG_SHIFT<<28|" 582 "0x7<<28 /* FUTEX_OP_??? */|0xfff<<12|" 583 "0xf<<24 /* FUTEX_OP_CMP_??? */|0xfff", 584 ENOSYS, EINVAL }, 585 }; 586 587 for (i = 0; i < ARRAY_SIZE(wake_ops); i++) { 588 for (j = 0; j < 2; j++) { 589 CHECK_FUTEX_ENOSYS(uaddr, 590 j ? FUTEX_WAKE_OP_PRIVATE : FUTEX_WAKE_OP, 591 VAL, i, uaddr2, wake_ops[i].val, 592 /* 593 * Either one of errs is 0 or rc == 0 is not 594 * allowed. 595 */ 596 ((!wake_ops[i].err || !wake_ops[i].err2 || 597 (rc != 0)) && 598 ((!wake_ops[i].err && (rc == 0)) || 599 (wake_ops[i].err && (rc == -1) && 600 (errno == wake_ops[i].err)) || 601 (wake_ops[i].err2 && (rc == -1) && 602 (errno == wake_ops[i].err2))))); 603 printf("futex(%p, FUTEX_WAKE_OP%s, %u, %u, %p, %s)" 604 " = %s\n", uaddr, j ? "_PRIVATE" : "", VAL_PR, 605 i, uaddr2, wake_ops[i].str, sprintrc(rc)); 606 } 607 } 608 609 CHECK_INVALID_CLOCKRT(FUTEX_WAKE_OP, ARG3 | ARG4 | ARG5 | ARG6, 610 "%u", "%u", "%#lx", 611 /* Decoding of the 0xdeadbee4 value */ 612 "FUTEX_OP_OPARG_SHIFT<<28|0x5<<28 /* FUTEX_OP_??? */|0xadb<<12|" 613 "0xe<<24 /* FUTEX_OP_CMP_??? */|0xee4"); 614 615 /* FUTEX_LOCK_PI - slow path for mutex lock with process inheritance 616 * support. Expect that futex has 0 in unlocked case and 617 * TID of owning process in locked case. Value can also 618 * contain FUTEX_WAITERS bit signalling the presence of 619 * waiters queue. 620 * Possible flags: PRIVATE 621 * 1. uaddr - futex address 622 * 2. op - FUTEX_LOCK_PI 623 * 3. val - not used 624 * 4. timeout - timeout 625 * 5. uaddr2 - not used 626 * 6. val3 - not used 627 */ 628 629 *uaddr = getpid(); 630 631 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_LOCK_PI, VAL, tmout, uaddr2 + 1, 632 VAL3, (rc == -1) && (errno == EFAULT)); 633 printf("futex(%p, FUTEX_LOCK_PI, {tv_sec=%lld, tv_nsec=%llu}) = %s\n", 634 uaddr + 1, (long long) tmout->tv_sec, 635 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc)); 636 637 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_PRIVATE_FLAG | FUTEX_LOCK_PI, VAL, 638 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EFAULT)); 639 printf("futex(%p, FUTEX_LOCK_PI_PRIVATE, {tv_sec=%lld, tv_nsec=%llu})" 640 " = %s\n", 641 uaddr + 1, (long long) tmout->tv_sec, 642 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc)); 643 644 /* NULL is passed by invalid_op() in cases valid timeout address is 645 * needed */ 646 CHECK_INVALID_CLOCKRT(FUTEX_LOCK_PI, ARG4, "NULL"); 647 648 /* FUTEX_UNLOCK_PI - slow path for mutex unlock with process inheritance 649 * support. Expected to be called by process in case 650 * it failed to execute fast path (it usually means 651 * that FUTEX_WAITERS flag had been set while the lock 652 * has been held). 653 * Possible flags: PRIVATE 654 * 1. uaddr - futex address 655 * 2. op - FUTEX_UNLOCK_PI 656 * 3. val - not used 657 * 4. timeout - not used 658 * 5. uaddr2 - not used 659 * 6. val3 - not used 660 */ 661 662 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_UNLOCK_PI, VAL, tmout, uaddr2 + 1, 663 VAL3, (rc == -1) && (errno == EFAULT)); 664 printf("futex(%p, FUTEX_UNLOCK_PI) = %s\n", uaddr + 1, sprintrc(rc)); 665 666 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_PRIVATE_FLAG | FUTEX_UNLOCK_PI, VAL, 667 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EFAULT)); 668 printf("futex(%p, FUTEX_UNLOCK_PI_PRIVATE) = %s\n", uaddr + 1, 669 sprintrc(rc)); 670 671 CHECK_INVALID_CLOCKRT(FUTEX_UNLOCK_PI, 0); 672 673 /* FUTEX_TRYLOCK_PI - slow path for mutex trylock with process 674 * inheritance support. 675 * Possible flags: PRIVATE 676 * 1. uaddr - futex address 677 * 2. op - FUTEX_TRYLOCK_PI 678 * 3. val - not used 679 * 4. timeout - not used 680 * 5. uaddr2 - not used 681 * 6. val3 - not used 682 */ 683 684 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_TRYLOCK_PI, VAL, tmout, uaddr2 + 1, 685 VAL3, (rc == -1) && (errno == EFAULT)); 686 printf("futex(%p, FUTEX_TRYLOCK_PI) = %s\n", uaddr + 1, sprintrc(rc)); 687 688 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_PRIVATE_FLAG | FUTEX_TRYLOCK_PI, 689 VAL, tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EFAULT)); 690 printf("futex(%p, FUTEX_TRYLOCK_PI_PRIVATE) = %s\n", uaddr + 1, 691 sprintrc(rc)); 692 693 CHECK_INVALID_CLOCKRT(FUTEX_TRYLOCK_PI, 0); 694 695 /* FUTEX_WAIT_REQUEUE_PI - kernel-side handling of special case when 696 * processes should be re-queued on PI-aware 697 * futexes. This is so special since PI futexes 698 * utilize rt_mutex and it should be at no time 699 * left free with a wait queue, so this should 700 * be performed atomically in-kernel. 701 * Possible flags: PRIVATE, CLOCKRT 702 * 1. uaddr - futex address 703 * 2. op - FUTEX_WAIT_REQUEUE_PI 704 * 3. val - expected value stored in uaddr 705 * 4. timeout - timeout 706 * 5. uaddr2 - (PI-aware) futex address to requeue process on 707 * 6. val3 - not used (in kernel, it always initialized to 708 * FUTEX_BITSET_MATCH_ANY and passed to 709 * futex_wait_requeue_pi()) 710 */ 711 712 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAIT_REQUEUE_PI, VAL, tmout, uaddr2, 713 VAL3, (rc == -1) && (errno == EAGAIN)); 714 printf("futex(%p, FUTEX_WAIT_REQUEUE_PI, %u" 715 ", {tv_sec=%lld, tv_nsec=%llu}, %p) = %s\n", 716 uaddr, VAL_PR, (long long) tmout->tv_sec, 717 zero_extend_signed_to_ull(tmout->tv_nsec), uaddr2, sprintrc(rc)); 718 719 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAIT_REQUEUE_PI, 720 VAL, tmout, uaddr2, VAL3, (rc == -1) && (errno == EAGAIN)); 721 printf("futex(%p, FUTEX_WAIT_REQUEUE_PI_PRIVATE, %u" 722 ", {tv_sec=%lld, tv_nsec=%llu}, %p) = %s\n", 723 uaddr, VAL_PR, (long long) tmout->tv_sec, 724 zero_extend_signed_to_ull(tmout->tv_nsec), uaddr2, sprintrc(rc)); 725 726 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_WAIT_REQUEUE_PI, 727 VAL, tmout, uaddr2, VAL3, (rc == -1) && (errno == EAGAIN)); 728 printf("futex(%p, FUTEX_WAIT_REQUEUE_PI|FUTEX_CLOCK_REALTIME, %u" 729 ", {tv_sec=%lld, tv_nsec=%llu}, %p) = %s\n", 730 uaddr, VAL_PR, (long long) tmout->tv_sec, 731 zero_extend_signed_to_ull(tmout->tv_nsec), uaddr2, sprintrc(rc)); 732 733 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG | 734 FUTEX_WAIT_REQUEUE_PI, VAL, tmout, uaddr2, VAL3, 735 (rc == -1) && (errno == EAGAIN)); 736 printf("futex(%p, FUTEX_WAIT_REQUEUE_PI_PRIVATE|FUTEX_CLOCK_REALTIME" 737 ", %u, {tv_sec=%lld, tv_nsec=%llu}, %p) = %s\n", 738 uaddr, VAL_PR, (long long) tmout->tv_sec, 739 zero_extend_signed_to_ull(tmout->tv_nsec), uaddr2, sprintrc(rc)); 740 741 /* FUTEX_CMP_REQUEUE_PI - version of FUTEX_CMP_REQUEUE which re-queues 742 * on PI-aware futex. 743 * Possible flags: PRIVATE 744 * 1. uaddr - futex address 745 * 2. op - FUTEX_CMP_REQUEUE 746 * 3. val - how many processes to wake 747 * 4. val2 - amount of processes to re-queue on uadr2 748 * 5. uaddr2 - (PI-aware) futex address, to re-queue waiting processes 749 * on 750 * 6. val3 - expected value stored in uaddr 751 */ 752 753 /* All these should fail with EINVAL since we try to re-queue to non-PI 754 * futex. 755 */ 756 757 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CMP_REQUEUE_PI, VAL, VAL2, uaddr2, VAL3, 758 (rc == -1) && (errno == EINVAL)); 759 printf("futex(%p, FUTEX_CMP_REQUEUE_PI, %u, %u, %p, %u) = %s\n", 760 uaddr, VAL_PR, VAL2_PR, uaddr2, VAL3_PR, sprintrc(rc)); 761 762 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CMP_REQUEUE_PI, VAL, VAL2, uaddr2, 763 *uaddr, (rc == -1) && (errno == EINVAL)); 764 printf("futex(%p, FUTEX_CMP_REQUEUE_PI, %u, %u, %p, %u) = %s\n", 765 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc)); 766 767 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE_PI, 768 VAL, VAL2, uaddr2, *uaddr, (rc == -1) && (errno == EINVAL)); 769 printf("futex(%p, FUTEX_CMP_REQUEUE_PI_PRIVATE, %u, %u, %p, %u) = %s\n", 770 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc)); 771 772 CHECK_INVALID_CLOCKRT(FUTEX_CMP_REQUEUE_PI, ARG3 | ARG4 | ARG5 | ARG6, 773 "%u", "%u", "%#lx", "%u"); 774 775 /* 776 * Unknown commands 777 */ 778 779 CHECK_FUTEX(uaddr, 0xd, VAL, tmout + 1, uaddr2 + 1, VAL3, 780 (rc == -1) && (errno == ENOSYS)); 781 printf("futex(%p, 0xd /* FUTEX_??? */, %u, %p, %p, %#x) = %s\n", 782 uaddr, VAL_PR, tmout + 1, uaddr2 + 1, VAL3_PR, sprintrc(rc)); 783 784 CHECK_FUTEX(uaddr, 0xbefeeded, VAL, tmout + 1, uaddr2, VAL3, 785 (rc == -1) && (errno == ENOSYS)); 786 printf("futex(%p, 0xbefeeded /* FUTEX_??? */, %u, %p, %p, %#x) = %s\n", 787 uaddr, VAL_PR, tmout + 1, uaddr2, VAL3_PR, sprintrc(rc)); 788 789 puts("+++ exited with 0 +++"); 790 791 return 0; 792 } 793 794 #else 795 796 SKIP_MAIN_UNDEFINED("__NR_futex") 797 798 #endif 799