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
create_lwp_waiter(struct lwp_data * d)107 create_lwp_waiter(struct lwp_data *d)
108 {
109           RL(_lwp_create(&d->context, 0, &d->lwpid));
110 }
111 
112 static void
exit_lwp_waiter(void)113 exit_lwp_waiter(void)
114 {
115           _lwp_exit();
116 }
117 
118 static void
reap_lwp_waiter(struct lwp_data * d)119 reap_lwp_waiter(struct lwp_data *d)
120 {
121           RL(_lwp_wait(d->lwpid, NULL));
122 }
123 
124 static void
create_proc_waiter(struct lwp_data * d)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
exit_proc_waiter(void)138 exit_proc_waiter(void)
139 {
140           _exit(0);
141 }
142 
143 static void
reap_proc_waiter(struct lwp_data * d)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
setup_lwp_context(struct lwp_data * d,void (* func)(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
simple_test_waiter_lwp(void * arg)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
verify_zero_bs(void)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
create_bs(int map_flags)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
cleanup_bs(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
do_cleanup(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
wait_wake_test_waiter_lwp(void * arg)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
do_futex_wait_wake_test(volatile int * futex_ptr,volatile int * error_ptr,void (* create_func)(struct lwp_data *),void (* exit_func)(void),void (* reap_func)(struct lwp_data *),int flags)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);
ATF_TC_HEAD(futex_basic_wait_wake_private,tc)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 }
ATF_TC_BODY(futex_basic_wait_wake_private,tc)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 }
ATF_TC_CLEANUP(futex_basic_wait_wake_private,tc)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);
ATF_TC_HEAD(futex_basic_wait_wake_shared,tc)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 }
ATF_TC_BODY(futex_basic_wait_wake_shared,tc)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 }
ATF_TC_CLEANUP(futex_basic_wait_wake_shared,tc)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);
ATF_TC_HEAD(futex_wait_wake_anon_bs_private,tc)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 }
ATF_TC_BODY(futex_wait_wake_anon_bs_private,tc)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 }
ATF_TC_CLEANUP(futex_wait_wake_anon_bs_private,tc)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);
ATF_TC_HEAD(futex_wait_wake_anon_bs_shared,tc)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 }
ATF_TC_BODY(futex_wait_wake_anon_bs_shared,tc)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 }
ATF_TC_CLEANUP(futex_wait_wake_anon_bs_shared,tc)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);
ATF_TC_HEAD(futex_wait_wake_file_bs_private,tc)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 }
ATF_TC_BODY(futex_wait_wake_file_bs_private,tc)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 }
ATF_TC_CLEANUP(futex_wait_wake_file_bs_private,tc)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);
ATF_TC_HEAD(futex_wait_wake_file_bs_cow_private,tc)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 }
ATF_TC_BODY(futex_wait_wake_file_bs_cow_private,tc)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 }
ATF_TC_CLEANUP(futex_wait_wake_file_bs_cow_private,tc)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);
ATF_TC_HEAD(futex_wait_wake_file_bs_shared,tc)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 }
ATF_TC_BODY(futex_wait_wake_file_bs_shared,tc)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 }
ATF_TC_CLEANUP(futex_wait_wake_file_bs_shared,tc)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);
ATF_TC_HEAD(futex_wait_wake_file_bs_cow_shared,tc)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 }
ATF_TC_BODY(futex_wait_wake_file_bs_cow_shared,tc)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 }
ATF_TC_CLEANUP(futex_wait_wake_file_bs_cow_shared,tc)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);
ATF_TC_HEAD(futex_wait_wake_anon_bs_shared_proc,tc)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 }
ATF_TC_BODY(futex_wait_wake_anon_bs_shared_proc,tc)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 }
ATF_TC_CLEANUP(futex_wait_wake_anon_bs_shared_proc,tc)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);
ATF_TC_HEAD(futex_wait_wake_file_bs_shared_proc,tc)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 }
ATF_TC_BODY(futex_wait_wake_file_bs_shared_proc,tc)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 }
ATF_TC_CLEANUP(futex_wait_wake_file_bs_shared_proc,tc)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);
ATF_TC_HEAD(futex_wait_pointless_bitset,tc)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 }
ATF_TC_BODY(futex_wait_pointless_bitset,tc)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
do_futex_wait_wake_bitset_test(int flags)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);
ATF_TC_HEAD(futex_wait_wake_bitset,tc)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 }
ATF_TC_BODY(futex_wait_wake_bitset,tc)763 ATF_TC_BODY(futex_wait_wake_bitset, tc)
764 {
765           do_futex_wait_wake_bitset_test(FUTEX_PRIVATE_FLAG);
766 }
ATF_TC_CLEANUP(futex_wait_wake_bitset,tc)767 ATF_TC_CLEANUP(futex_wait_wake_bitset, tc)
768 {
769           do_cleanup();
770 }
771 
772 /*****************************************************************************/
773 
774 static void
do_futex_requeue_test(int flags,int op)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);
ATF_TC_HEAD(futex_requeue,tc)911 ATF_TC_HEAD(futex_requeue, tc)
912 {
913           atf_tc_set_md_var(tc, "descr",
914               "tests futex REQUEUE operations");
915 }
ATF_TC_BODY(futex_requeue,tc)916 ATF_TC_BODY(futex_requeue, tc)
917 {
918           do_futex_requeue_test(FUTEX_PRIVATE_FLAG, FUTEX_REQUEUE);
919 }
ATF_TC_CLEANUP(futex_requeue,tc)920 ATF_TC_CLEANUP(futex_requeue, tc)
921 {
922           do_cleanup();
923 }
924 
925 ATF_TC_WITH_CLEANUP(futex_cmp_requeue);
ATF_TC_HEAD(futex_cmp_requeue,tc)926 ATF_TC_HEAD(futex_cmp_requeue, tc)
927 {
928           atf_tc_set_md_var(tc, "descr",
929               "tests futex CMP_REQUEUE operations");
930 }
ATF_TC_BODY(futex_cmp_requeue,tc)931 ATF_TC_BODY(futex_cmp_requeue, tc)
932 {
933           do_futex_requeue_test(FUTEX_PRIVATE_FLAG, FUTEX_CMP_REQUEUE);
934 }
ATF_TC_CLEANUP(futex_cmp_requeue,tc)935 ATF_TC_CLEANUP(futex_cmp_requeue, tc)
936 {
937           do_cleanup();
938 }
939 
940 ATF_TC(futex_cmp_requeue_trivial);
ATF_TC_HEAD(futex_cmp_requeue_trivial,tc)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 }
ATF_TC_BODY(futex_cmp_requeue_trivial,tc)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
do_futex_wake_op_op_test(int flags)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);
ATF_TC_HEAD(futex_wake_op_op,tc)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 }
ATF_TC_BODY(futex_wake_op_op,tc)1070 ATF_TC_BODY(futex_wake_op_op, tc)
1071 {
1072           do_futex_wake_op_op_test(FUTEX_PRIVATE_FLAG);
1073 }
ATF_TC_CLEANUP(futex_wake_op_op,tc)1074 ATF_TC_CLEANUP(futex_wake_op_op, tc)
1075 {
1076           do_cleanup();
1077 }
1078 
1079 static void
create_wake_op_test_lwps(int flags)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
reap_wake_op_test_lwps(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
do_futex_wake_op_cmp_test(int flags)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);
ATF_TC_HEAD(futex_wake_op_cmp,tc)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 }
ATF_TC_BODY(futex_wake_op_cmp,tc)1288 ATF_TC_BODY(futex_wake_op_cmp, tc)
1289 {
1290           do_futex_wake_op_cmp_test(FUTEX_PRIVATE_FLAG);
1291 }
ATF_TC_CLEANUP(futex_wake_op_cmp,tc)1292 ATF_TC_CLEANUP(futex_wake_op_cmp, tc)
1293 {
1294           do_cleanup();
1295 }
1296 
1297 /*****************************************************************************/
1298 
1299 
1300 
1301 /*****************************************************************************/
1302 
1303 static void
do_futex_wait_timeout(bool relative,clockid_t clock)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);
ATF_TC_HEAD(futex_wait_timeout_relative,tc)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 }
ATF_TC_BODY(futex_wait_timeout_relative,tc)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);
ATF_TC_HEAD(futex_wait_timeout_relative_rt,tc)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 }
ATF_TC_BODY(futex_wait_timeout_relative_rt,tc)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);
ATF_TC_HEAD(futex_wait_timeout_deadline,tc)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 }
ATF_TC_BODY(futex_wait_timeout_deadline,tc)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);
ATF_TC_HEAD(futex_wait_timeout_deadline_rt,tc)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 }
ATF_TC_BODY(futex_wait_timeout_deadline_rt,tc)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
sig_noop(int sig __unused)1389 sig_noop(int sig __unused)
1390 {
1391 }
1392 
1393 static void (*old_act)(int) = SIG_DFL;
1394 
1395 static void
do_futex_wait_evil_unmapped(int map_flags)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);
ATF_TC_HEAD(futex_wait_evil_unmapped_anon,tc)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 }
ATF_TC_BODY(futex_wait_evil_unmapped_anon,tc)1444 ATF_TC_BODY(futex_wait_evil_unmapped_anon, tc)
1445 {
1446           do_futex_wait_evil_unmapped(MAP_ANON);
1447 }
ATF_TC_CLEANUP(futex_wait_evil_unmapped_anon,tc)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
lowpri_simple_test_waiter_lwp(void * arg)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
highpri_simple_test_waiter_lwp(void * arg)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
do_test_wake_highest_pri(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);
ATF_TC_HEAD(futex_wake_highest_pri,tc)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 }
ATF_TC_BODY(futex_wake_highest_pri,tc)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 }
ATF_TC_CLEANUP(futex_wake_highest_pri,tc)1606 ATF_TC_CLEANUP(futex_wake_highest_pri, tc)
1607 {
1608           do_cleanup();
1609 }
1610 
1611 /*****************************************************************************/
1612 
ATF_TP_ADD_TCS(tp)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