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