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