Module Name:    src
Committed By:   riastradh
Date:           Fri Apr  8 23:35:52 UTC 2022

Modified Files:
        src/distrib/sets/lists/debug: mi
        src/distrib/sets/lists/tests: mi
        src/etc/mtree: NetBSD.dist.tests
        src/tests/lib/libc: Makefile
Added Files:
        src/tests/lib/libc/membar: Makefile t_dekker.c t_seqlock.c t_spinlock.c

Log Message:
membar_ops(3): Add some automatic tests.

These tests run two threads for five seconds each to try to trigger
races in the event of broken memory barriers.  They run only on
machines with at least two CPUs; on uniprocessor systems there's no
point -- the membars can correctly just be (instruction barrier)
no-ops.


To generate a diff of this commit:
cvs rdiff -u -r1.375 -r1.376 src/distrib/sets/lists/debug/mi
cvs rdiff -u -r1.1191 -r1.1192 src/distrib/sets/lists/tests/mi
cvs rdiff -u -r1.189 -r1.190 src/etc/mtree/NetBSD.dist.tests
cvs rdiff -u -r1.50 -r1.51 src/tests/lib/libc/Makefile
cvs rdiff -u -r0 -r1.1 src/tests/lib/libc/membar/Makefile \
    src/tests/lib/libc/membar/t_dekker.c \
    src/tests/lib/libc/membar/t_seqlock.c \
    src/tests/lib/libc/membar/t_spinlock.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/distrib/sets/lists/debug/mi
diff -u src/distrib/sets/lists/debug/mi:1.375 src/distrib/sets/lists/debug/mi:1.376
--- src/distrib/sets/lists/debug/mi:1.375	Wed Apr  6 14:28:44 2022
+++ src/distrib/sets/lists/debug/mi	Fri Apr  8 23:35:51 2022
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.375 2022/04/06 14:28:44 reinoud Exp $
+# $NetBSD: mi,v 1.376 2022/04/08 23:35:51 riastradh Exp $
 ./etc/mtree/set.debug                           comp-sys-root
 ./usr/lib					comp-sys-usr		compatdir
 ./usr/lib/i18n/libBIG5_g.a			comp-c-debuglib		debuglib,compatfile
@@ -2062,6 +2062,9 @@
 ./usr/libdata/debug/usr/tests/lib/libc/locale/t_wcstod.debug		tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/locale/t_wctomb.debug		tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/locale/t_wctype.debug		tests-lib-debug		debug,atf,compattestfile
+./usr/libdata/debug/usr/tests/lib/libc/membar/t_dekker.debug		tests-lib-debug		debug,atf,compattestfile
+./usr/libdata/debug/usr/tests/lib/libc/membar/t_seqlock.debug		tests-lib-debug		debug,atf,compattestfile
+./usr/libdata/debug/usr/tests/lib/libc/membar/t_spinlock.debug		tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/misc/t_ubsan.debug		tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/misc/t_ubsanxx.debug		tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/net/getaddrinfo/h_gai.debug	tests-lib-debug		debug,atf,compattestfile

Index: src/distrib/sets/lists/tests/mi
diff -u src/distrib/sets/lists/tests/mi:1.1191 src/distrib/sets/lists/tests/mi:1.1192
--- src/distrib/sets/lists/tests/mi:1.1191	Fri Apr  8 21:29:29 2022
+++ src/distrib/sets/lists/tests/mi	Fri Apr  8 23:35:52 2022
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.1191 2022/04/08 21:29:29 rillig Exp $
+# $NetBSD: mi,v 1.1192 2022/04/08 23:35:52 riastradh Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -104,6 +104,7 @@
 ./usr/libdata/debug/usr/tests/lib/libc/ieeefp		tests-obsolete		obsolete
 ./usr/libdata/debug/usr/tests/lib/libc/inet		tests-lib-debug		compattestfile,atf
 ./usr/libdata/debug/usr/tests/lib/libc/locale		tests-lib-debug		compattestfile,atf
