t_futex_ops.c revision 1.14 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