t_futex_ops.c revision 1.13 1 /* $NetBSD: t_futex_ops.c,v 1.13 2025/03/05 00:03:12 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.13 2025/03/05 00:03:12 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 atf_tc_expect_fail("PR kern/59129: futex(3):"
1050 " missing sign extension in FUTEX_WAKE_OP");
1051 futex_word1 = 0;
1052 op = FUTEX_OP(FUTEX_OP_SET, 0xfff, FUTEX_OP_CMP_EQ, 0);
1053 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
1054 0, NULL, &futex_word1, 0, op));
1055 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
1056 ATF_CHECK_EQ_MSG(futex_word1, -1, "futex_word1=%d", futex_word1);
1057
1058 futex_word1 = 0;
1059 op = (int)FUTEX_OP(FUTEX_OP_SET, -1, FUTEX_OP_CMP_EQ, 0);
1060 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
1061 0, NULL, &futex_word1, 0, op));
1062 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
1063 ATF_CHECK_EQ_MSG(futex_word1, -1, "futex_word1=%d", futex_word1);
1064 }
1065
1066 ATF_TC_WITH_CLEANUP(futex_wake_op_op);
1067 ATF_TC_HEAD(futex_wake_op_op, tc)
1068 {
1069 atf_tc_set_md_var(tc, "descr",
1070 "tests futex WAKE_OP OP operations");
1071 }
1072 ATF_TC_BODY(futex_wake_op_op, tc)
1073 {
1074 do_futex_wake_op_op_test(FUTEX_PRIVATE_FLAG);
1075 }
1076 ATF_TC_CLEANUP(futex_wake_op_op, tc)
1077 {
1078 do_cleanup();
1079 }
1080
1081 static void
1082 create_wake_op_test_lwps(int flags)
1083 {
1084 int i;
1085
1086 futex_word1 = 0;
1087 membar_sync();
1088
1089 for (i = WAITER_LWP0; i <= WAITER_LWP5; i++) {
1090 setup_lwp_context(&lwp_data[i], simple_test_waiter_lwp);
1091 lwp_data[i].op_flags = flags;
1092 lwp_data[i].futex_error = -1;
1093 lwp_data[i].futex_ptr = &futex_word1;
1094 lwp_data[i].block_val = 0;
1095 lwp_data[i].bitset = 0;
1096 lwp_data[i].wait_op = FUTEX_WAIT;
1097 RL(_lwp_create(&lwp_data[i].context, 0, &lwp_data[i].lwpid));
1098 }
1099
1100 for (i = 0; i < 5; i++) {
1101 membar_sync();
1102 if (nlwps_running == 6)
1103 break;
1104 sleep(1);
1105 }
1106 membar_sync();
1107 ATF_REQUIRE_EQ_MSG(nlwps_running, 6,
1108 "waiters failed to start, nlwps_running=%u", nlwps_running);
1109
1110 /* Ensure they're blocked. */
1111 for (i = WAITER_LWP0; i <= WAITER_LWP5; i++) {
1112 ATF_REQUIRE_EQ_MSG(lwp_data[i].futex_error, -1,
1113 "i=%d lwp_data[i].futex_error=%d",
1114 i, lwp_data[i].futex_error);
1115 }
1116 }
1117
1118 static void
1119 reap_wake_op_test_lwps(void)
1120 {
1121 int i;
1122
1123 for (i = WAITER_LWP0; i <= WAITER_LWP5; i++) {
1124 RL(_lwp_wait(lwp_data[i].lwpid, NULL));
1125 }
1126 }
1127
1128 static void
1129 do_futex_wake_op_cmp_test(int flags)
1130 {
1131 int tries, op, n;
1132
1133 futex_word = 0;
1134 membar_sync();
1135
1136 /*
1137 * Verify and negative and positive for each individual
1138 * compare.
1139 */
1140
1141 create_wake_op_test_lwps(flags);
1142
1143 /* #LWPs = 6 */
1144 atf_tc_expect_fail("PR kern/59129: futex(3):"
1145 " missing sign extension in FUTEX_WAKE_OP");
1146 futex_word1 = 0xfff;
1147 op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, 0xfff);
1148 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
1149 0, NULL, &futex_word1, 1, op));
1150 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
1151 ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1);
1152
1153 futex_word1 = 0xfff;
1154 op = (int)FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, -1);
1155 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
1156 0, NULL, &futex_word1, 1, op));
1157 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
1158 ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1);
1159
1160 op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, 1);
1161 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
1162 0, NULL, &futex_word1, 1, op));
1163 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
1164 ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1);
1165
1166 futex_word1 = -1;
1167 op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_EQ, 0xfff);
1168 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
1169 0, NULL, &futex_word1, 1, op));
1170 ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n);
1171 ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1);
1172
1173 /* #LWPs = 5 */
1174 op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_NE, 1);
1175 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
1176 0, NULL, &futex_word1, 1, op));
1177 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
1178 ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1);
1179
1180 op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_NE, 2);
1181 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
1182 0, NULL, &futex_word1, 1, op));
1183 ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n);
1184 ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1);
1185
1186 /* #LWPs = 4 */
1187 op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_LT, 2);
1188 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
1189 0, NULL, &futex_word1, 1, op));
1190 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
1191 ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1);
1192
1193 op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_LT, 3);
1194 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
1195 0, NULL, &futex_word1, 1, op));
1196 ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n);
1197 ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1);
1198
1199 /* #LWPs = 3 */
1200 op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_LE, 1);
1201 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
1202 0, NULL, &futex_word1, 1, op));
1203 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
1204 ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1);
1205
1206 op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_LE, 1);
1207 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
1208 0, NULL, &futex_word1, 1, op));
1209 ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n);
1210 ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1);
1211
1212 /* #LWPs = 2 */
1213 op = FUTEX_OP(FUTEX_OP_SET, 3, FUTEX_OP_CMP_GT, 3);
1214 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
1215 0, NULL, &futex_word1, 1, op));
1216 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
1217 ATF_CHECK_EQ_MSG(futex_word1, 3, "futex_word1=%d", futex_word1);
1218
1219 op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_GT, 2);
1220 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
1221 0, NULL, &futex_word1, 1, op));
1222 ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n);
1223 ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1);
1224
1225 /* #LWPs = 1 */
1226 op = FUTEX_OP(FUTEX_OP_SET, 3, FUTEX_OP_CMP_GE, 4);
1227 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
1228 0, NULL, &futex_word1, 1, op));
1229 ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
1230 ATF_CHECK_EQ_MSG(futex_word1, 3, "futex_word1=%d", futex_word1);
1231
1232 op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_GE, 3);
1233 RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
1234 0, NULL, &futex_word1, 1, op));
1235 ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n);
1236 ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1);
1237
1238 /* #LWPs = 0 */
1239
1240 /* Trust, but verify. */
1241 sleep(1);
1242 for (tries = 0; tries < 5; tries++) {
1243 membar_sync();
1244 if (nlwps_running == 0)
1245 break;
1246 sleep(1);
1247 }
1248 membar_sync();
1249 ATF_REQUIRE_EQ_MSG(nlwps_running, 0,
1250 "waiters failed to exit, nlwps_running=%u", nlwps_running);
1251
1252 reap_wake_op_test_lwps();
1253
1254 /*
1255 * Verify wakes on uaddr work even if the uaddr2 comparison
1256 * fails.
1257 */
1258
1259 create_wake_op_test_lwps(flags);
1260
1261 /* #LWPs = 6 */
1262 ATF_CHECK_EQ_MSG(futex_word, 0, "futex_word=%d", futex_word);
1263 op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, 666);
1264 RL(n = __futex(&futex_word1, FUTEX_WAKE_OP | flags,
1265 INT_MAX, NULL, &futex_word, 0, op));
1266 ATF_CHECK_EQ_MSG(n, 6, "n=%d woken", n);
1267 ATF_CHECK_EQ_MSG(futex_word, 0, "futex_word=%d", futex_word);
1268
1269 /* #LWPs = 0 */
1270
1271 /* Trust, but verify. */
1272 sleep(1);
1273 for (tries = 0; tries < 5; tries++) {
1274 membar_sync();
1275 if (nlwps_running == 0)
1276 break;
1277 sleep(1);
1278 }
1279 membar_sync();
1280 ATF_REQUIRE_EQ_MSG(nlwps_running, 0,
1281 "waiters failed to exit, nlwps_running=%u", nlwps_running);
1282
1283 reap_wake_op_test_lwps();
1284 }
1285
1286 ATF_TC_WITH_CLEANUP(futex_wake_op_cmp);
1287 ATF_TC_HEAD(futex_wake_op_cmp, tc)
1288 {
1289 atf_tc_set_md_var(tc, "descr",
1290 "tests futex WAKE_OP CMP operations");
1291 }
1292 ATF_TC_BODY(futex_wake_op_cmp, tc)
1293 {
1294 do_futex_wake_op_cmp_test(FUTEX_PRIVATE_FLAG);
1295 }
1296 ATF_TC_CLEANUP(futex_wake_op_cmp, tc)
1297 {
1298 do_cleanup();
1299 }
1300
1301 /*****************************************************************************/
1302
1303
1304
1305 /*****************************************************************************/
1306
1307 static void
1308 do_futex_wait_timeout(bool relative, clockid_t clock)
1309 {
1310 struct timespec ts;
1311 struct timespec deadline;
1312 int op = relative ? FUTEX_WAIT : FUTEX_WAIT_BITSET;
1313
1314 if (clock == CLOCK_REALTIME)
1315 op |= FUTEX_CLOCK_REALTIME;
1316
1317 RL(clock_gettime(clock, &deadline));
1318 deadline.tv_sec += 2;
1319 if (relative) {
1320 ts.tv_sec = 2;
1321 ts.tv_nsec = 0;
1322 } else {
1323 ts = deadline;
1324 }
1325
1326 futex_word = 1;
1327 ATF_REQUIRE_ERRNO(ETIMEDOUT,
1328 __futex(&futex_word, op | FUTEX_PRIVATE_FLAG,
1329 1, &ts, NULL, 0, FUTEX_BITSET_MATCH_ANY) == -1);
1330
1331 /* Can't reliably check CLOCK_REALTIME in the presence of NTP. */
1332 if (clock != CLOCK_REALTIME) {
1333 RL(clock_gettime(clock, &ts));
1334 ATF_CHECK_MSG(ts.tv_sec >= deadline.tv_sec,
1335 "ts=%lld.%09ldsec deadline=%lld.%09ldsec",
1336 (long long)ts.tv_sec, ts.tv_nsec,
1337 (long long)deadline.tv_sec, deadline.tv_nsec);
1338 ATF_CHECK_MSG((ts.tv_sec > deadline.tv_sec ||
1339 ts.tv_nsec >= deadline.tv_nsec),
1340 "ts=%lld.%09ldsec deadline=%lld.%09ldsec",
1341 (long long)ts.tv_sec, ts.tv_nsec,
1342 (long long)deadline.tv_sec, deadline.tv_nsec);
1343 }
1344 }
1345
1346 ATF_TC(futex_wait_timeout_relative);
1347 ATF_TC_HEAD(futex_wait_timeout_relative, tc)
1348 {
1349 atf_tc_set_md_var(tc, "descr",
1350 "tests futex WAIT with relative timeout");
1351 }
1352 ATF_TC_BODY(futex_wait_timeout_relative, tc)
1353 {
1354 do_futex_wait_timeout(true, CLOCK_MONOTONIC);
1355 }
1356
1357 ATF_TC(futex_wait_timeout_relative_rt);
1358 ATF_TC_HEAD(futex_wait_timeout_relative_rt, tc)
1359 {
1360 atf_tc_set_md_var(tc, "descr",
1361 "tests futex WAIT with relative timeout (REALTIME)");
1362 }
1363 ATF_TC_BODY(futex_wait_timeout_relative_rt, tc)
1364 {
1365 do_futex_wait_timeout(true, CLOCK_REALTIME);
1366 }
1367
1368 ATF_TC(futex_wait_timeout_deadline);
1369 ATF_TC_HEAD(futex_wait_timeout_deadline, tc)
1370 {
1371 atf_tc_set_md_var(tc, "descr",
1372 "tests futex WAIT with absolute deadline");
1373 }
1374 ATF_TC_BODY(futex_wait_timeout_deadline, tc)
1375 {
1376 do_futex_wait_timeout(false, CLOCK_MONOTONIC);
1377 }
1378
1379 ATF_TC(futex_wait_timeout_deadline_rt);
1380 ATF_TC_HEAD(futex_wait_timeout_deadline_rt, tc)
1381 {
1382 atf_tc_set_md_var(tc, "descr",
1383 "tests futex WAIT with absolute deadline (REALTIME)");
1384 }
1385 ATF_TC_BODY(futex_wait_timeout_deadline_rt, tc)
1386 {
1387 do_futex_wait_timeout(false, CLOCK_REALTIME);
1388 }
1389
1390 /*****************************************************************************/
1391
1392 static void
1393 sig_noop(int sig __unused)
1394 {
1395 }
1396
1397 static void (*old_act)(int) = SIG_DFL;
1398
1399 static void
1400 do_futex_wait_evil_unmapped(int map_flags)
1401 {
1402 int i;
1403
1404 create_bs(map_flags);
1405
1406 REQUIRE_LIBC(signal(SIGUSR1, sig_noop), SIG_ERR);
1407
1408 setup_lwp_context(&lwp_data[0], simple_test_waiter_lwp);
1409 lwp_data[0].op_flags = 0;
1410 lwp_data[0].futex_error = -1;
1411 lwp_data[0].futex_ptr = &bs_addr[0];
1412 lwp_data[0].block_val = 0;
1413 lwp_data[0].bitset = 0;
1414 lwp_data[0].wait_op = FUTEX_WAIT;
1415 RL(_lwp_create(&lwp_data[0].context, 0, &lwp_data[0].lwpid));
1416
1417 for (i = 0; i < 5; i++) {
1418 membar_sync();
1419 if (nlwps_running == 1)
1420 break;
1421 sleep(1);
1422 }
1423 membar_sync();
1424 ATF_REQUIRE_EQ_MSG(nlwps_running, 1,
1425 "waiters failed to start, nlwps_running=%u", nlwps_running);
1426
1427 /* Ensure it's blocked. */
1428 ATF_REQUIRE_EQ_MSG(lwp_data[0].futex_error, -1,
1429 "lwp_data[0].futex_error=%d", lwp_data[0].futex_error);
1430
1431 /* Rudely unmap the backing store. */
1432 cleanup_bs();
1433
1434 /* Signal the waiter so that it leaves the futex. */
1435 RL(_lwp_kill(lwp_data[0].threadid, SIGUSR1));
1436
1437 /* Yay! No panic! */
1438
1439 reap_lwp_waiter(&lwp_data[0]);
1440 }
1441
1442 ATF_TC_WITH_CLEANUP(futex_wait_evil_unmapped_anon);
1443 ATF_TC_HEAD(futex_wait_evil_unmapped_anon, tc)
1444 {
1445 atf_tc_set_md_var(tc, "descr",
1446 "tests futex WAIT while futex is unmapped - anon memory");
1447 }
1448 ATF_TC_BODY(futex_wait_evil_unmapped_anon, tc)
1449 {
1450 do_futex_wait_evil_unmapped(MAP_ANON);
1451 }
1452 ATF_TC_CLEANUP(futex_wait_evil_unmapped_anon, tc)
1453 {
1454 signal(SIGUSR1, old_act);
1455 do_cleanup();
1456 }
1457
1458 /*****************************************************************************/
1459
1460 static int pri_min;
1461 static int pri_max;
1462
1463 static void
1464 lowpri_simple_test_waiter_lwp(void *arg)
1465 {
1466 struct lwp_data *d = arg;
1467 struct sched_param sp;
1468 int policy;
1469
1470 d->threadid = _lwp_self();
1471
1472 RL(_sched_getparam(getpid(), d->threadid, &policy, &sp));
1473 policy = SCHED_RR;
1474 sp.sched_priority = pri_min;
1475 RL(_sched_setparam(getpid(), d->threadid, policy, &sp));
1476
1477 simple_test_waiter_lwp(arg);
1478 }
1479
1480 static void
1481 highpri_simple_test_waiter_lwp(void *arg)
1482 {
1483 struct lwp_data *d = arg;
1484 struct sched_param sp;
1485 int policy;
1486
1487 d->threadid = _lwp_self();
1488
1489 RL(_sched_getparam(getpid(), d->threadid, &policy, &sp));
1490 policy = SCHED_RR;
1491 sp.sched_priority = pri_max;
1492 RL(_sched_setparam(getpid(), d->threadid, policy, &sp));
1493
1494 simple_test_waiter_lwp(arg);
1495 }
1496
1497 static void
1498 do_test_wake_highest_pri(void)
1499 {
1500 lwpid_t waiter;
1501 int tries;
1502 long pri;
1503 int n;
1504
1505 RL(pri = sysconf(_SC_SCHED_PRI_MIN));
1506 pri_min = (int)pri;
1507 RL(pri = sysconf(_SC_SCHED_PRI_MAX));
1508 pri_max = (int)pri;
1509
1510 futex_word = 0;
1511 membar_sync();
1512
1513 setup_lwp_context(&lwp_data[0], lowpri_simple_test_waiter_lwp);
1514 lwp_data[0].op_flags = FUTEX_PRIVATE_FLAG;
1515 lwp_data[0].futex_error = -1;
1516 lwp_data[0].futex_ptr = &futex_word;
1517 lwp_data[0].block_val = 0;
1518 lwp_data[0].bitset = 0;
1519 lwp_data[0].wait_op = FUTEX_WAIT;
1520 RL(_lwp_create(&lwp_data[0].context, 0, &lwp_data[0].lwpid));
1521
1522 for (tries = 0; tries < 5; tries++) {
1523 membar_sync();
1524 if (nlwps_running == 1)
1525 break;
1526 sleep(1);
1527 }
1528 membar_sync();
1529 ATF_REQUIRE_EQ_MSG(nlwps_running, 1,
1530 "lowpri waiter failed to start, nlwps_running=%u", nlwps_running);
1531
1532 /* Ensure it's blocked. */
1533 ATF_REQUIRE_EQ_MSG(lwp_data[0].futex_error, -1,
1534 "lwp_data[0].futex_error=%d", lwp_data[0].futex_error);
1535
1536 setup_lwp_context(&lwp_data[1], highpri_simple_test_waiter_lwp);
1537 lwp_data[1].op_flags = FUTEX_PRIVATE_FLAG;
1538 lwp_data[1].futex_error = -1;
1539 lwp_data[1].futex_ptr = &futex_word;
1540 lwp_data[1].block_val = 0;
1541 lwp_data[1].bitset = 0;
1542 lwp_data[1].wait_op = FUTEX_WAIT;
1543 RL(_lwp_create(&lwp_data[1].context, 0, &lwp_data[1].lwpid));
1544
1545 for (tries = 0; tries < 5; tries++) {
1546 membar_sync();
1547 if (nlwps_running == 2)
1548 break;
1549 sleep(1);
1550 }
1551 membar_sync();
1552 ATF_REQUIRE_EQ_MSG(nlwps_running, 2,
1553 "highpri waiter failed to start, nlwps_running=%u", nlwps_running);
1554
1555 /* Ensure it's blocked. */
1556 ATF_REQUIRE_EQ_MSG(lwp_data[1].futex_error, -1,
1557 "lwp_data[1].futex_error=%d", lwp_data[1].futex_error);
1558
1559 /* Wake the first LWP. We should get the highpri thread. */
1560 RL(n = __futex(&futex_word, FUTEX_WAKE | FUTEX_PRIVATE_FLAG,
1561 1, NULL, NULL, 0, 0));
1562 ATF_REQUIRE_EQ_MSG(n, 1, "n=%d woken", n);
1563 sleep(1);
1564 for (tries = 0; tries < 5; tries++) {
1565 membar_sync();
1566 if (nlwps_running == 1)
1567 break;
1568 sleep(1);
1569 }
1570 membar_sync();
1571 ATF_REQUIRE_EQ_MSG(nlwps_running, 1, "nlwps_running=%u",
1572 nlwps_running);
1573 RL(_lwp_wait(0, &waiter));
1574 ATF_REQUIRE_EQ_MSG(waiter, lwp_data[1].threadid,
1575 "waiter=%ld lwp_data[1].threadid=%ld",
1576 (long)waiter, (long)lwp_data[1].threadid);
1577
1578 /* Wake the second LWP. We should get the lowpri thread. */
1579 RL(n = __futex(&futex_word, FUTEX_WAKE | FUTEX_PRIVATE_FLAG,
1580 1, NULL, NULL, 0, 0));
1581 ATF_REQUIRE_EQ_MSG(n, 1, "n=%d woken", n);
1582 sleep(1);
1583 for (tries = 0; tries < 5; tries++) {
1584 membar_sync();
1585 if (nlwps_running == 0)
1586 break;
1587 sleep(1);
1588 }
1589 membar_sync();
1590 ATF_REQUIRE_EQ_MSG(nlwps_running, 0, "nlwps_running=%u",
1591 nlwps_running);
1592 RL(_lwp_wait(0, &waiter));
1593 ATF_REQUIRE_EQ_MSG(waiter, lwp_data[0].threadid,
1594 "waiter=%ld lwp_data[0].threadid=%ld",
1595 (long)waiter, (long)lwp_data[0].threadid);
1596 }
1597
1598 ATF_TC_WITH_CLEANUP(futex_wake_highest_pri);
1599 ATF_TC_HEAD(futex_wake_highest_pri, tc)
1600 {
1601 atf_tc_set_md_var(tc, "descr",
1602 "tests that futex WAKE wakes the highest priority waiter");
1603 atf_tc_set_md_var(tc, "require.user", "root");
1604 }
1605 ATF_TC_BODY(futex_wake_highest_pri, tc)
1606 {
1607 atf_tc_expect_fail("PR kern/55230");
1608 do_test_wake_highest_pri();
1609 }
1610 ATF_TC_CLEANUP(futex_wake_highest_pri, tc)
1611 {
1612 do_cleanup();
1613 }
1614
1615 /*****************************************************************************/
1616
1617 ATF_TP_ADD_TCS(tp)
1618 {
1619 ATF_TP_ADD_TC(tp, futex_basic_wait_wake_private);
1620 ATF_TP_ADD_TC(tp, futex_basic_wait_wake_shared);
1621 ATF_TP_ADD_TC(tp, futex_wait_wake_anon_bs_private);
1622 ATF_TP_ADD_TC(tp, futex_wait_wake_anon_bs_shared);
1623 ATF_TP_ADD_TC(tp, futex_wait_wake_file_bs_private);
1624 ATF_TP_ADD_TC(tp, futex_wait_wake_file_bs_shared);
1625 ATF_TP_ADD_TC(tp, futex_wait_wake_file_bs_cow_private);
1626 ATF_TP_ADD_TC(tp, futex_wait_wake_file_bs_cow_shared);
1627
1628 ATF_TP_ADD_TC(tp, futex_wait_wake_anon_bs_shared_proc);
1629 ATF_TP_ADD_TC(tp, futex_wait_wake_file_bs_shared_proc);
1630
1631 ATF_TP_ADD_TC(tp, futex_wait_pointless_bitset);
1632 ATF_TP_ADD_TC(tp, futex_wait_wake_bitset);
1633
1634 ATF_TP_ADD_TC(tp, futex_wait_timeout_relative);
1635 ATF_TP_ADD_TC(tp, futex_wait_timeout_relative_rt);
1636 ATF_TP_ADD_TC(tp, futex_wait_timeout_deadline);
1637 ATF_TP_ADD_TC(tp, futex_wait_timeout_deadline_rt);
1638
1639 ATF_TP_ADD_TC(tp, futex_wait_evil_unmapped_anon);
1640
1641 ATF_TP_ADD_TC(tp, futex_requeue);
1642 ATF_TP_ADD_TC(tp, futex_cmp_requeue);
1643 ATF_TP_ADD_TC(tp, futex_cmp_requeue_trivial);
1644
1645 ATF_TP_ADD_TC(tp, futex_wake_op_op);
1646 ATF_TP_ADD_TC(tp, futex_wake_op_cmp);
1647
1648 ATF_TP_ADD_TC(tp, futex_wake_highest_pri);
1649
1650 return atf_no_error();
1651 }
1652