+./usr/libdata/debug/usr/tests/lib/libc/membar		tests-lib-debug		compattestfile,atf
 ./usr/libdata/debug/usr/tests/lib/libc/misc		tests-lib-debug		compattestfile,atf
 ./usr/libdata/debug/usr/tests/lib/libc/net		tests-lib-debug		compattestfile,atf
 ./usr/libdata/debug/usr/tests/lib/libc/net/getaddrinfo	tests-lib-debug		compattestfile,atf
@@ -2955,6 +2956,12 @@
 ./usr/tests/lib/libc/locale/t_wcstod			tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/locale/t_wctomb			tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/locale/t_wctype			tests-lib-tests		compattestfile,atf
+./usr/tests/lib/libc/membar				tests-lib-tests		compattestfile,atf
+./usr/tests/lib/libc/membar/Atffile			tests-lib-tests		compattestfile,atf
+./usr/tests/lib/libc/membar/Kyuafile			tests-lib-tests		compattestfile,atf,kyua
+./usr/tests/lib/libc/membar/t_dekker			tests-lib-tests		compattestfile,atf
+./usr/tests/lib/libc/membar/t_seqlock			tests-lib-tests		compattestfile,atf
+./usr/tests/lib/libc/membar/t_spinlock			tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/misc				tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/misc/Atffile			tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/misc/Kyuafile			tests-lib-tests		compattestfile,atf,kyua

Index: src/etc/mtree/NetBSD.dist.tests
diff -u src/etc/mtree/NetBSD.dist.tests:1.189 src/etc/mtree/NetBSD.dist.tests:1.190
--- src/etc/mtree/NetBSD.dist.tests:1.189	Fri Apr  8 23:14:10 2022
+++ src/etc/mtree/NetBSD.dist.tests	Fri Apr  8 23:35:52 2022
@@ -1,4 +1,4 @@
-#	$NetBSD: NetBSD.dist.tests,v 1.189 2022/04/08 23:14:10 riastradh Exp $
+#	$NetBSD: NetBSD.dist.tests,v 1.190 2022/04/08 23:35:52 riastradh Exp $
 
 ./usr/libdata/debug/usr/tests
 ./usr/libdata/debug/usr/tests/atf
@@ -85,6 +85,7 @@
 ./usr/libdata/debug/usr/tests/lib/libc/hash
 ./usr/libdata/debug/usr/tests/lib/libc/inet
 ./usr/libdata/debug/usr/tests/lib/libc/locale
+./usr/libdata/debug/usr/tests/lib/libc/membar
 ./usr/libdata/debug/usr/tests/lib/libc/misc
 ./usr/libdata/debug/usr/tests/lib/libc/net
 ./usr/libdata/debug/usr/tests/lib/libc/net/getaddrinfo
@@ -287,6 +288,7 @@
 ./usr/tests/lib/libc/hash/data
 ./usr/tests/lib/libc/inet
 ./usr/tests/lib/libc/locale
+./usr/tests/lib/libc/membar
 ./usr/tests/lib/libc/misc
 ./usr/tests/lib/libc/net
 ./usr/tests/lib/libc/net/getaddrinfo

Index: src/tests/lib/libc/Makefile
diff -u src/tests/lib/libc/Makefile:1.50 src/tests/lib/libc/Makefile:1.51
--- src/tests/lib/libc/Makefile:1.50	Sun Mar  8 22:08:46 2020
+++ src/tests/lib/libc/Makefile	Fri Apr  8 23:35:52 2022
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.50 2020/03/08 22:08:46 mgorny Exp $
+# $NetBSD: Makefile,v 1.51 2022/04/08 23:35:52 riastradh Exp $
 
 .include "Makefile.inc"
 .include <bsd.own.mk>
@@ -6,8 +6,27 @@
 SUBDIR+=	tls_dso .WAIT sync
 
 TESTS_SUBDIRS+=	atomic
