xref: /freebsd/lib/libthr/tests/umtx_op_test.c (revision 623d432b154a7fc0bd75f3ca221114808b6e9113)
14be0a1b5SKyle Evans /*-
24be0a1b5SKyle Evans  * SPDX-License-Identifier: BSD-2-Clause
34be0a1b5SKyle Evans  *
44be0a1b5SKyle Evans  * Copyright (c) 2020 Kyle Evans <kevans@FreeBSD.org>
54be0a1b5SKyle Evans  *
64be0a1b5SKyle Evans  * Redistribution and use in source and binary forms, with or without
74be0a1b5SKyle Evans  * modification, are permitted provided that the following conditions
84be0a1b5SKyle Evans  * are met:
94be0a1b5SKyle Evans  * 1. Redistributions of source code must retain the above copyright
104be0a1b5SKyle Evans  *    notice, this list of conditions and the following disclaimer.
114be0a1b5SKyle Evans  * 2. Redistributions in binary form must reproduce the above copyright
124be0a1b5SKyle Evans  *    notice, this list of conditions and the following disclaimer in the
134be0a1b5SKyle Evans  *    documentation and/or other materials provided with the distribution.
144be0a1b5SKyle Evans  *
154be0a1b5SKyle Evans  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
164be0a1b5SKyle Evans  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
174be0a1b5SKyle Evans  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
184be0a1b5SKyle Evans  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
194be0a1b5SKyle Evans  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
204be0a1b5SKyle Evans  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
214be0a1b5SKyle Evans  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
224be0a1b5SKyle Evans  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
234be0a1b5SKyle Evans  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
244be0a1b5SKyle Evans  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
254be0a1b5SKyle Evans  * SUCH DAMAGE.
264be0a1b5SKyle Evans  */
274be0a1b5SKyle Evans 
284be0a1b5SKyle Evans #include <sys/types.h>
294be0a1b5SKyle Evans #include <sys/umtx.h>
304be0a1b5SKyle Evans 
314be0a1b5SKyle Evans #include <pthread.h>
324be0a1b5SKyle Evans 
334be0a1b5SKyle Evans #include <atf-c.h>
344be0a1b5SKyle Evans 
354be0a1b5SKyle Evans /*
364be0a1b5SKyle Evans  * This is an implementation detail of _umtx_op(2), pulled from
374be0a1b5SKyle Evans  * sys/kern/kern_umtx.c.  The relevant bug observed that requests above the
38*623d432bSWarner Losh  * batch size would not function as intended, so it's important that this
394be0a1b5SKyle Evans  * reflects the BATCH_SIZE configured there.
404be0a1b5SKyle Evans  */
414be0a1b5SKyle Evans #define	UMTX_OP_BATCH_SIZE	128
424be0a1b5SKyle Evans #define THREAD_COUNT		((UMTX_OP_BATCH_SIZE * 3) / 2)
434be0a1b5SKyle Evans 
444be0a1b5SKyle Evans static pthread_mutex_t static_mutex = PTHREAD_MUTEX_INITIALIZER;
454be0a1b5SKyle Evans 
464be0a1b5SKyle Evans static int batched_waiting;
474be0a1b5SKyle Evans 
484be0a1b5SKyle Evans static void *
batching_threadfunc(void * arg)494be0a1b5SKyle Evans batching_threadfunc(void *arg)
504be0a1b5SKyle Evans {
514be0a1b5SKyle Evans 
524be0a1b5SKyle Evans 	pthread_mutex_lock(&static_mutex);
534be0a1b5SKyle Evans 	++batched_waiting;
544be0a1b5SKyle Evans 	pthread_mutex_unlock(&static_mutex);
554be0a1b5SKyle Evans 	_umtx_op(arg, UMTX_OP_WAIT_UINT_PRIVATE, 0, NULL, NULL);
564be0a1b5SKyle Evans 
574be0a1b5SKyle Evans 	return (NULL);
584be0a1b5SKyle Evans }
594be0a1b5SKyle Evans 
604be0a1b5SKyle Evans ATF_TC(batching);
ATF_TC_HEAD(batching,tc)614be0a1b5SKyle Evans ATF_TC_HEAD(batching, tc)
624be0a1b5SKyle Evans {
634be0a1b5SKyle Evans 	atf_tc_set_md_var(tc, "descr",
644be0a1b5SKyle Evans 	    "Checks batching of UMTX_OP_NWAKE_PRIVATE");
654be0a1b5SKyle Evans }
ATF_TC_BODY(batching,tc)664be0a1b5SKyle Evans ATF_TC_BODY(batching, tc)
674be0a1b5SKyle Evans {
684be0a1b5SKyle Evans 	uintptr_t addrs[THREAD_COUNT];
694be0a1b5SKyle Evans 	uint32_t vals[THREAD_COUNT];
704be0a1b5SKyle Evans 	pthread_t threads[THREAD_COUNT];
714be0a1b5SKyle Evans 
724be0a1b5SKyle Evans 	for (int i = 0; i < THREAD_COUNT; i++) {
734be0a1b5SKyle Evans 		addrs[i] = (uintptr_t)&vals[i];
744be0a1b5SKyle Evans 		vals[i] = 0;
754be0a1b5SKyle Evans 		pthread_create(&threads[i], NULL, batching_threadfunc,
764be0a1b5SKyle Evans 		    &vals[i]);
774be0a1b5SKyle Evans 	}
784be0a1b5SKyle Evans 
794be0a1b5SKyle Evans 	pthread_mutex_lock(&static_mutex);
804be0a1b5SKyle Evans 	while (batched_waiting != THREAD_COUNT) {
814be0a1b5SKyle Evans 		pthread_mutex_unlock(&static_mutex);
824be0a1b5SKyle Evans 		pthread_yield();
834be0a1b5SKyle Evans 		pthread_mutex_lock(&static_mutex);
844be0a1b5SKyle Evans 	}
854be0a1b5SKyle Evans 
864be0a1b5SKyle Evans 	/*
874be0a1b5SKyle Evans 	 * Spin for another .50 seconds to make sure they're all safely in the
884be0a1b5SKyle Evans 	 * kernel.
894be0a1b5SKyle Evans 	 */
904be0a1b5SKyle Evans 	usleep(500000);
914be0a1b5SKyle Evans 
924be0a1b5SKyle Evans 	pthread_mutex_unlock(&static_mutex);
934be0a1b5SKyle Evans 	_umtx_op(addrs, UMTX_OP_NWAKE_PRIVATE, THREAD_COUNT, NULL, NULL);
944be0a1b5SKyle Evans 
954be0a1b5SKyle Evans 	for (int i = 0; i < THREAD_COUNT; i++) {
964be0a1b5SKyle Evans 		ATF_REQUIRE_EQ(0, pthread_join(threads[i], NULL));
974be0a1b5SKyle Evans 	}
984be0a1b5SKyle Evans }
994be0a1b5SKyle Evans 
ATF_TP_ADD_TCS(tp)1004be0a1b5SKyle Evans ATF_TP_ADD_TCS(tp)
1014be0a1b5SKyle Evans {
1024be0a1b5SKyle Evans 
1034be0a1b5SKyle Evans 	ATF_TP_ADD_TC(tp, batching);
1044be0a1b5SKyle Evans 	return (atf_no_error());
1054be0a1b5SKyle Evans }
106