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