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