-TESTS_SUBDIRS+=	c063 db gen hash inet locale misc net nls regex rpc setjmp
-TESTS_SUBDIRS+=	stdlib stdio string sys termios time tls ttyio
+TESTS_SUBDIRS+=	c063
+TESTS_SUBDIRS+=	db
+TESTS_SUBDIRS+=	gen
+TESTS_SUBDIRS+=	hash
+TESTS_SUBDIRS+=	inet
+TESTS_SUBDIRS+=	locale
+TESTS_SUBDIRS+=	membar
+TESTS_SUBDIRS+=	misc
+TESTS_SUBDIRS+=	net
+TESTS_SUBDIRS+=	nls
+TESTS_SUBDIRS+=	regex
+TESTS_SUBDIRS+=	rpc
+TESTS_SUBDIRS+=	setjmp
+TESTS_SUBDIRS+=	stdio
+TESTS_SUBDIRS+=	stdlib
+TESTS_SUBDIRS+=	string
+TESTS_SUBDIRS+=	sys
+TESTS_SUBDIRS+=	termios
+TESTS_SUBDIRS+=	time
+TESTS_SUBDIRS+=	tls
+TESTS_SUBDIRS+=	ttyio
 
 .if ${HAVE_SSP} == "yes"
 TESTS_SUBDIRS+=	ssp

Added files:

