1 /* $NetBSD: t_futex_ops.c,v 1.14 2025/03/05 12:02:00 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2019, 2020 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __COPYRIGHT("@(#) Copyright (c) 2019, 2020\ 31 The NetBSD Foundation, inc. All rights reserved."); 32 __RCSID("$NetBSD: t_futex_ops.c,v 1.14 2025/03/05 12:02:00 riastradh Exp $"); 33 34 #include <sys/fcntl.h> 35 #include <sys/mman.h> 36 #include <sys/wait.h> 37 #include <atomic.h> 38 #include <errno.h> 39 #include <lwp.h> 40 #include <stdlib.h> 41 #include <stdio.h> 42 #include <signal.h> 43 #include <time.h> 44 #include <limits.h> 45 #include <sched.h> 46 #include <unistd.h> 47 48 #include <atf-c.h> 49 50 #include <libc/include/futex_private.h> 51 52 #include "h_macros.h" 53 54 #define LOAD(x) (*(volatile int *)(x)) 55 #define STORE(x, y) *(volatile int *)(x) = (y) 56 57 #if 0 58 #define DPRINTF(x) printf x 59 #else 60 #define DPRINTF(x) __nothing 61 #endif 62 63 #define STACK_SIZE 65536 64 65 static volatile int futex_word; 66 static volatile int futex_word1; 67 68 static volatile unsigned int nlwps_running; 69 70 struct lwp_data { 71 ucontext_t context; 72 void (*func)(void *); 73 void *stack_base; 74 lwpid_t lwpid; 75 pid_t child; 76 lwpid_t threadid; 77 int wait_op; 78 int op_flags; 79 int bitset; 80 volatile int *futex_ptr; 81 volatile int *error_ptr; 82 int block_val; 83 84 void (*exit_func)(void); 85 86 int futex_error; 87 }; 88 89 #define WAITER_LWP0 0 90 #define WAITER_LWP1 1 91 #define WAITER_LWP2 2 92 #define WAITER_LWP3 3 93 #define WAITER_LWP4 4 94 #define WAITER_LWP5 5 95 #define NLWPS 6 96 97 struct lwp_data lwp_data[NLWPS]; 98 99 static const char *bs_path = "t_futex_ops_backing_store"; 100 static int bs_fd = -1; 101 static int *bs_addr = MAP_FAILED; 102 static void *bs_source_buffer = NULL; 103 static void *bs_verify_buffer = NULL; 104 static long bs_pagesize; 105 106 static void 107 create_lwp_waiter(struct lwp_data *d) 108 { 109 RL(_lwp_create(&d->context, 0, &d->lwpid)); 110 } 111 112 static void 113 exit_lwp_waiter(void) 114 { 115 _lwp_exit(); 116 } 117 118 static void 119 reap_lwp_waiter(struct lwp_data *d) 120 { 121 RL(_lwp_wait(d->lwpid, NULL)); 122 } 123 124 static void 125 create_proc_waiter(struct lwp_data *d) 126 { 127 pid_t pid; 128 129 RL(pid = fork()); 130 if (pid == 0) { 131 (*d->func)(d); 132 _exit(666); /* backstop */ 133 } else 134 d->child = pid; 135 } 136 137 static void 138 exit_proc_waiter(void) 139 { 140 _exit(0); 141 } 142 143 static void 144 reap_proc_waiter(struct lwp_data *d) 145 { 146 pid_t pid; 147 int status; 148 149 RL(pid = waitpid(d->child, &status, 0)); 150 ATF_CHECK_EQ_MSG(pid, d->child, 151 "pid=%lld d->child=%lld", (long long)pid, (long long)d->child); 152 ATF_CHECK_MSG(WIFEXITED(status), "status=0x%x", status); 153 ATF_CHECK_EQ_MSG(WEXITSTATUS(status), 0, "status=0x%x", status); 154 } 155 156 static void 157 setup_lwp_context(struct lwp_data *d, void (*func)(void *)) 158 { 159 160 memset(d, 0, sizeof(*d)); 161 REQUIRE_LIBC(d->stack_base = mmap(NULL, STACK_SIZE, 162 PROT_READ | PROT_WRITE, MAP_ANON | MAP_STACK | MAP_PRIVATE, 163 -1, 0), 164 MAP_FAILED); 165 _lwp_makecontext(&d->context, func, d, NULL, d->stack_base, 166 STACK_SIZE); 167 d->threadid = 0; 168 d->func = func; 169 } 170 171 static void 172 simple_test_waiter_lwp(void *arg) 173 { 174 struct lwp_data *d = arg; 175 176 d->threadid = _lwp_self(); 177 178 membar_producer(); 179 atomic_inc_uint(&nlwps_running); 180 membar_sync(); 181 182 if (__futex(d->futex_ptr, d->wait_op | d->op_flags, 183 d->block_val, NULL, NULL, 0, d->bitset) == -1) { 184 d->futex_error = errno; 185 membar_sync(); 186 atomic_dec_uint(&nlwps_running); 187 _lwp_exit(); 188 } else { 189 d->futex_error = 0; 190 } 191 192 membar_sync(); 193 atomic_dec_uint(&nlwps_running); 194 195 _lwp_exit(); 196 } 197 198 static bool 199 verify_zero_bs(void) 200 { 201 ssize_t nread; 202 203 if (bs_verify_buffer == NULL) { 204 REQUIRE_LIBC(bs_verify_buffer = malloc(bs_pagesize), NULL); 205 } 206 207 RL(nread = pread(bs_fd, bs_verify_buffer, bs_pagesize, 0)); 208 ATF_REQUIRE_EQ_MSG(nread, bs_pagesize, "nread=%zu bs_pagesize=%lu", 209 nread, bs_pagesize); 210 211 return (memcmp(bs_verify_buffer, bs_source_buffer, bs_pagesize) == 0); 212 } 213 214 static void 215 create_bs(int map_flags) 216 { 217 ssize_t nwrit; 218 219 bs_pagesize = sysconf(_SC_PAGESIZE); 220 ATF_REQUIRE_MSG(bs_pagesize > 0, "bs_pagesize=%ld", bs_pagesize); 221 222 if ((map_flags & (MAP_FILE | MAP_ANON)) == MAP_FILE) { 223 REQUIRE_LIBC(bs_source_buffer = calloc(1, bs_pagesize), NULL); 224 225 RL(bs_fd = open(bs_path, O_RDWR | O_CREAT | O_EXCL, 0644)); 226 RL(nwrit = pwrite(bs_fd, bs_source_buffer, bs_pagesize, 0)); 227 ATF_REQUIRE_EQ_MSG(nwrit, bs_pagesize, 228 "nwrit=%zu bs_pagesize=%lu", nwrit, bs_pagesize); 229 ATF_REQUIRE(verify_zero_bs()); 230 } 231 232 REQUIRE_LIBC(bs_addr = mmap(NULL, bs_pagesize, PROT_READ | PROT_WRITE, 233 map_flags | MAP_HASSEMAPHORE, bs_fd, 0), 234 MAP_FAILED); 235 } 236 237 static void 238 cleanup_bs(void) 239 { 240 241 if (bs_fd != -1) { 242 (void) close(bs_fd); 243 bs_fd = -1; 244 (void) unlink(bs_path); 245 } 246 if (bs_source_buffer != NULL) { 247 free(bs_source_buffer); 248 bs_source_buffer = NULL; 249 } 250 if (bs_verify_buffer != NULL) { 251 free(bs_verify_buffer); 252 bs_verify_buffer = NULL; 253 } 254 if (bs_addr != MAP_FAILED) { 255 munmap(bs_addr, bs_pagesize); 256 bs_addr = MAP_FAILED; 257 } 258 } 259 260 static void 261 do_cleanup(void) 262 { 263 int i; 264 265 for (i = 0; i < NLWPS; i++) { 266 struct lwp_data *d = &lwp_data[i]; 267 if (d->stack_base != NULL && d->stack_base != MAP_FAILED) { 268 (void) munmap(d->stack_base, STACK_SIZE); 269 } 270 } 271 memset(lwp_data, 0, sizeof(lwp_data)); 272 STORE(&futex_word, 0); 273 STORE(&futex_word1, 0); 274 nlwps_running = 0; 275 276 cleanup_bs(); 277 } 278 279 /*****************************************************************************/ 280 281 static void 282 wait_wake_test_waiter_lwp(void *arg) 283 { 284 struct lwp_data *d = arg; 285 286 d->threadid = _lwp_self(); 287 288 STORE(d->futex_ptr, 1); 289 membar_sync(); 290 291 /* This will block because *futex_ptr == 1. */ 292 if (__futex(d->futex_ptr, FUTEX_WAIT | d->op_flags, 293 1, NULL, NULL, 0, 0) == -1) { 294 STORE(d->error_ptr, errno); 295 (*d->exit_func)(); 296 } else { 297 STORE(d->error_ptr, 0); 298 } 299 300 do { 301 membar_sync(); 302 sleep(1); 303 } while (LOAD(d->futex_ptr) != 0); 304 305 STORE(d->futex_ptr, 2); 306 membar_sync(); 307 308 do { 309 membar_sync(); 310 sleep(1); 311 } while (LOAD(d->futex_ptr) != 3); 312 313 /* This will not block because futex_word != 666. */ 314 if (__futex(d->futex_ptr, FUTEX_WAIT | d->op_flags, 315 666, NULL, NULL, 0, 0) == -1) { 316 /* This SHOULD be EAGAIN. */ 317 STORE(d->error_ptr, errno); 318 } 319 320 STORE(d->futex_ptr, 4); 321 membar_sync(); 322 323 (*d->exit_func)(); 324 } 325 326 static void 327 do_futex_wait_wake_test(volatile int *futex_ptr, volatile int *error_ptr, 328 void (*create_func)(struct lwp_data *), 329 void (*exit_func)(void), 330 void (*reap_func)(struct lwp_data *), 331 int flags) 332 { 333 struct lwp_data *wlwp = &lwp_data[WAITER_LWP0]; 334 int tries; 335 int n; 336 337 if (error_ptr == NULL) 338 error_ptr = &wlwp->futex_error; 339 340 if (create_func == NULL) 341 create_func = create_lwp_waiter; 342 if (exit_func == NULL) 343 exit_func = exit_lwp_waiter; 344 if (reap_func == NULL) 345 reap_func = reap_lwp_waiter; 346 347 setup_lwp_context(wlwp, wait_wake_test_waiter_lwp); 348 349 DPRINTF(("futex_basic_wait_wake: testing with flags 0x%x\n", flags)); 350 wlwp->op_flags = flags; 351 wlwp->error_ptr = error_ptr; 352 STORE(error_ptr, -1); 353 wlwp->futex_ptr = futex_ptr; 354 STORE(futex_ptr, 0); 355 wlwp->exit_func = exit_func; 356 membar_sync(); 357 358 DPRINTF(("futex_basic_wait_wake: creating watier LWP\n")); 359 (*create_func)(wlwp); 360 361 DPRINTF(("futex_basic_wait_wake: waiting for LWP %d to enter futex\n", 362 wlwp->lwpid)); 363 for (tries = 0; tries < 5; tries++) { 364 membar_sync(); 365 if (LOAD(futex_ptr) == 1) 366 break; 367 sleep(1); 368 } 369 membar_sync(); 370 ATF_REQUIRE_EQ_MSG((n = LOAD(futex_ptr)), 1, "LOAD(futex_ptr)=%d", n); 371 372 /* 373 * If the LWP is blocked in the futex, it will not have yet 374 * modified *error_ptr. 375 */ 376 DPRINTF(("futex_basic_wait_wake: checking for successful wait (%d)\n", 377 LOAD(error_ptr))); 378 for (tries = 0; tries < 5; tries++) { 379 membar_sync(); 380 if (LOAD(error_ptr) == -1) 381 break; 382 sleep(1); 383 } 384 membar_sync(); 385 ATF_REQUIRE_EQ_MSG((n = LOAD(error_ptr)), -1, "error=%d", n); 386 387 /* Make sure invalid #wakes in rejected. */ 388 ATF_REQUIRE_ERRNO(EINVAL, 389 __futex(futex_ptr, FUTEX_WAKE | flags, 390 -1, NULL, NULL, 0, 0) == -1); 391 392 DPRINTF(("futex_basic_wait_wake: waking 1 waiter\n")); 393 RL(n = __futex(futex_ptr, FUTEX_WAKE | flags, 1, NULL, NULL, 0, 0)); 394 ATF_REQUIRE_EQ_MSG(n, 1, "n=%d wakeups", n); 395 396 DPRINTF(("futex_basic_wait_wake: checking for successful wake (%d)\n", 397 LOAD(error_ptr))); 398 for (tries = 0; tries < 5; tries++) { 399 membar_sync(); 400 if (LOAD(error_ptr) == 0) 401 break; 402 sleep(1); 403 } 404 membar_sync(); 405 ATF_REQUIRE_EQ_MSG((n = LOAD(error_ptr)), 0, "error=%d", n); 406 407 STORE(futex_ptr, 0); 408 membar_sync(); 409 410 DPRINTF(("futex_basic_wait_wake: waiting for LWP to advance (2)\n")); 411 for (tries = 0; tries < 5; tries++) { 412 membar_sync(); 413 if (LOAD(futex_ptr) == 2) 414 break; 415 sleep(1); 416 } 417 membar_sync(); 418 ATF_REQUIRE_EQ_MSG((n = LOAD(futex_ptr)), 2, "LOAD(futex_ptr)=%d", n); 419 420 STORE(futex_ptr, 3); 421 membar_sync(); 422 423 DPRINTF(("futex_basic_wait_wake: waiting for LWP to advance (4)\n")); 424 for (tries = 0; tries < 5; tries++) { 425 membar_sync(); 426 if (LOAD(futex_ptr) == 4) 427 break; 428 sleep(1); 429 } 430 membar_sync(); 431 ATF_REQUIRE_EQ_MSG((n = LOAD(futex_ptr)), 4, "error=%d", n); 432 433 DPRINTF(("futex_basic_wait_wake: checking for expected EGAIN\n")); 434 ATF_REQUIRE_EQ_MSG((n = LOAD(error_ptr)), EAGAIN, "error=%d", n); 435 436 DPRINTF(("futex_basic_wait_wake: reaping LWP %d\n", wlwp->lwpid)); 437 (*reap_func)(wlwp); 438 } 439 440 ATF_TC_WITH_CLEANUP(futex_basic_wait_wake_private); 441 ATF_TC_HEAD(futex_basic_wait_wake_private, tc) 442 { 443 atf_tc_set_md_var(tc, "descr", 444 "tests basic futex WAIT + WAKE operations (PRIVATE)"); 445 } 446 ATF_TC_BODY(futex_basic_wait_wake_private, tc) 447 { 448 do_futex_wait_wake_test(&futex_word, NULL, 449 NULL, NULL, NULL, 450 FUTEX_PRIVATE_FLAG); 451 } 452 ATF_TC_CLEANUP(futex_basic_wait_wake_private, tc) 453 { 454 do_cleanup(); 455 } 456 457 ATF_TC_WITH_CLEANUP(futex_basic_wait_wake_shared); 458 ATF_TC_HEAD(futex_basic_wait_wake_shared, tc) 459 { 460 atf_tc_set_md_var(tc, "descr", 461 "tests basic futex WAIT + WAKE operations (SHARED)"); 462 } 463 ATF_TC_BODY(futex_basic_wait_wake_shared, tc) 464 { 465 do_futex_wait_wake_test(&futex_word, NULL, 466 NULL, NULL, NULL, 467 0); 468 } 469 ATF_TC_CLEANUP(futex_basic_wait_wake_shared, tc) 470 { 471 do_cleanup(); 472 } 473 474 ATF_TC_WITH_CLEANUP(futex_wait_wake_anon_bs_private); 475 ATF_TC_HEAD(futex_wait_wake_anon_bs_private, tc) 476 { 477 atf_tc_set_md_var(tc, "descr", 478 "tests futex WAIT + WAKE operations (MAP_ANON + PRIVATE)"); 479 } 480 ATF_TC_BODY(futex_wait_wake_anon_bs_private, tc) 481 { 482 create_bs(MAP_ANON | MAP_PRIVATE); 483 do_futex_wait_wake_test(&bs_addr[0], NULL, 484 NULL, NULL, NULL, 485 FUTEX_PRIVATE_FLAG); 486 } 487 ATF_TC_CLEANUP(futex_wait_wake_anon_bs_private, tc) 488 { 489 do_cleanup(); 490 } 491 492 ATF_TC_WITH_CLEANUP(futex_wait_wake_anon_bs_shared); 493 ATF_TC_HEAD(futex_wait_wake_anon_bs_shared, tc) 494 { 495 atf_tc_set_md_var(tc, "descr", 496 "tests futex WAIT + WAKE operations (MAP_ANON + SHARED)"); 497 } 498 ATF_TC_BODY(futex_wait_wake_anon_bs_shared, tc) 499 { 500 create_bs(MAP_ANON | MAP_PRIVATE); 501 do_futex_wait_wake_test(&bs_addr[0], NULL, 502 NULL, NULL, NULL, 503 0); 504 } 505 ATF_TC_CLEANUP(futex_wait_wake_anon_bs_shared, tc) 506 { 507 do_cleanup(); 508 } 509 510 ATF_TC_WITH_CLEANUP(futex_wait_wake_file_bs_private); 511 ATF_TC_HEAD(futex_wait_wake_file_bs_private, tc) 512 { 513 atf_tc_set_md_var(tc, "descr", 514 "tests futex WAIT + WAKE operations (MAP_FILE + PRIVATE)"); 515 } 516 ATF_TC_BODY(futex_wait_wake_file_bs_private, tc) 517 { 518 /* 519 * This combination (non-COW mapped file + PRIVATE futex) 520 * doesn't really make sense, but we should make sure it 521 * works as expected. 522 */ 523 create_bs(MAP_FILE | MAP_SHARED); 524 do_futex_wait_wake_test(&bs_addr[0], NULL, 525 NULL, NULL, NULL, 526 FUTEX_PRIVATE_FLAG); 527 ATF_REQUIRE(!verify_zero_bs()); 528 } 529 ATF_TC_CLEANUP(futex_wait_wake_file_bs_private, tc) 530 { 531 do_cleanup(); 532 } 533 534 ATF_TC_WITH_CLEANUP(futex_wait_wake_file_bs_cow_private); 535 ATF_TC_HEAD(futex_wait_wake_file_bs_cow_private, tc) 536 { 537 atf_tc_set_md_var(tc, "descr", 538 "tests futex WAIT + WAKE operations (MAP_FILE COW + PRIVATE)"); 539 } 540 ATF_TC_BODY(futex_wait_wake_file_bs_cow_private, tc) 541 { 542 create_bs(MAP_FILE | MAP_PRIVATE); 543 do_futex_wait_wake_test(&bs_addr[0], NULL, 544 NULL, NULL, NULL, 545 FUTEX_PRIVATE_FLAG); 546 ATF_REQUIRE(verify_zero_bs()); 547 } 548 ATF_TC_CLEANUP(futex_wait_wake_file_bs_cow_private, tc) 549 { 550 do_cleanup(); 551 } 552 553 ATF_TC_WITH_CLEANUP(futex_wait_wake_file_bs_shared); 554 ATF_TC_HEAD(futex_wait_wake_file_bs_shared, tc) 555 { 556 atf_tc_set_md_var(tc, "descr", 557 "tests futex WAIT + WAKE operations (MAP_FILE + SHARED)"); 558 } 559 ATF_TC_BODY(futex_wait_wake_file_bs_shared, tc) 560 { 561 create_bs(MAP_FILE | MAP_SHARED); 562 do_futex_wait_wake_test(&bs_addr[0], NULL, 563 NULL, NULL, NULL, 564 0); 565 ATF_REQUIRE(!verify_zero_bs()); 566 } 567 ATF_TC_CLEANUP(futex_wait_wake_file_bs_shared, tc) 568 { 569 do_cleanup(); 570 } 571 572 ATF_TC_WITH_CLEANUP(futex_wait_wake_file_bs_cow_shared); 573 ATF_TC_HEAD(futex_wait_wake_file_bs_cow_shared, tc) 574 { 575 atf_tc_set_md_var(tc, "descr", 576 "tests futex WAIT + WAKE operations (MAP_FILE COW + SHARED)"); 577 } 578 ATF_TC_BODY(futex_wait_wake_file_bs_cow_shared, tc) 579 { 580 /* 581 * This combination (COW mapped file + SHARED futex) 582 * doesn't really make sense, but we should make sure it 583 * works as expected. 584 */ 585 create_bs(MAP_FILE | MAP_PRIVATE); 586 do_futex_wait_wake_test(&bs_addr[0], NULL, 587 NULL, NULL, NULL, 588 0); 589 ATF_REQUIRE(verify_zero_bs()); 590 } 591 ATF_TC_CLEANUP(futex_wait_wake_file_bs_cow_shared, tc) 592 { 593 do_cleanup(); 594 } 595 596 ATF_TC_WITH_CLEANUP(futex_wait_wake_anon_bs_shared_proc); 597 ATF_TC_HEAD(futex_wait_wake_anon_bs_shared_proc, tc) 598 { 599 atf_tc_set_md_var(tc, "descr", 600 "tests multiproc futex WAIT + WAKE operations (MAP_ANON + SHARED)"); 601 } 602 ATF_TC_BODY(futex_wait_wake_anon_bs_shared_proc, tc) 603 { 604 create_bs(MAP_ANON | MAP_SHARED); 605 do_futex_wait_wake_test(&bs_addr[0], &bs_addr[1], 606 create_proc_waiter, 607 exit_proc_waiter, 608 reap_proc_waiter, 609 0); 610 } 611 ATF_TC_CLEANUP(futex_wait_wake_anon_bs_shared_proc, tc) 612 { 613 do_cleanup(); 614 } 615 616 ATF_TC_WITH_CLEANUP(futex_wait_wake_file_bs_shared_proc); 617 ATF_TC_HEAD(futex_wait_wake_file_bs_shared_proc, tc) 618 { 619 atf_tc_set_md_var(tc, "descr", 620 "tests multiproc futex WAIT + WAKE operations (MAP_ANON + SHARED)"); 621 } 622 ATF_TC_BODY(futex_wait_wake_file_bs_shared_proc, tc) 623 { 624 create_bs(MAP_FILE | MAP_SHARED); 625 do_futex_wait_wake_test(&bs_addr[0], &bs_addr[1], 626 create_proc_waiter, 627 exit_proc_waiter, 628 reap_proc_waiter, 629 0); 630 } 631 ATF_TC_CLEANUP(futex_wait_wake_file_bs_shared_proc, tc) 632 { 633 do_cleanup(); 634 } 635 636 /*****************************************************************************/ 637 638 ATF_TC(futex_wait_pointless_bitset); 639 ATF_TC_HEAD(futex_wait_pointless_bitset, tc) 640 { 641 atf_tc_set_md_var(tc, "descr", 642 "tests basic futex WAIT + WAKE operations (SHARED)"); 643 } 644 ATF_TC_BODY(futex_wait_pointless_bitset, tc) 645 { 646 647 futex_word = 1; 648 ATF_REQUIRE_ERRNO(EINVAL, 649 __futex(&futex_word, FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG, 650 1, NULL, NULL, 0, 0) == -1); 651 } 652 653 static void 654 do_futex_wait_wake_bitset_test(int flags) 655 { 656 struct lwp_data *wlwp0 = &lwp_data[WAITER_LWP0]; 657 struct lwp_data *wlwp1 = &lwp_data[WAITER_LWP1]; 658 int i, tries, n; 659 660 for (i = WAITER_LWP0; i <= WAITER_LWP1; i++) { 661 setup_lwp_context(&lwp_data[i], simple_test_waiter_lwp); 662 lwp_data[i].op_flags = flags; 663 lwp_data[i].futex_error = -1; 664 lwp_data[i].bitset = __BIT(i); 665 lwp_data[i].wait_op = FUTEX_WAIT_BITSET; 666 lwp_data[i].futex_ptr = &futex_word; 667 lwp_data[i].block_val = 1; 668 } 669 670 STORE(&futex_word, 1); 671 membar_sync(); 672 673 RL(_lwp_create(&wlwp0->context, 0, &wlwp0->lwpid)); 674 RL(_lwp_create(&wlwp1->context, 0, &wlwp1->lwpid)); 675 676 for (tries = 0; tries < 5; tries++) { 677 membar_sync(); 678 if (nlwps_running == 2) 679 break; 680 sleep(1); 681 } 682 membar_sync(); 683 ATF_REQUIRE_EQ_MSG(nlwps_running, 2, 684 "waiters failed to start, nlwps_running=%u", nlwps_running); 685 686 /* Ensure they're blocked. */ 687 ATF_REQUIRE_EQ_MSG(wlwp0->futex_error, -1, "wlwp0->futex_error=%d", 688 wlwp0->futex_error); 689 ATF_REQUIRE_EQ_MSG(wlwp1->futex_error, -1, "wlwp1->futex_error=%d", 690 wlwp1->futex_error); 691 692 /* Make sure invalid #wakes in rejected. */ 693 ATF_REQUIRE_ERRNO(EINVAL, 694 __futex(&futex_word, FUTEX_WAKE_BITSET | flags, 695 -1, NULL, NULL, 0, 0) == -1); 696 697 /* This should result in no wakeups because no bits are set. */ 698 RL(n = __futex(&futex_word, FUTEX_WAKE_BITSET | flags, 699 INT_MAX, NULL, NULL, 0, 0)); 700 ATF_REQUIRE_EQ_MSG(n, 0, "n=%d wakeups", n); 701 702 /* This should result in no wakeups because the wrongs bits are set. */ 703 RL(n = __futex(&futex_word, FUTEX_WAKE_BITSET | flags, 704 INT_MAX, NULL, NULL, 0, 705 ~(wlwp0->bitset | wlwp1->bitset))); 706 ATF_REQUIRE_EQ_MSG(n, 0, "n=%d wakeups", n); 707 708 /* Trust, but verify. */ 709 sleep(1); 710 for (tries = 0; tries < 5; tries++) { 711 membar_sync(); 712 if (nlwps_running == 2) 713 break; 714 sleep(1); 715 } 716 membar_sync(); 717 ATF_REQUIRE_EQ_MSG(nlwps_running, 2, 718 "waiters exited unexpectedly, nlwps_running=%u", nlwps_running); 719 720 /* Wake up the first LWP. */ 721 RL(n = __futex(&futex_word, FUTEX_WAKE_BITSET | flags, 722 INT_MAX, NULL, NULL, 0, wlwp0->bitset)); 723 ATF_REQUIRE_EQ_MSG(n, 1, "n=%d wakeups", n); 724 sleep(1); 725 for (tries = 0; tries < 5; tries++) { 726 membar_sync(); 727 if (nlwps_running == 1) 728 break; 729 sleep(1); 730 } 731 membar_sync(); 732 ATF_REQUIRE_EQ_MSG(nlwps_running, 1, "nlwps_running=%u", 733 nlwps_running); 734 ATF_REQUIRE_EQ_MSG(wlwp0->futex_error, 0, "wlwp0->futex_error=%d", 735 wlwp0->futex_error); 736 RL(_lwp_wait(wlwp0->lwpid, NULL)); 737 738 /* Wake up the second LWP. */ 739 RL(n = __futex(&futex_word, FUTEX_WAKE_BITSET | flags, 740 INT_MAX, NULL, NULL, 0, wlwp1->bitset)); 741 ATF_REQUIRE_EQ_MSG(n, 1, "n=%d wakeups", n); 742 sleep(1); 743 for (tries = 0; tries < 5; tries++) { 744 membar_sync(); 745 if (nlwps_running == 0) 746 break; 747 sleep(1); 748 } 749 membar_sync(); 750 ATF_REQUIRE_EQ_MSG(nlwps_running, 0, "nlwps_running=%u", 751 nlwps_running); 752 ATF_REQUIRE_EQ_MSG(wlwp1->futex_error, 0, "wlwp1->futex_error=%d", 753 wlwp1->futex_error); 754 RL(_lwp_wait(wlwp1->lwpid, NULL)); 755 } 756 757 ATF_TC_WITH_CLEANUP(futex_wait_wake_bitset); 758 ATF_TC_HEAD(futex_wait_wake_bitset, tc) 759 { 760 atf_tc_set_md_var(tc, "descr", 761 "tests futex WAIT_BITSET + WAKE_BITSET operations"); 762 } 763 ATF_TC_BODY(futex_wait_wake_bitset, tc) 764 { 765 do_futex_wait_wake_bitset_test(FUTEX_PRIVATE_FLAG); 766 } 767 ATF_TC_CLEANUP(futex_wait_wake_bitset, tc) 768 { 769 do_cleanup(); 770 } 771 772 /*****************************************************************************/ 773 774 static void 775 do_futex_requeue_test(int flags, int op) 776 { 777 struct lwp_data *wlwp0 = &lwp_data[WAITER_LWP0]; 778 struct lwp_data *wlwp1 = &lwp_data[WAITER_LWP1]; 779 struct lwp_data *wlwp2 = &lwp_data[WAITER_LWP2]; 780 struct lwp_data *wlwp3 = &lwp_data[WAITER_LWP3]; 781 const int good_val3 = (op == FUTEX_CMP_REQUEUE) ? 1 : 0; 782 const int bad_val3 = (op == FUTEX_CMP_REQUEUE) ? 666 : 0; 783 int i, tries, n; 784 785 for (i = WAITER_LWP0; i <= WAITER_LWP3; i++) { 786 setup_lwp_context(&lwp_data[i], simple_test_waiter_lwp); 787 lwp_data[i].op_flags = flags; 788 lwp_data[i].futex_error = -1; 789 lwp_data[i].futex_ptr = &futex_word; 790 lwp_data[i].block_val = 1; 791 lwp_data[i].bitset = 0; 792 lwp_data[i].wait_op = FUTEX_WAIT; 793 } 794 795 STORE(&futex_word, 1); 796 STORE(&futex_word1, 1); 797 membar_sync(); 798 799 RL(_lwp_create(&wlwp0->context, 0, &wlwp0->lwpid)); 800 RL(_lwp_create(&wlwp1->context, 0, &wlwp1->lwpid)); 801 RL(_lwp_create(&wlwp2->context, 0, &wlwp2->lwpid)); 802 RL(_lwp_create(&wlwp3->context, 0, &wlwp3->lwpid)); 803 804 for (tries = 0; tries < 5; tries++) { 805 membar_sync(); 806 if (nlwps_running == 4) 807 break; 808 sleep(1); 809 } 810 membar_sync(); 811 ATF_REQUIRE_EQ_MSG(nlwps_running, 4, 812 "waiters failed to start, nlwps_running=%u", nlwps_running); 813 814 /* Ensure they're blocked. */ 815 ATF_REQUIRE_EQ_MSG(wlwp0->futex_error, -1, "wlwp0->futex_error=%d", 816 wlwp0->futex_error); 817 ATF_REQUIRE_EQ_MSG(wlwp1->futex_error, -1, "wlwp1->futex_error=%d", 818 wlwp1->futex_error); 819 ATF_REQUIRE_EQ_MSG(wlwp2->futex_error, -1, "wlwp2->futex_error=%d", 820 wlwp2->futex_error); 821 ATF_REQUIRE_EQ_MSG(wlwp3->futex_error, -1, "wlwp3->futex_error=%d", 822 wlwp3->futex_error); 823 824 /* Make sure invalid #wakes and #requeues are rejected. */ 825 ATF_REQUIRE_ERRNO(EINVAL, 826 __futex(&futex_word, op | flags, 827 -1, NULL, &futex_word1, INT_MAX, bad_val3) == -1); 828 829 ATF_REQUIRE_ERRNO(EINVAL, 830 __futex(&futex_word, op | flags, 831 0, NULL, &futex_word1, -1, bad_val3) == -1); 832 833 /* 834 * FUTEX 0: 4 LWPs 835 * FUTEX 1: 0 LWPs 836 */ 837 838 if (op == FUTEX_CMP_REQUEUE) { 839 /* This should fail because the futex_word value is 1. */ 840 ATF_REQUIRE_ERRNO(EAGAIN, 841 __futex(&futex_word, op | flags, 842 0, NULL, &futex_word1, INT_MAX, bad_val3) == -1); 843 } 844 845 /* 846 * FUTEX 0: 4 LWPs 847 * FUTEX 1: 0 LWPs 848 */ 849 850 /* Move all waiters from 0 to 1. */ 851 RL(n = __futex(&futex_word, op | flags, 0, NULL, &futex_word1, 852 INT_MAX, good_val3)); 853 ATF_CHECK_EQ_MSG(n, 4, "n=%d woken or requeued", n); 854 855 /* 856 * FUTEX 0: 0 LWPs 857 * FUTEX 1: 4 LWPs 858 */ 859 860 if (op == FUTEX_CMP_REQUEUE) { 861 /* This should fail because the futex_word1 value is 1. */ 862 ATF_REQUIRE_ERRNO(EAGAIN, 863 __futex(&futex_word1, op | flags, 864 1, NULL, &futex_word, 1, bad_val3) == -1); 865 } 866 867 /* 868 * FUTEX 0: 0 LWPs 869 * FUTEX 1: 4 LWPs 870 */ 871 872 /* Wake one waiter on 1, move one waiter to 0. */ 873 RL(n = __futex(&futex_word1, op | flags, 1, NULL, &futex_word, 874 1, good_val3)); 875 ATF_CHECK_EQ_MSG(n, 2, "n=%d woken or requeued", n); 876 877 /* 878 * FUTEX 0: 1 LWP 879 * FUTEX 1: 2 LWPs 880 */ 881 882 /* Wake all waiters on 0 (should be 1). */ 883 RL(n = __futex(&futex_word, FUTEX_WAKE | flags, INT_MAX, NULL, NULL, 884 0, 0)); 885 ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n); 886 887 /* Wake all waiters on 1 (should be 2). */ 888 RL(n = __futex(&futex_word1, FUTEX_WAKE | flags, INT_MAX, NULL, NULL, 889 0, 0)); 890 ATF_CHECK_EQ_MSG(n, 2, "n=%d woken", n); 891 892 /* Trust, but verify. */ 893 sleep(1); 894 for (tries = 0; tries < 5; tries++) { 895 membar_sync(); 896 if (nlwps_running == 0) 897 break; 898 sleep(1); 899 } 900 membar_sync(); 901 ATF_REQUIRE_EQ_MSG(nlwps_running, 0, 902 "waiters failed to exit, nlwps_running=%u", nlwps_running); 903 904 RL(_lwp_wait(wlwp0->lwpid, NULL)); 905 RL(_lwp_wait(wlwp1->lwpid, NULL)); 906 RL(_lwp_wait(wlwp2->lwpid, NULL)); 907 RL(_lwp_wait(wlwp3->lwpid, NULL)); 908 } 909 910 ATF_TC_WITH_CLEANUP(futex_requeue); 911 ATF_TC_HEAD(futex_requeue, tc) 912 { 913 atf_tc_set_md_var(tc, "descr", 914 "tests futex REQUEUE operations"); 915 } 916 ATF_TC_BODY(futex_requeue, tc) 917 { 918 do_futex_requeue_test(FUTEX_PRIVATE_FLAG, FUTEX_REQUEUE); 919 } 920 ATF_TC_CLEANUP(futex_requeue, tc) 921 { 922 do_cleanup(); 923 } 924 925 ATF_TC_WITH_CLEANUP(futex_cmp_requeue); 926 ATF_TC_HEAD(futex_cmp_requeue, tc) 927 { 928 atf_tc_set_md_var(tc, "descr", 929 "tests futex CMP_REQUEUE operations"); 930 } 931 ATF_TC_BODY(futex_cmp_requeue, tc) 932 { 933 do_futex_requeue_test(FUTEX_PRIVATE_FLAG, FUTEX_CMP_REQUEUE); 934 } 935 ATF_TC_CLEANUP(futex_cmp_requeue, tc) 936 { 937 do_cleanup(); 938 } 939 940 ATF_TC(futex_cmp_requeue_trivial); 941 ATF_TC_HEAD(futex_cmp_requeue_trivial, tc) 942 { 943 atf_tc_set_md_var(tc, "descr", 944 "tests trivial cases of futex CMP_REQUEUE operations"); 945 } 946 ATF_TC_BODY(futex_cmp_requeue_trivial, tc) 947 { 948 int nwoken; 949 950 futex_word = 123; 951 futex_word1 = 456; /* should be ignored */ 952 ATF_CHECK_ERRNO(EAGAIN, __futex(&futex_word, FUTEX_CMP_REQUEUE, 953 /*nwake*/1, NULL, &futex_word1, /*nrequeue*/1, 0) == -1); 954 ATF_CHECK_ERRNO(EAGAIN, __futex(&futex_word, FUTEX_CMP_REQUEUE, 955 /*nwake*/1, NULL, &futex_word1, /*nrequeue*/1, 122) == -1); 956 nwoken = __futex(&futex_word, FUTEX_CMP_REQUEUE, 957 /*nwake*/1, NULL, &futex_word1, /*nrequeue*/1, 123); 958 ATF_CHECK_MSG(nwoken != -1, "errno=%d (%s)", errno, strerror(errno)); 959 ATF_CHECK_EQ_MSG(nwoken, 0, "nwoken=%d", nwoken); 960 ATF_CHECK_EQ_MSG(futex_word, 123, "futex_word=%d", futex_word); 961 ATF_CHECK_EQ_MSG(futex_word1, 456, "futex_word1=%d", futex_word1); 962 } 963 964 /*****************************************************************************/ 965 966 static void 967 do_futex_wake_op_op_test(int flags) 968 { 969 int op, n; 970 971 futex_word = 0; 972 futex_word1 = 0; 973 974 /* 975 * The op= operations should work even if there are no waiters. 976 */ 977 978 /* 979 * Because these operations use both futex addresses, exercise 980 * rejecting unaligned futex addresses here. 981 */ 982 op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_EQ, 0); 983 ATF_CHECK_ERRNO(EINVAL, 984 __futex((int *)1, FUTEX_WAKE_OP | flags, 985 0, NULL, &futex_word1, 0, op) == -1); 986 ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1); 987 988 ATF_CHECK_ERRNO(EINVAL, 989 __futex(&futex_word, FUTEX_WAKE_OP | flags, 990 0, NULL, (int *)1, 0, op) == -1); 991 ATF_CHECK_EQ_MSG(futex_word, 0, "futex_word=%d", futex_word); 992 993 /* Check unmapped uaddr2 handling, too. */ 994 ATF_CHECK_ERRNO(EFAULT, 995 __futex(&futex_word, FUTEX_WAKE_OP | flags, 996 0, NULL, NULL, 0, op) == -1); 997 ATF_CHECK_EQ_MSG(futex_word, 0, "futex_word=%d", futex_word); 998 999 op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_EQ, 0); 1000 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1001 0, NULL, &futex_word1, 0, op)); 1002 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); 1003 ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1); 1004 1005 op = FUTEX_OP(FUTEX_OP_ADD, 1, FUTEX_OP_CMP_EQ, 0); 1006 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1007 0, NULL, &futex_word1, 0, op)); 1008 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); 1009 ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); 1010 1011 op = FUTEX_OP(FUTEX_OP_OR, 2, FUTEX_OP_CMP_EQ, 0); 1012 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1013 0, NULL, &futex_word1, 0, op)); 1014 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); 1015 ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); 1016 1017 /* This should fail because of invalid shift value 32. */ 1018 op = FUTEX_OP(FUTEX_OP_OR | FUTEX_OP_OPARG_SHIFT, 32, 1019 FUTEX_OP_CMP_EQ, 0); 1020 ATF_CHECK_ERRNO(EINVAL, 1021 __futex(&futex_word, FUTEX_WAKE_OP | flags, 1022 0, NULL, &futex_word1, 0, op) == -1); 1023 ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); 1024 1025 op = FUTEX_OP(FUTEX_OP_OR | FUTEX_OP_OPARG_SHIFT, 31, 1026 FUTEX_OP_CMP_EQ, 0); 1027 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1028 0, NULL, &futex_word1, 0, op)); 1029 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); 1030 ATF_CHECK_EQ_MSG(futex_word1, (int)0x80000002, 1031 "futex_word1=0x%x", futex_word1); 1032 1033 op = FUTEX_OP(FUTEX_OP_ANDN | FUTEX_OP_OPARG_SHIFT, 31, 1034 FUTEX_OP_CMP_EQ, 0); 1035 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1036 0, NULL, &futex_word1, 0, op)); 1037 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); 1038 ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); 1039 1040 op = FUTEX_OP(FUTEX_OP_XOR, 2, FUTEX_OP_CMP_EQ, 0); 1041 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1042 0, NULL, &futex_word1, 0, op)); 1043 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); 1044 ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1); 1045 1046 /* 1047 * Verify oparg is sign-extended. 1048 */ 1049 futex_word1 = 0; 1050 op = FUTEX_OP(FUTEX_OP_SET, 0xfff, FUTEX_OP_CMP_EQ, 0); 1051 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1052 0, NULL, &futex_word1, 0, op)); 1053 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); 1054 ATF_CHECK_EQ_MSG(futex_word1, -1, "futex_word1=%d", futex_word1); 1055 1056 futex_word1 = 0; 1057 op = FUTEX_OP(FUTEX_OP_SET, -1, FUTEX_OP_CMP_EQ, 0); 1058 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1059 0, NULL, &futex_word1, 0, op)); 1060 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); 1061 ATF_CHECK_EQ_MSG(futex_word1, -1, "futex_word1=%d", futex_word1); 1062 } 1063 1064 ATF_TC_WITH_CLEANUP(futex_wake_op_op); 1065 ATF_TC_HEAD(futex_wake_op_op, tc) 1066 { 1067 atf_tc_set_md_var(tc, "descr", 1068 "tests futex WAKE_OP OP operations"); 1069 } 1070 ATF_TC_BODY(futex_wake_op_op, tc) 1071 { 1072 do_futex_wake_op_op_test(FUTEX_PRIVATE_FLAG); 1073 } 1074 ATF_TC_CLEANUP(futex_wake_op_op, tc) 1075 { 1076 do_cleanup(); 1077 } 1078 1079 static void 1080 create_wake_op_test_lwps(int flags) 1081 { 1082 int i; 1083 1084 futex_word1 = 0; 1085 membar_sync(); 1086 1087 for (i = WAITER_LWP0; i <= WAITER_LWP5; i++) { 1088 setup_lwp_context(&lwp_data[i], simple_test_waiter_lwp); 1089 lwp_data[i].op_flags = flags; 1090 lwp_data[i].futex_error = -1; 1091 lwp_data[i].futex_ptr = &futex_word1; 1092 lwp_data[i].block_val = 0; 1093 lwp_data[i].bitset = 0; 1094 lwp_data[i].wait_op = FUTEX_WAIT; 1095 RL(_lwp_create(&lwp_data[i].context, 0, &lwp_data[i].lwpid)); 1096 } 1097 1098 for (i = 0; i < 5; i++) { 1099 membar_sync(); 1100 if (nlwps_running == 6) 1101 break; 1102 sleep(1); 1103 } 1104 membar_sync(); 1105 ATF_REQUIRE_EQ_MSG(nlwps_running, 6, 1106 "waiters failed to start, nlwps_running=%u", nlwps_running); 1107 1108 /* Ensure they're blocked. */ 1109 for (i = WAITER_LWP0; i <= WAITER_LWP5; i++) { 1110 ATF_REQUIRE_EQ_MSG(lwp_data[i].futex_error, -1, 1111 "i=%d lwp_data[i].futex_error=%d", 1112 i, lwp_data[i].futex_error); 1113 } 1114 } 1115 1116 static void 1117 reap_wake_op_test_lwps(void) 1118 { 1119 int i; 1120 1121 for (i = WAITER_LWP0; i <= WAITER_LWP5; i++) { 1122 RL(_lwp_wait(lwp_data[i].lwpid, NULL)); 1123 } 1124 } 1125 1126 static void 1127 do_futex_wake_op_cmp_test(int flags) 1128 { 1129 int tries, op, n; 1130 1131 futex_word = 0; 1132 membar_sync(); 1133 1134 /* 1135 * Verify and negative and positive for each individual 1136 * compare. 1137 */ 1138 1139 create_wake_op_test_lwps(flags); 1140 1141 /* #LWPs = 6 */ 1142 futex_word1 = 0xfff; 1143 op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, 0xfff); 1144 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1145 0, NULL, &futex_word1, 1, op)); 1146 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); 1147 ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1); 1148 1149 futex_word1 = 0xfff; 1150 op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, -1); 1151 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1152 0, NULL, &futex_word1, 1, op)); 1153 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); 1154 ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1); 1155 1156 op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, 1); 1157 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1158 0, NULL, &futex_word1, 1, op)); 1159 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); 1160 ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1); 1161 1162 futex_word1 = -1; 1163 op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_EQ, 0xfff); 1164 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1165 0, NULL, &futex_word1, 1, op)); 1166 ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n); 1167 ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1); 1168 1169 /* #LWPs = 5 */ 1170 op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_NE, 1); 1171 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1172 0, NULL, &futex_word1, 1, op)); 1173 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); 1174 ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1); 1175 1176 op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_NE, 2); 1177 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1178 0, NULL, &futex_word1, 1, op)); 1179 ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n); 1180 ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); 1181 1182 /* #LWPs = 4 */ 1183 op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_LT, 2); 1184 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1185 0, NULL, &futex_word1, 1, op)); 1186 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); 1187 ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); 1188 1189 op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_LT, 3); 1190 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1191 0, NULL, &futex_word1, 1, op)); 1192 ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n); 1193 ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); 1194 1195 /* #LWPs = 3 */ 1196 op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_LE, 1); 1197 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1198 0, NULL, &futex_word1, 1, op)); 1199 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); 1200 ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1); 1201 1202 op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_LE, 1); 1203 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1204 0, NULL, &futex_word1, 1, op)); 1205 ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n); 1206 ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1); 1207 1208 /* #LWPs = 2 */ 1209 op = FUTEX_OP(FUTEX_OP_SET, 3, FUTEX_OP_CMP_GT, 3); 1210 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1211 0, NULL, &futex_word1, 1, op)); 1212 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); 1213 ATF_CHECK_EQ_MSG(futex_word1, 3, "futex_word1=%d", futex_word1); 1214 1215 op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_GT, 2); 1216 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1217 0, NULL, &futex_word1, 1, op)); 1218 ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n); 1219 ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); 1220 1221 /* #LWPs = 1 */ 1222 op = FUTEX_OP(FUTEX_OP_SET, 3, FUTEX_OP_CMP_GE, 4); 1223 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1224 0, NULL, &futex_word1, 1, op)); 1225 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); 1226 ATF_CHECK_EQ_MSG(futex_word1, 3, "futex_word1=%d", futex_word1); 1227 1228 op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_GE, 3); 1229 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, 1230 0, NULL, &futex_word1, 1, op)); 1231 ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n); 1232 ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); 1233 1234 /* #LWPs = 0 */ 1235 1236 /* Trust, but verify. */ 1237 sleep(1); 1238 for (tries = 0; tries < 5; tries++) { 1239 membar_sync(); 1240 if (nlwps_running == 0) 1241 break; 1242 sleep(1); 1243 } 1244 membar_sync(); 1245 ATF_REQUIRE_EQ_MSG(nlwps_running, 0, 1246 "waiters failed to exit, nlwps_running=%u", nlwps_running); 1247 1248 reap_wake_op_test_lwps(); 1249 1250 /* 1251 * Verify wakes on uaddr work even if the uaddr2 comparison 1252 * fails. 1253 */ 1254 1255 create_wake_op_test_lwps(flags); 1256 1257 /* #LWPs = 6 */ 1258 ATF_CHECK_EQ_MSG(futex_word, 0, "futex_word=%d", futex_word); 1259 op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, 666); 1260 RL(n = __futex(&futex_word1, FUTEX_WAKE_OP | flags, 1261 INT_MAX, NULL, &futex_word, 0, op)); 1262 ATF_CHECK_EQ_MSG(n, 6, "n=%d woken", n); 1263 ATF_CHECK_EQ_MSG(futex_word, 0, "futex_word=%d", futex_word); 1264 1265 /* #LWPs = 0 */ 1266 1267 /* Trust, but verify. */ 1268 sleep(1); 1269 for (tries = 0; tries < 5; tries++) { 1270 membar_sync(); 1271 if (nlwps_running == 0) 1272 break; 1273 sleep(1); 1274 } 1275 membar_sync(); 1276 ATF_REQUIRE_EQ_MSG(nlwps_running, 0, 1277 "waiters failed to exit, nlwps_running=%u", nlwps_running); 1278 1279 reap_wake_op_test_lwps(); 1280 } 1281 1282 ATF_TC_WITH_CLEANUP(futex_wake_op_cmp); 1283 ATF_TC_HEAD(futex_wake_op_cmp, tc) 1284 { 1285 atf_tc_set_md_var(tc, "descr", 1286 "tests futex WAKE_OP CMP operations"); 1287 } 1288 ATF_TC_BODY(futex_wake_op_cmp, tc) 1289 { 1290 do_futex_wake_op_cmp_test(FUTEX_PRIVATE_FLAG); 1291 } 1292 ATF_TC_CLEANUP(futex_wake_op_cmp, tc) 1293 { 1294 do_cleanup(); 1295 } 1296 1297 /*****************************************************************************/ 1298 1299 1300 1301 /*****************************************************************************/ 1302 1303 static void 1304 do_futex_wait_timeout(bool relative, clockid_t clock) 1305 { 1306 struct timespec ts; 1307 struct timespec deadline; 1308 int op = relative ? FUTEX_WAIT : FUTEX_WAIT_BITSET; 1309 1310 if (clock == CLOCK_REALTIME) 1311 op |= FUTEX_CLOCK_REALTIME; 1312 1313 RL(clock_gettime(clock, &deadline)); 1314 deadline.tv_sec += 2; 1315 if (relative) { 1316 ts.tv_sec = 2; 1317 ts.tv_nsec = 0; 1318 } else { 1319 ts = deadline; 1320 } 1321 1322 futex_word = 1; 1323 ATF_REQUIRE_ERRNO(ETIMEDOUT, 1324 __futex(&futex_word, op | FUTEX_PRIVATE_FLAG, 1325 1, &ts, NULL, 0, FUTEX_BITSET_MATCH_ANY) == -1); 1326 1327 /* Can't reliably check CLOCK_REALTIME in the presence of NTP. */ 1328 if (clock != CLOCK_REALTIME) { 1329 RL(clock_gettime(clock, &ts)); 1330 ATF_CHECK_MSG(ts.tv_sec >= deadline.tv_sec, 1331 "ts=%lld.%09ldsec deadline=%lld.%09ldsec", 1332 (long long)ts.tv_sec, ts.tv_nsec, 1333 (long long)deadline.tv_sec, deadline.tv_nsec); 1334 ATF_CHECK_MSG((ts.tv_sec > deadline.tv_sec || 1335 ts.tv_nsec >= deadline.tv_nsec), 1336 "ts=%lld.%09ldsec deadline=%lld.%09ldsec", 1337 (long long)ts.tv_sec, ts.tv_nsec, 1338 (long long)deadline.tv_sec, deadline.tv_nsec); 1339 } 1340 } 1341 1342 ATF_TC(futex_wait_timeout_relative); 1343 ATF_TC_HEAD(futex_wait_timeout_relative, tc) 1344 { 1345 atf_tc_set_md_var(tc, "descr", 1346 "tests futex WAIT with relative timeout"); 1347 } 1348 ATF_TC_BODY(futex_wait_timeout_relative, tc) 1349 { 1350 do_futex_wait_timeout(true, CLOCK_MONOTONIC); 1351 } 1352 1353 ATF_TC(futex_wait_timeout_relative_rt); 1354 ATF_TC_HEAD(futex_wait_timeout_relative_rt, tc) 1355 { 1356 atf_tc_set_md_var(tc, "descr", 1357 "tests futex WAIT with relative timeout (REALTIME)"); 1358 } 1359 ATF_TC_BODY(futex_wait_timeout_relative_rt, tc) 1360 { 1361 do_futex_wait_timeout(true, CLOCK_REALTIME); 1362 } 1363 1364 ATF_TC(futex_wait_timeout_deadline); 1365 ATF_TC_HEAD(futex_wait_timeout_deadline, tc) 1366 { 1367 atf_tc_set_md_var(tc, "descr", 1368 "tests futex WAIT with absolute deadline"); 1369 } 1370 ATF_TC_BODY(futex_wait_timeout_deadline, tc) 1371 { 1372 do_futex_wait_timeout(false, CLOCK_MONOTONIC); 1373 } 1374 1375 ATF_TC(futex_wait_timeout_deadline_rt); 1376 ATF_TC_HEAD(futex_wait_timeout_deadline_rt, tc) 1377 { 1378 atf_tc_set_md_var(tc, "descr", 1379 "tests futex WAIT with absolute deadline (REALTIME)"); 1380 } 1381 ATF_TC_BODY(futex_wait_timeout_deadline_rt, tc) 1382 { 1383 do_futex_wait_timeout(false, CLOCK_REALTIME); 1384 } 1385 1386 /*****************************************************************************/ 1387 1388 static void 1389 sig_noop(int sig __unused) 1390 { 1391 } 1392 1393 static void (*old_act)(int) = SIG_DFL; 1394 1395 static void 1396 do_futex_wait_evil_unmapped(int map_flags) 1397 { 1398 int i; 1399 1400 create_bs(map_flags); 1401 1402 REQUIRE_LIBC(signal(SIGUSR1, sig_noop), SIG_ERR); 1403 1404 setup_lwp_context(&lwp_data[0], simple_test_waiter_lwp); 1405 lwp_data[0].op_flags = 0; 1406 lwp_data[0].futex_error = -1; 1407 lwp_data[0].futex_ptr = &bs_addr[0]; 1408 lwp_data[0].block_val = 0; 1409 lwp_data[0].bitset = 0; 1410 lwp_data[0].wait_op = FUTEX_WAIT; 1411 RL(_lwp_create(&lwp_data[0].context, 0, &lwp_data[0].lwpid)); 1412 1413 for (i = 0; i < 5; i++) { 1414 membar_sync(); 1415 if (nlwps_running == 1) 1416 break; 1417 sleep(1); 1418 } 1419 membar_sync(); 1420 ATF_REQUIRE_EQ_MSG(nlwps_running, 1, 1421 "waiters failed to start, nlwps_running=%u", nlwps_running); 1422 1423 /* Ensure it's blocked. */ 1424 ATF_REQUIRE_EQ_MSG(lwp_data[0].futex_error, -1, 1425 "lwp_data[0].futex_error=%d", lwp_data[0].futex_error); 1426 1427 /* Rudely unmap the backing store. */ 1428 cleanup_bs(); 1429 1430 /* Signal the waiter so that it leaves the futex. */ 1431 RL(_lwp_kill(lwp_data[0].threadid, SIGUSR1)); 1432 1433 /* Yay! No panic! */ 1434 1435 reap_lwp_waiter(&lwp_data[0]); 1436 } 1437 1438 ATF_TC_WITH_CLEANUP(futex_wait_evil_unmapped_anon); 1439 ATF_TC_HEAD(futex_wait_evil_unmapped_anon, tc) 1440 { 1441 atf_tc_set_md_var(tc, "descr", 1442 "tests futex WAIT while futex is unmapped - anon memory"); 1443 } 1444 ATF_TC_BODY(futex_wait_evil_unmapped_anon, tc) 1445 { 1446 do_futex_wait_evil_unmapped(MAP_ANON); 1447 } 1448 ATF_TC_CLEANUP(futex_wait_evil_unmapped_anon, tc) 1449 { 1450 signal(SIGUSR1, old_act); 1451 do_cleanup(); 1452 } 1453 1454 /*****************************************************************************/ 1455 1456 static int pri_min; 1457 static int pri_max; 1458 1459 static void 1460 lowpri_simple_test_waiter_lwp(void *arg) 1461 { 1462 struct lwp_data *d = arg; 1463 struct sched_param sp; 1464 int policy; 1465 1466 d->threadid = _lwp_self(); 1467 1468 RL(_sched_getparam(getpid(), d->threadid, &policy, &sp)); 1469 policy = SCHED_RR; 1470 sp.sched_priority = pri_min; 1471 RL(_sched_setparam(getpid(), d->threadid, policy, &sp)); 1472 1473 simple_test_waiter_lwp(arg); 1474 } 1475 1476 static void 1477 highpri_simple_test_waiter_lwp(void *arg) 1478 { 1479 struct lwp_data *d = arg; 1480 struct sched_param sp; 1481 int policy; 1482 1483 d->threadid = _lwp_self(); 1484 1485 RL(_sched_getparam(getpid(), d->threadid, &policy, &sp)); 1486 policy = SCHED_RR; 1487 sp.sched_priority = pri_max; 1488 RL(_sched_setparam(getpid(), d->threadid, policy, &sp)); 1489 1490 simple_test_waiter_lwp(arg); 1491 } 1492 1493 static void 1494 do_test_wake_highest_pri(void) 1495 { 1496 lwpid_t waiter; 1497 int tries; 1498 long pri; 1499 int n; 1500 1501 RL(pri = sysconf(_SC_SCHED_PRI_MIN)); 1502 pri_min = (int)pri; 1503 RL(pri = sysconf(_SC_SCHED_PRI_MAX)); 1504 pri_max = (int)pri; 1505 1506 futex_word = 0; 1507 membar_sync(); 1508 1509 setup_lwp_context(&lwp_data[0], lowpri_simple_test_waiter_lwp); 1510 lwp_data[0].op_flags = FUTEX_PRIVATE_FLAG; 1511 lwp_data[0].futex_error = -1; 1512 lwp_data[0].futex_ptr = &futex_word; 1513 lwp_data[0].block_val = 0; 1514 lwp_data[0].bitset = 0; 1515 lwp_data[0].wait_op = FUTEX_WAIT; 1516 RL(_lwp_create(&lwp_data[0].context, 0, &lwp_data[0].lwpid)); 1517 1518 for (tries = 0; tries < 5; tries++) { 1519 membar_sync(); 1520 if (nlwps_running == 1) 1521 break; 1522 sleep(1); 1523 } 1524 membar_sync(); 1525 ATF_REQUIRE_EQ_MSG(nlwps_running, 1, 1526 "lowpri waiter failed to start, nlwps_running=%u", nlwps_running); 1527 1528 /* Ensure it's blocked. */ 1529 ATF_REQUIRE_EQ_MSG(lwp_data[0].futex_error, -1, 1530 "lwp_data[0].futex_error=%d", lwp_data[0].futex_error); 1531 1532 setup_lwp_context(&lwp_data[1], highpri_simple_test_waiter_lwp); 1533 lwp_data[1].op_flags = FUTEX_PRIVATE_FLAG; 1534 lwp_data[1].futex_error = -1; 1535 lwp_data[1].futex_ptr = &futex_word; 1536 lwp_data[1].block_val = 0; 1537 lwp_data[1].bitset = 0; 1538 lwp_data[1].wait_op = FUTEX_WAIT; 1539 RL(_lwp_create(&lwp_data[1].context, 0, &lwp_data[1].lwpid)); 1540 1541 for (tries = 0; tries < 5; tries++) { 1542 membar_sync(); 1543 if (nlwps_running == 2) 1544 break; 1545 sleep(1); 1546 } 1547 membar_sync(); 1548 ATF_REQUIRE_EQ_MSG(nlwps_running, 2, 1549 "highpri waiter failed to start, nlwps_running=%u", nlwps_running); 1550 1551 /* Ensure it's blocked. */ 1552 ATF_REQUIRE_EQ_MSG(lwp_data[1].futex_error, -1, 1553 "lwp_data[1].futex_error=%d", lwp_data[1].futex_error); 1554 1555 /* Wake the first LWP. We should get the highpri thread. */ 1556 RL(n = __futex(&futex_word, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1557 1, NULL, NULL, 0, 0)); 1558 ATF_REQUIRE_EQ_MSG(n, 1, "n=%d woken", n); 1559 sleep(1); 1560 for (tries = 0; tries < 5; tries++) { 1561 membar_sync(); 1562 if (nlwps_running == 1) 1563 break; 1564 sleep(1); 1565 } 1566 membar_sync(); 1567 ATF_REQUIRE_EQ_MSG(nlwps_running, 1, "nlwps_running=%u", 1568 nlwps_running); 1569 RL(_lwp_wait(0, &waiter)); 1570 ATF_REQUIRE_EQ_MSG(waiter, lwp_data[1].threadid, 1571 "waiter=%ld lwp_data[1].threadid=%ld", 1572 (long)waiter, (long)lwp_data[1].threadid); 1573 1574 /* Wake the second LWP. We should get the lowpri thread. */ 1575 RL(n = __futex(&futex_word, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1576 1, NULL, NULL, 0, 0)); 1577 ATF_REQUIRE_EQ_MSG(n, 1, "n=%d woken", n); 1578 sleep(1); 1579 for (tries = 0; tries < 5; tries++) { 1580 membar_sync(); 1581 if (nlwps_running == 0) 1582 break; 1583 sleep(1); 1584 } 1585 membar_sync(); 1586 ATF_REQUIRE_EQ_MSG(nlwps_running, 0, "nlwps_running=%u", 1587 nlwps_running); 1588 RL(_lwp_wait(0, &waiter)); 1589 ATF_REQUIRE_EQ_MSG(waiter, lwp_data[0].threadid, 1590 "waiter=%ld lwp_data[0].threadid=%ld", 1591 (long)waiter, (long)lwp_data[0].threadid); 1592 } 1593 1594 ATF_TC_WITH_CLEANUP(futex_wake_highest_pri); 1595 ATF_TC_HEAD(futex_wake_highest_pri, tc) 1596 { 1597 atf_tc_set_md_var(tc, "descr", 1598 "tests that futex WAKE wakes the highest priority waiter"); 1599 atf_tc_set_md_var(tc, "require.user", "root"); 1600 } 1601 ATF_TC_BODY(futex_wake_highest_pri, tc) 1602 { 1603 atf_tc_expect_fail("PR kern/55230"); 1604 do_test_wake_highest_pri(); 1605 } 1606 ATF_TC_CLEANUP(futex_wake_highest_pri, tc) 1607 { 1608 do_cleanup(); 1609 } 1610 1611 /*****************************************************************************/ 1612 1613 ATF_TP_ADD_TCS(tp) 1614 { 1615 ATF_TP_ADD_TC(tp, futex_basic_wait_wake_private); 1616 ATF_TP_ADD_TC(tp, futex_basic_wait_wake_shared); 1617 ATF_TP_ADD_TC(tp, futex_wait_wake_anon_bs_private); 1618 ATF_TP_ADD_TC(tp, futex_wait_wake_anon_bs_shared); 1619 ATF_TP_ADD_TC(tp, futex_wait_wake_file_bs_private); 1620 ATF_TP_ADD_TC(tp, futex_wait_wake_file_bs_shared); 1621 ATF_TP_ADD_TC(tp, futex_wait_wake_file_bs_cow_private); 1622 ATF_TP_ADD_TC(tp, futex_wait_wake_file_bs_cow_shared); 1623 1624 ATF_TP_ADD_TC(tp, futex_wait_wake_anon_bs_shared_proc); 1625 ATF_TP_ADD_TC(tp, futex_wait_wake_file_bs_shared_proc); 1626 1627 ATF_TP_ADD_TC(tp, futex_wait_pointless_bitset); 1628 ATF_TP_ADD_TC(tp, futex_wait_wake_bitset); 1629 1630 ATF_TP_ADD_TC(tp, futex_wait_timeout_relative); 1631 ATF_TP_ADD_TC(tp, futex_wait_timeout_relative_rt); 1632 ATF_TP_ADD_TC(tp, futex_wait_timeout_deadline); 1633 ATF_TP_ADD_TC(tp, futex_wait_timeout_deadline_rt); 1634 1635 ATF_TP_ADD_TC(tp, futex_wait_evil_unmapped_anon); 1636 1637 ATF_TP_ADD_TC(tp, futex_requeue); 1638 ATF_TP_ADD_TC(tp, futex_cmp_requeue); 1639 ATF_TP_ADD_TC(tp, futex_cmp_requeue_trivial); 1640 1641 ATF_TP_ADD_TC(tp, futex_wake_op_op); 1642 ATF_TP_ADD_TC(tp, futex_wake_op_cmp); 1643 1644 ATF_TP_ADD_TC(tp, futex_wake_highest_pri); 1645 1646 return atf_no_error(); 1647 } 1648