1 /* $NetBSD: t_futex_ops.c,v 1.5 2020/05/06 05:14:27 thorpej 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.5 2020/05/06 05:14:27 thorpej 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_REQUIRE(__futex(&futex_word, op | flags, 829 0, NULL, &futex_word1, INT_MAX, good_val3) == 0); 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_REQUIRE(__futex(&futex_word1, op | flags, 850 1, NULL, &futex_word, 1, good_val3) == 1); 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 /*****************************************************************************/ 913 914 static void 915 do_futex_wake_op_op_test(int flags) 916 { 917 int op; 918 919 futex_word = 0; 920 futex_word1 = 0; 921 922 /* 923 * The op= operations should work even if there are no waiters. 924 */ 925 926 /* 927 * Because these operations use both futex addresses, exercise 928 * rejecting unaligned futex addresses here. 929 */ 930 op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_EQ, 0); 931 ATF_REQUIRE_ERRNO(EINVAL, 932 __futex((int *)1, FUTEX_WAKE_OP | flags, 933 0, NULL, &futex_word1, 0, op) == -1); 934 ATF_REQUIRE(futex_word1 == 0); 935 936 ATF_REQUIRE_ERRNO(EINVAL, 937 __futex(&futex_word, FUTEX_WAKE_OP | flags, 938 0, NULL, (int *)1, 0, op) == -1); 939 ATF_REQUIRE(futex_word == 0); 940 941 /* Check unmapped uaddr2 handling, too. */ 942 ATF_REQUIRE_ERRNO(EFAULT, 943 __futex(&futex_word, FUTEX_WAKE_OP | flags, 944 0, NULL, NULL, 0, op) == -1); 945 ATF_REQUIRE(futex_word == 0); 946 947 op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_EQ, 0); 948 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 949 0, NULL, &futex_word1, 0, op) == 0); 950 ATF_REQUIRE(futex_word1 == 1); 951 952 op = FUTEX_OP(FUTEX_OP_ADD, 1, FUTEX_OP_CMP_EQ, 0); 953 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 954 0, NULL, &futex_word1, 0, op) == 0); 955 ATF_REQUIRE(futex_word1 == 2); 956 957 op = FUTEX_OP(FUTEX_OP_OR, 2, FUTEX_OP_CMP_EQ, 0); 958 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 959 0, NULL, &futex_word1, 0, op) == 0); 960 ATF_REQUIRE(futex_word1 == 2); 961 962 /* This should fail because of invalid shift value 32. */ 963 op = FUTEX_OP(FUTEX_OP_OR | FUTEX_OP_OPARG_SHIFT, 32, 964 FUTEX_OP_CMP_EQ, 0); 965 ATF_REQUIRE_ERRNO(EINVAL, 966 __futex(&futex_word, FUTEX_WAKE_OP | flags, 967 0, NULL, &futex_word1, 0, op) == -1); 968 ATF_REQUIRE(futex_word1 == 2); 969 970 op = FUTEX_OP(FUTEX_OP_OR | FUTEX_OP_OPARG_SHIFT, 31, 971 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 == (int)0x80000002); 975 976 op = FUTEX_OP(FUTEX_OP_ANDN | FUTEX_OP_OPARG_SHIFT, 31, 977 FUTEX_OP_CMP_EQ, 0); 978 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 979 0, NULL, &futex_word1, 0, op) == 0); 980 ATF_REQUIRE(futex_word1 == 2); 981 982 op = FUTEX_OP(FUTEX_OP_XOR, 2, FUTEX_OP_CMP_EQ, 0); 983 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 984 0, NULL, &futex_word1, 0, op) == 0); 985 ATF_REQUIRE(futex_word1 == 0); 986 } 987 988 ATF_TC_WITH_CLEANUP(futex_wake_op_op); 989 ATF_TC_HEAD(futex_wake_op_op, tc) 990 { 991 atf_tc_set_md_var(tc, "descr", 992 "tests futex WAKE_OP OP operations"); 993 } 994 ATF_TC_BODY(futex_wake_op_op, tc) 995 { 996 do_futex_wake_op_op_test(FUTEX_PRIVATE_FLAG); 997 } 998 ATF_TC_CLEANUP(futex_wake_op_op, tc) 999 { 1000 do_cleanup(); 1001 } 1002 1003 static void 1004 create_wake_op_test_lwps(int flags) 1005 { 1006 int i; 1007 1008 futex_word1 = 0; 1009 membar_sync(); 1010 1011 for (i = WAITER_LWP0; i <= WAITER_LWP5; i++) { 1012 setup_lwp_context(&lwp_data[i], simple_test_waiter_lwp); 1013 lwp_data[i].op_flags = flags; 1014 lwp_data[i].futex_error = -1; 1015 lwp_data[i].futex_ptr = &futex_word1; 1016 lwp_data[i].block_val = 0; 1017 lwp_data[i].bitset = 0; 1018 lwp_data[i].wait_op = FUTEX_WAIT; 1019 ATF_REQUIRE(_lwp_create(&lwp_data[i].context, 0, 1020 &lwp_data[i].lwpid) == 0); 1021 } 1022 1023 for (i = 0; i < 5; i++) { 1024 membar_sync(); 1025 if (nlwps_running == 6) 1026 break; 1027 sleep(1); 1028 } 1029 membar_sync(); 1030 ATF_REQUIRE_EQ_MSG(nlwps_running, 6, "waiters failed to start"); 1031 1032 /* Ensure they're blocked. */ 1033 for (i = WAITER_LWP0; i <= WAITER_LWP5; i++) { 1034 ATF_REQUIRE(lwp_data[i].futex_error == -1); 1035 } 1036 } 1037 1038 static void 1039 reap_wake_op_test_lwps(void) 1040 { 1041 int i; 1042 1043 for (i = WAITER_LWP0; i <= WAITER_LWP5; i++) { 1044 ATF_REQUIRE(_lwp_wait(lwp_data[i].lwpid, NULL) == 0); 1045 } 1046 } 1047 1048 static void 1049 do_futex_wake_op_cmp_test(int flags) 1050 { 1051 int tries, op; 1052 1053 futex_word = 0; 1054 membar_sync(); 1055 1056 /* 1057 * Verify and negative and positive for each individual 1058 * compare. 1059 */ 1060 1061 create_wake_op_test_lwps(flags); 1062 1063 /* #LWPs = 6 */ 1064 op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, 1); 1065 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 1066 0, NULL, &futex_word1, 1, op) == 0); 1067 ATF_REQUIRE(futex_word1 == 0); 1068 1069 op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_EQ, 0); 1070 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 1071 0, NULL, &futex_word1, 1, op) == 1); 1072 ATF_REQUIRE(futex_word1 == 1); 1073 1074 /* #LWPs = 5 */ 1075 op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_NE, 1); 1076 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 1077 0, NULL, &futex_word1, 1, op) == 0); 1078 ATF_REQUIRE(futex_word1 == 1); 1079 1080 op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_NE, 2); 1081 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 1082 0, NULL, &futex_word1, 1, op) == 1); 1083 ATF_REQUIRE(futex_word1 == 2); 1084 1085 /* #LWPs = 4 */ 1086 op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_LT, 2); 1087 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 1088 0, NULL, &futex_word1, 1, op) == 0); 1089 ATF_REQUIRE(futex_word1 == 2); 1090 1091 op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_LT, 3); 1092 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 1093 0, NULL, &futex_word1, 1, op) == 1); 1094 ATF_REQUIRE(futex_word1 == 2); 1095 1096 /* #LWPs = 3 */ 1097 op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_LE, 1); 1098 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 1099 0, NULL, &futex_word1, 1, op) == 0); 1100 ATF_REQUIRE(futex_word1 == 1); 1101 1102 op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_LE, 1); 1103 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 1104 0, NULL, &futex_word1, 1, op) == 1); 1105 ATF_REQUIRE(futex_word1 == 1); 1106 1107 /* #LWPs = 2 */ 1108 op = FUTEX_OP(FUTEX_OP_SET, 3, FUTEX_OP_CMP_GT, 3); 1109 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 1110 0, NULL, &futex_word1, 1, op) == 0); 1111 ATF_REQUIRE(futex_word1 == 3); 1112 1113 op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_GT, 2); 1114 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 1115 0, NULL, &futex_word1, 1, op) == 1); 1116 ATF_REQUIRE(futex_word1 == 2); 1117 1118 /* #LWPs = 1 */ 1119 op = FUTEX_OP(FUTEX_OP_SET, 3, FUTEX_OP_CMP_GE, 4); 1120 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 1121 0, NULL, &futex_word1, 1, op) == 0); 1122 ATF_REQUIRE(futex_word1 == 3); 1123 1124 op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_GE, 3); 1125 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, 1126 0, NULL, &futex_word1, 1, op) == 1); 1127 ATF_REQUIRE(futex_word1 == 2); 1128 1129 /* #LWPs = 0 */ 1130 1131 /* Trust, but verify. */ 1132 sleep(1); 1133 for (tries = 0; tries < 5; tries++) { 1134 membar_sync(); 1135 if (nlwps_running == 0) 1136 break; 1137 sleep(1); 1138 } 1139 membar_sync(); 1140 ATF_REQUIRE_EQ_MSG(nlwps_running, 0, "waiters failed to exit"); 1141 1142 reap_wake_op_test_lwps(); 1143 1144 /* 1145 * Verify wakes on uaddr work even if the uaddr2 comparison 1146 * fails. 1147 */ 1148 1149 create_wake_op_test_lwps(flags); 1150 1151 /* #LWPs = 6 */ 1152 ATF_REQUIRE(futex_word == 0); 1153 op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, 666); 1154 ATF_REQUIRE(__futex(&futex_word1, FUTEX_WAKE_OP | flags, 1155 INT_MAX, NULL, &futex_word, 0, op) == 6); 1156 ATF_REQUIRE(futex_word == 0); 1157 1158 /* #LWPs = 0 */ 1159 1160 /* Trust, but verify. */ 1161 sleep(1); 1162 for (tries = 0; tries < 5; tries++) { 1163 membar_sync(); 1164 if (nlwps_running == 0) 1165 break; 1166 sleep(1); 1167 } 1168 membar_sync(); 1169 ATF_REQUIRE_EQ_MSG(nlwps_running, 0, "waiters failed to exit"); 1170 1171 reap_wake_op_test_lwps(); 1172 } 1173 1174 ATF_TC_WITH_CLEANUP(futex_wake_op_cmp); 1175 ATF_TC_HEAD(futex_wake_op_cmp, tc) 1176 { 1177 atf_tc_set_md_var(tc, "descr", 1178 "tests futex WAKE_OP CMP operations"); 1179 } 1180 ATF_TC_BODY(futex_wake_op_cmp, tc) 1181 { 1182 do_futex_wake_op_cmp_test(FUTEX_PRIVATE_FLAG); 1183 } 1184 ATF_TC_CLEANUP(futex_wake_op_cmp, tc) 1185 { 1186 do_cleanup(); 1187 } 1188 1189 /*****************************************************************************/ 1190 1191 static void 1192 do_futex_wait_timeout(bool relative, clockid_t clock) 1193 { 1194 struct timespec ts; 1195 struct timespec deadline; 1196 int op = relative ? FUTEX_WAIT : FUTEX_WAIT_BITSET; 1197 1198 if (clock == CLOCK_REALTIME) 1199 op |= FUTEX_CLOCK_REALTIME; 1200 1201 ATF_REQUIRE(clock_gettime(clock, &deadline) == 0); 1202 deadline.tv_sec += 2; 1203 if (relative) { 1204 ts.tv_sec = 2; 1205 ts.tv_nsec = 0; 1206 } else { 1207 ts = deadline; 1208 } 1209 1210 futex_word = 1; 1211 ATF_REQUIRE_ERRNO(ETIMEDOUT, 1212 __futex(&futex_word, op | FUTEX_PRIVATE_FLAG, 1213 1, &ts, NULL, 0, FUTEX_BITSET_MATCH_ANY) == -1); 1214 1215 /* Can't reliably check CLOCK_REALTIME in the presence of NTP. */ 1216 if (clock != CLOCK_REALTIME) { 1217 ATF_REQUIRE(clock_gettime(clock, &ts) == 0); 1218 ATF_REQUIRE(ts.tv_sec >= deadline.tv_sec); 1219 ATF_REQUIRE(ts.tv_sec > deadline.tv_sec || 1220 ts.tv_nsec >= deadline.tv_nsec); 1221 } 1222 } 1223 1224 ATF_TC(futex_wait_timeout_relative); 1225 ATF_TC_HEAD(futex_wait_timeout_relative, tc) 1226 { 1227 atf_tc_set_md_var(tc, "descr", 1228 "tests futex WAIT with relative timeout"); 1229 } 1230 ATF_TC_BODY(futex_wait_timeout_relative, tc) 1231 { 1232 do_futex_wait_timeout(true, CLOCK_MONOTONIC); 1233 } 1234 1235 ATF_TC(futex_wait_timeout_relative_rt); 1236 ATF_TC_HEAD(futex_wait_timeout_relative_rt, tc) 1237 { 1238 atf_tc_set_md_var(tc, "descr", 1239 "tests futex WAIT with relative timeout (REALTIME)"); 1240 } 1241 ATF_TC_BODY(futex_wait_timeout_relative_rt, tc) 1242 { 1243 do_futex_wait_timeout(true, CLOCK_REALTIME); 1244 } 1245 1246 ATF_TC(futex_wait_timeout_deadline); 1247 ATF_TC_HEAD(futex_wait_timeout_deadline, tc) 1248 { 1249 atf_tc_set_md_var(tc, "descr", 1250 "tests futex WAIT with absolute deadline"); 1251 } 1252 ATF_TC_BODY(futex_wait_timeout_deadline, tc) 1253 { 1254 do_futex_wait_timeout(false, CLOCK_MONOTONIC); 1255 } 1256 1257 ATF_TC(futex_wait_timeout_deadline_rt); 1258 ATF_TC_HEAD(futex_wait_timeout_deadline_rt, tc) 1259 { 1260 atf_tc_set_md_var(tc, "descr", 1261 "tests futex WAIT with absolute deadline (REALTIME)"); 1262 } 1263 ATF_TC_BODY(futex_wait_timeout_deadline_rt, tc) 1264 { 1265 do_futex_wait_timeout(false, CLOCK_REALTIME); 1266 } 1267 1268 /*****************************************************************************/ 1269 1270 static void 1271 sig_noop(int sig __unused) 1272 { 1273 } 1274 1275 static void (*old_act)(int) = SIG_DFL; 1276 1277 static void 1278 do_futex_wait_evil_unmapped(int map_flags) 1279 { 1280 int i; 1281 1282 create_bs(map_flags); 1283 1284 old_act = signal(SIGUSR1, sig_noop); 1285 ATF_REQUIRE(old_act != SIG_ERR); 1286 1287 setup_lwp_context(&lwp_data[0], simple_test_waiter_lwp); 1288 lwp_data[0].op_flags = 0; 1289 lwp_data[0].futex_error = -1; 1290 lwp_data[0].futex_ptr = &bs_addr[0]; 1291 lwp_data[0].block_val = 0; 1292 lwp_data[0].bitset = 0; 1293 lwp_data[0].wait_op = FUTEX_WAIT; 1294 ATF_REQUIRE(_lwp_create(&lwp_data[0].context, 0, 1295 &lwp_data[0].lwpid) == 0); 1296 1297 for (i = 0; i < 5; i++) { 1298 membar_sync(); 1299 if (nlwps_running == 1) 1300 break; 1301 sleep(1); 1302 } 1303 membar_sync(); 1304 ATF_REQUIRE_EQ_MSG(nlwps_running, 1, "waiters failed to start"); 1305 1306 /* Ensure it's blocked. */ 1307 ATF_REQUIRE(lwp_data[0].futex_error == -1); 1308 1309 /* Rudely unmap the backing store. */ 1310 cleanup_bs(); 1311 1312 /* Signal the waiter so that it leaves the futex. */ 1313 ATF_REQUIRE(_lwp_kill(lwp_data[0].threadid, SIGUSR1) == 0); 1314 1315 /* Yay! No panic! */ 1316 1317 reap_lwp_waiter(&lwp_data[0]); 1318 } 1319 1320 ATF_TC_WITH_CLEANUP(futex_wait_evil_unmapped_anon); 1321 ATF_TC_HEAD(futex_wait_evil_unmapped_anon, tc) 1322 { 1323 atf_tc_set_md_var(tc, "descr", 1324 "tests futex WAIT while futex is unmapped - anon memory"); 1325 } 1326 ATF_TC_BODY(futex_wait_evil_unmapped_anon, tc) 1327 { 1328 do_futex_wait_evil_unmapped(MAP_ANON); 1329 } 1330 ATF_TC_CLEANUP(futex_wait_evil_unmapped_anon, tc) 1331 { 1332 signal(SIGUSR1, old_act); 1333 do_cleanup(); 1334 } 1335 1336 /*****************************************************************************/ 1337 1338 static int pri_min; 1339 static int pri_max; 1340 1341 static void 1342 lowpri_simple_test_waiter_lwp(void *arg) 1343 { 1344 struct lwp_data *d = arg; 1345 struct sched_param sp; 1346 int policy; 1347 1348 d->threadid = _lwp_self(); 1349 1350 ATF_REQUIRE(_sched_getparam(getpid(), d->threadid, &policy, &sp) == 0); 1351 policy = SCHED_RR; 1352 sp.sched_priority = pri_min; 1353 ATF_REQUIRE(_sched_setparam(getpid(), d->threadid, policy, &sp) == 0); 1354 1355 simple_test_waiter_lwp(arg); 1356 } 1357 1358 static void 1359 highpri_simple_test_waiter_lwp(void *arg) 1360 { 1361 struct lwp_data *d = arg; 1362 struct sched_param sp; 1363 int policy; 1364 1365 d->threadid = _lwp_self(); 1366 1367 ATF_REQUIRE(_sched_getparam(getpid(), d->threadid, &policy, &sp) == 0); 1368 policy = SCHED_RR; 1369 sp.sched_priority = pri_max; 1370 ATF_REQUIRE(_sched_setparam(getpid(), d->threadid, policy, &sp) == 0); 1371 1372 simple_test_waiter_lwp(arg); 1373 } 1374 1375 static void 1376 do_test_wake_highest_pri(void) 1377 { 1378 lwpid_t waiter; 1379 int tries; 1380 long pri; 1381 1382 ATF_REQUIRE((pri = sysconf(_SC_SCHED_PRI_MIN)) != -1); 1383 pri_min = (int)pri; 1384 ATF_REQUIRE((pri = sysconf(_SC_SCHED_PRI_MAX)) != -1); 1385 pri_max = (int)pri; 1386 1387 futex_word = 0; 1388 membar_sync(); 1389 1390 setup_lwp_context(&lwp_data[0], lowpri_simple_test_waiter_lwp); 1391 lwp_data[0].op_flags = FUTEX_PRIVATE_FLAG; 1392 lwp_data[0].futex_error = -1; 1393 lwp_data[0].futex_ptr = &futex_word; 1394 lwp_data[0].block_val = 0; 1395 lwp_data[0].bitset = 0; 1396 lwp_data[0].wait_op = FUTEX_WAIT; 1397 ATF_REQUIRE(_lwp_create(&lwp_data[0].context, 0, 1398 &lwp_data[0].lwpid) == 0); 1399 1400 for (tries = 0; tries < 5; tries++) { 1401 membar_sync(); 1402 if (nlwps_running == 1) 1403 break; 1404 sleep(1); 1405 } 1406 membar_sync(); 1407 ATF_REQUIRE_EQ_MSG(nlwps_running, 1, "lowpri waiter failed to start"); 1408 1409 /* Ensure it's blocked. */ 1410 ATF_REQUIRE(lwp_data[0].futex_error == -1); 1411 1412 setup_lwp_context(&lwp_data[1], highpri_simple_test_waiter_lwp); 1413 lwp_data[1].op_flags = FUTEX_PRIVATE_FLAG; 1414 lwp_data[1].futex_error = -1; 1415 lwp_data[1].futex_ptr = &futex_word; 1416 lwp_data[1].block_val = 0; 1417 lwp_data[1].bitset = 0; 1418 lwp_data[1].wait_op = FUTEX_WAIT; 1419 ATF_REQUIRE(_lwp_create(&lwp_data[1].context, 0, 1420 &lwp_data[1].lwpid) == 0); 1421 1422 for (tries = 0; tries < 5; tries++) { 1423 membar_sync(); 1424 if (nlwps_running == 2) 1425 break; 1426 sleep(1); 1427 } 1428 membar_sync(); 1429 ATF_REQUIRE_EQ_MSG(nlwps_running, 2, "highpri waiter failed to start"); 1430 1431 /* Ensure it's blocked. */ 1432 ATF_REQUIRE(lwp_data[1].futex_error == -1); 1433 1434 /* Wake the first LWP. We should get the highpri thread. */ 1435 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1436 1, NULL, NULL, 0, 0) == 1); 1437 sleep(1); 1438 for (tries = 0; tries < 5; tries++) { 1439 membar_sync(); 1440 if (nlwps_running == 1) 1441 break; 1442 sleep(1); 1443 } 1444 membar_sync(); 1445 ATF_REQUIRE(nlwps_running == 1); 1446 ATF_REQUIRE(_lwp_wait(0, &waiter) == 0); 1447 ATF_REQUIRE(waiter == lwp_data[1].threadid); 1448 1449 /* Wake the second LWP. We should get the lowpri thread. */ 1450 ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1451 1, NULL, NULL, 0, 0) == 1); 1452 sleep(1); 1453 for (tries = 0; tries < 5; tries++) { 1454 membar_sync(); 1455 if (nlwps_running == 0) 1456 break; 1457 sleep(1); 1458 } 1459 membar_sync(); 1460 ATF_REQUIRE(nlwps_running == 0); 1461 ATF_REQUIRE(_lwp_wait(0, &waiter) == 0); 1462 ATF_REQUIRE(waiter == lwp_data[0].threadid); 1463 } 1464 1465 ATF_TC_WITH_CLEANUP(futex_wake_highest_pri); 1466 ATF_TC_HEAD(futex_wake_highest_pri, tc) 1467 { 1468 atf_tc_set_md_var(tc, "descr", 1469 "tests that futex WAKE wakes the highest priority waiter"); 1470 atf_tc_set_md_var(tc, "require.user", "root"); 1471 } 1472 ATF_TC_BODY(futex_wake_highest_pri, tc) 1473 { 1474 atf_tc_expect_fail("PR kern/55230"); 1475 do_test_wake_highest_pri(); 1476 } 1477 ATF_TC_CLEANUP(futex_wake_highest_pri, tc) 1478 { 1479 do_cleanup(); 1480 } 1481 1482 /*****************************************************************************/ 1483 1484 ATF_TP_ADD_TCS(tp) 1485 { 1486 ATF_TP_ADD_TC(tp, futex_basic_wait_wake_private); 1487 ATF_TP_ADD_TC(tp, futex_basic_wait_wake_shared); 1488 ATF_TP_ADD_TC(tp, futex_wait_wake_anon_bs_private); 1489 ATF_TP_ADD_TC(tp, futex_wait_wake_anon_bs_shared); 1490 ATF_TP_ADD_TC(tp, futex_wait_wake_file_bs_private); 1491 ATF_TP_ADD_TC(tp, futex_wait_wake_file_bs_shared); 1492 ATF_TP_ADD_TC(tp, futex_wait_wake_file_bs_cow_private); 1493 ATF_TP_ADD_TC(tp, futex_wait_wake_file_bs_cow_shared); 1494 1495 ATF_TP_ADD_TC(tp, futex_wait_wake_anon_bs_shared_proc); 1496 ATF_TP_ADD_TC(tp, futex_wait_wake_file_bs_shared_proc); 1497 1498 ATF_TP_ADD_TC(tp, futex_wait_pointless_bitset); 1499 ATF_TP_ADD_TC(tp, futex_wait_wake_bitset); 1500 1501 ATF_TP_ADD_TC(tp, futex_wait_timeout_relative); 1502 ATF_TP_ADD_TC(tp, futex_wait_timeout_relative_rt); 1503 ATF_TP_ADD_TC(tp, futex_wait_timeout_deadline); 1504 ATF_TP_ADD_TC(tp, futex_wait_timeout_deadline_rt); 1505 1506 ATF_TP_ADD_TC(tp, futex_wait_evil_unmapped_anon); 1507 1508 ATF_TP_ADD_TC(tp, futex_requeue); 1509 ATF_TP_ADD_TC(tp, futex_cmp_requeue); 1510 1511 ATF_TP_ADD_TC(tp, futex_wake_op_op); 1512 ATF_TP_ADD_TC(tp, futex_wake_op_cmp); 1513 1514 ATF_TP_ADD_TC(tp, futex_wake_highest_pri); 1515 1516 return atf_no_error(); 1517 } 1518