Index: src/tests/lib/libc/membar/Makefile
diff -u /dev/null src/tests/lib/libc/membar/Makefile:1.1
--- /dev/null	Fri Apr  8 23:35:52 2022
+++ src/tests/lib/libc/membar/Makefile	Fri Apr  8 23:35:52 2022
@@ -0,0 +1,15 @@
+#	$NetBSD: Makefile,v 1.1 2022/04/08 23:35:52 riastradh Exp $
+
+.include <bsd.own.mk>
+
+TESTSDIR=	${TESTSBASE}/lib/libc/membar
+
+TESTS_C+=	t_dekker
+TESTS_C+=	t_seqlock
+TESTS_C+=	t_spinlock
+
+LDADD+=		-pthread
+
+WARNS=		6
+
+.include <bsd.test.mk>
Index: src/tests/lib/libc/membar/t_dekker.c
diff -u /dev/null src/tests/lib/libc/membar/t_dekker.c:1.1
--- /dev/null	Fri Apr  8 23:35:52 2022
+++ src/tests/lib/libc/membar/t_dekker.c	Fri Apr  8 23:35:52 2022
@@ -0,0 +1,172 @@
+/*	$NetBSD: t_dekker.c,v 1.1 2022/04/08 23:35:52 riastradh Exp $	*/
+
+/*-
+ * Copyright (c) 2022 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_dekker.c,v 1.1 2022/04/08 23:35:52 riastradh Exp $");
+
+#include <sys/atomic.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <assert.h>
+#include <atf-c.h>
+#include <err.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/* XXX */
+#define	membar_acquire()	membar_enter()
+#define	membar_release()	membar_exit()
+
+#ifdef	BROKEN_SYNC
+#undef	membar_sync
+#define	membar_sync()	asm volatile("" ::: "memory")
+#endif	/* BROKEN_SYNC */
+
+volatile sig_atomic_t times_up;
+
+volatile unsigned turn __aligned(COHERENCY_UNIT);
+volatile struct {
+	unsigned v;
+} __aligned(COHERENCY_UNIT) waiting[2];
+__CTASSERT(sizeof(waiting) == 2*COHERENCY_UNIT);
+
+volatile uint64_t C;
+uint64_t TC[2];
+
+static void
+lock(unsigned me)
+{
+
+top:	waiting[me].v = 1;
+	membar_sync();
+	while (waiting[1 - me].v) {
+		if (turn != me) {
+			waiting[me].v = 0;
+			while (turn != me)
+				continue;
+			goto top;
+		}
+	}
+	membar_acquire();
+}
+
+static void
+unlock(unsigned me)
+{
+
+	membar_release();
+	turn = 1 - me;
+	waiting[me].v = 0;
+
+	/*
+	 * Not needed for correctness, but this helps on Cavium Octeon
+	 * cnMIPS CPUs which require issuing a sync plunger to unclog
+	 * store buffers which can otherwise stay clogged for hundreds
+	 * of thousands of cycles, giving very little concurrency to
+	 * this test.
+	 */
+	membar_producer();
+}
+
+static void
+alarm_handler(int signo)
+{
+
+	(void)signo;
+	times_up = 1;
+}
+
+static void *
+thread(void *cookie)
+{
+	unsigned me = (unsigned)(uintptr_t)cookie;
+	uint64_t C_local = 0;
+
+	while (!times_up) {
+		C_local++;
+		lock(me);
+		C++;
+		unlock(me);
+	}
+
+	TC[me] = C_local;
+
+	return NULL;
+}
+
+ATF_TC(dekker);
+ATF_TC_HEAD(dekker, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Verify membar_sync works for Dekker's algorithm");
+}
+ATF_TC_BODY(dekker, tc)
+{
+	pthread_t t[2];
+	unsigned i;
+	int ncpu;
+	size_t ncpulen = sizeof(ncpu);
+	int error;
+
+	if (sysctlbyname("hw.ncpu", &ncpu, &ncpulen, NULL, 0) == -1)
+		atf_tc_fail("hw.ncpu: (%d) %s", errno, strerror(errno));
+	assert(ncpulen == sizeof(ncpu));
+	if (ncpu == 1)
+		atf_tc_skip("membar tests are only for multicore systems");
+
+	if (signal(SIGALRM, alarm_handler) == SIG_ERR)
+		err(1, "signal(SIGALRM");
+	alarm(5);
+	for (i = 0; i < 2; i++) {
+		error = pthread_create(&t[i], NULL, &thread,
+		    (void *)(uintptr_t)i);
+		if (error)
+			errc(1, error, "pthread_create");
+	}
+	for (i = 0; i < 2; i++) {
+		error = pthread_join(t[i], NULL);
+		if (error)
+			errc(1, error, "pthread_join");
+	}
+	ATF_REQUIRE_MSG(C == TC[0] + TC[1],
+	    "%"PRIu64" != %"PRIu64" + %"PRIu64" (off by %"PRIdMAX")",
+	    C, TC[0], TC[1], TC[0] + TC[1] - C);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+	ATF_TP_ADD_TC(tp, dekker);
+	return atf_no_error();
+}
Index: src/tests/lib/libc/membar/t_seqlock.c
diff -u /dev/null src/tests/lib/libc/membar/t_seqlock.c:1.1
--- /dev/null	Fri Apr  8 23:35:52 2022
+++ src/tests/lib/libc/membar/t_seqlock.c	Fri Apr  8 23:35:52 2022
@@ -0,0 +1,197 @@
+/*	$NetBSD: t_seqlock.c,v 1.1 2022/04/08 23:35:52 riastradh Exp $	*/
+
+/*-
+ * Copyright (c) 2022 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_seqlock.c,v 1.1 2022/04/08 23:35:52 riastradh Exp $");
+
+#include <sys/atomic.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <assert.h>
+#include <atf-c.h>
+#include <err.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef	BROKEN_PRODUCER
+#undef	membar_producer
+#define	membar_producer()	asm volatile("" ::: "memory")
+#endif	/* BROKEN_PRODUCER */
+
+#ifdef	BROKEN_CONSUMER
+#undef	membar_consumer
+#define	membar_consumer()	asm volatile("" ::: "memory")
+#endif	/* BROKEN_CONSUMER */
+
+volatile sig_atomic_t times_up;
+
+volatile unsigned version;
+
+volatile struct {
+	uint64_t s;
+} __aligned(COHERENCY_UNIT) stats[16];
+
+uint64_t results[2];
+
+static void
+alarm_handler(int signo)
+{
+
+	(void)signo;
+	times_up = 1;
+}
+
+static void *
+writer(void *cookie)
+{
+	uint64_t s;
+	unsigned i;
+
+	for (s = 0; !times_up; s++) {
+		version |= 1;
+		membar_producer();
+		for (i = __arraycount(stats); i --> 0;)
+			stats[i].s = s;
+		membar_producer();
+		version |= 1;
+		version += 1;
+
+		/*
+		 * Not needed for correctness, but this helps on Cavium
+		 * Octeon cnMIPS CPUs which require issuing a sync
+		 * plunger to unclog store buffers which can otherwise
+		 * stay clogged for hundreds of thousands of cycles,
+		 * giving very little concurrency to this test.
+		 * Without this, the reader spends most of its time
+		 * thinking an update is in progress.
+		 */
+		membar_producer();
+	}
+
+	return NULL;
+}
+
+static void *
+reader(void *cookie)
+{
+	uint64_t s;
+	unsigned v, result, i;
+	volatile unsigned *vp = &version;
+	volatile uint64_t t;
+
+	while (!times_up) {
+		/*
+		 * Prime the cache with possibly stale garbage.
+		 */
+		t = stats[0].s;
+
+		/*
+		 * Normally we would do
+		 *
+		 *	while ((v = version) & 1)
+		 *		SPINLOCK_BACKOFF_HOOK;
+		 *
+		 * to avoid copying out a version that we know is in
+		 * flux, but it's not wrong to copy out a version in
+		 * flux -- just wasteful.
+		 *
+		 * Reading the version unconditionally, and then
+		 * copying out the record, better exercises plausible
+		 * bugs in PowerPC membars based on `isync' that
+		 * provide the desired ordering only if separated from
+		 * the load by a conditional branch based on the load.
+		 */
+		v = *vp;
+		membar_consumer();
+		s = stats[0].s;
+		for (result = 0, i = 1; i < __arraycount(stats); i++)
+			result |= (s != stats[i].s);
+		membar_consumer();
+		if ((v & ~1u) != *vp)
+			continue;
+		results[result]++;
+	}
+
+	(void)t;
+
+	return NULL;
+}
+
+ATF_TC(seqlock);
+ATF_TC_HEAD(seqlock, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Verify membar_producer/consumer work for seqlocks");
+}
+ATF_TC_BODY(seqlock, tc)
+{
+	pthread_t t[2];
+	void *(*start[2])(void *) = { &reader, &writer };
+	unsigned i;
+	int ncpu;
+	size_t ncpulen = sizeof(ncpu);
+	int error;
+
+	if (sysctlbyname("hw.ncpu", &ncpu, &ncpulen, NULL, 0) == -1)
+		atf_tc_fail("hw.ncpu: (%d) %s", errno, strerror(errno));
+	assert(ncpulen == sizeof(ncpu));
+	if (ncpu == 1)
+		atf_tc_skip("membar tests are only for multicore systems");
+
+	if (signal(SIGALRM, alarm_handler) == SIG_ERR)
+		err(1, "signal(SIGALRM");
+	alarm(5);
+	for (i = 0; i < 2; i++) {
+		error = pthread_create(&t[i], NULL, start[i],
+		    (void *)(uintptr_t)i);
+		if (error)
+			errc(1, error, "pthread_create");
+	}
+	for (i = 0; i < 2; i++) {
+		error = pthread_join(t[i], NULL);
+		if (error)
+			errc(1, error, "pthread_join");
+	}
+	ATF_REQUIRE(results[0] != 0);
+	ATF_REQUIRE_MSG(results[1] == 0,
+	    "%"PRIu64" good snapshots, %"PRIu64" bad snapshots",
+	    results[0], results[1]);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+	ATF_TP_ADD_TC(tp, seqlock);
+	return atf_no_error();
+}
Index: src/tests/lib/libc/membar/t_spinlock.c
diff -u /dev/null src/tests/lib/libc/membar/t_spinlock.c:1.1
--- /dev/null	Fri Apr  8 23:35:52 2022
+++ src/tests/lib/libc/membar/t_spinlock.c	Fri Apr  8 23:35:52 2022
@@ -0,0 +1,164 @@
+/*	$NetBSD: t_spinlock.c,v 1.1 2022/04/08 23:35:52 riastradh Exp $	*/
+
+/*-
+ * Copyright (c) 2022 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_spinlock.c,v 1.1 2022/04/08 23:35:52 riastradh Exp $");
+
+#include <sys/atomic.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <assert.h>
+#include <atf-c.h>
+#include <err.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/* XXX */
+#define	membar_acquire()	membar_enter()
+#define	membar_release()	membar_exit()
+
+#ifdef	BROKEN_ACQUIRE
+#undef	membar_acquire
+#define	membar_acquire()	asm volatile("" ::: "memory")
+#endif	/* BROKEN_ACQUIRE */
+
+#ifdef	BROKEN_RELEASE
+#undef	membar_release
+#define	membar_release()	asm volatile("" ::: "memory")
+#endif	/* BROKEN_RELEASE */
+
+volatile sig_atomic_t times_up;
+
+volatile unsigned lockbit __aligned(COHERENCY_UNIT);
+
+volatile struct {
+	uint64_t v;
+} __aligned(COHERENCY_UNIT) C[8];
+uint64_t TC[2];
+
+static void
+lock(void)
+{
+
+	while (atomic_swap_uint(&lockbit, 1))
+		continue;
+	membar_acquire();
+}
+
+static void
+unlock(void)
+{
+
+	membar_release();
+	lockbit = 0;
+}
+
+static void
+alarm_handler(int signo)
+{
+
+	(void)signo;
+	times_up = 1;
+}
+
+static void *
+thread(void *cookie)
+{
+	unsigned me = (unsigned)(uintptr_t)cookie;
+	uint64_t C_local = 0, C0[__arraycount(C)];
+	unsigned i;
+
+	while (!times_up) {
+		C_local++;
+		lock();
+		for (i = 0; i < __arraycount(C); i++)
+			C0[i] = C[i].v;
+		__insn_barrier();
+		for (i = __arraycount(C); i --> 0;)
+			C[i].v = C0[i] + 1;
+		unlock();
+	}
+
+	TC[me] = C_local;
+
+	return NULL;
+}
+
+ATF_TC(spinlock);
+ATF_TC_HEAD(spinlock, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Verify membar_acquire/release work for spin locks");
+}
+ATF_TC_BODY(spinlock, tc)
+{
+	pthread_t t[2];
+	unsigned i;
+	int ncpu;
+	size_t ncpulen = sizeof(ncpu);
+	int error;
+
+	if (sysctlbyname("hw.ncpu", &ncpu, &ncpulen, NULL, 0) == -1)
+		atf_tc_fail("hw.ncpu: (%d) %s", errno, strerror(errno));
+	assert(ncpulen == sizeof(ncpu));
+	if (ncpu == 1)
+		atf_tc_skip("membar tests are only for multicore systems");
+
+	if (signal(SIGALRM, alarm_handler) == SIG_ERR)
+		err(1, "signal(SIGALRM");
+	alarm(5);
+	for (i = 0; i < 2; i++) {
+		error = pthread_create(&t[i], NULL, &thread,
+		    (void *)(uintptr_t)i);
+		if (error)
+			errc(1, error, "pthread_create");
+	}
+	for (i = 0; i < 2; i++) {
+		error = pthread_join(t[i], NULL);
+		if (error)
+			errc(1, error, "pthread_join");
+	}
+	for (i = 0; i < __arraycount(C); i++) {
+		ATF_CHECK_MSG(C[i].v == TC[0] + TC[1], "%d: "
+		    "%"PRIu64" != %"PRIu64" + %"PRIu64" (off by %"PRIdMAX")",
+		    i, C[i].v, TC[0], TC[1], TC[0] + TC[1] - C[i].v);
+	}
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+	ATF_TP_ADD_TC(tp, spinlock);
+	return atf_no_error();
+}

Reply via email to