xref: /netbsd-src/tests/lib/libc/membar/t_dekker.c (revision ea43e3d5a060c14963260a83096fdcc54a9e3672)
1*ea43e3d5Sriastradh /*	$NetBSD: t_dekker.c,v 1.3 2022/04/10 11:36:32 riastradh Exp $	*/
2d4961618Sriastradh 
3d4961618Sriastradh /*-
4d4961618Sriastradh  * Copyright (c) 2022 The NetBSD Foundation, Inc.
5d4961618Sriastradh  * All rights reserved.
6d4961618Sriastradh  *
7d4961618Sriastradh  * Redistribution and use in source and binary forms, with or without
8d4961618Sriastradh  * modification, are permitted provided that the following conditions
9d4961618Sriastradh  * are met:
10d4961618Sriastradh  * 1. Redistributions of source code must retain the above copyright
11d4961618Sriastradh  *    notice, this list of conditions and the following disclaimer.
12d4961618Sriastradh  * 2. Redistributions in binary form must reproduce the above copyright
13d4961618Sriastradh  *    notice, this list of conditions and the following disclaimer in the
14d4961618Sriastradh  *    documentation and/or other materials provided with the distribution.
15d4961618Sriastradh  *
16d4961618Sriastradh  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17d4961618Sriastradh  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18d4961618Sriastradh  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19d4961618Sriastradh  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20d4961618Sriastradh  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21d4961618Sriastradh  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22d4961618Sriastradh  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23d4961618Sriastradh  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24d4961618Sriastradh  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25d4961618Sriastradh  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26d4961618Sriastradh  * POSSIBILITY OF SUCH DAMAGE.
27d4961618Sriastradh  */
28d4961618Sriastradh 
29d4961618Sriastradh #include <sys/cdefs.h>
30*ea43e3d5Sriastradh __RCSID("$NetBSD: t_dekker.c,v 1.3 2022/04/10 11:36:32 riastradh Exp $");
31d4961618Sriastradh 
32d4961618Sriastradh #include <sys/atomic.h>
33d4961618Sriastradh #include <sys/param.h>
34d4961618Sriastradh #include <sys/sysctl.h>
35d4961618Sriastradh 
36d4961618Sriastradh #include <assert.h>
37d4961618Sriastradh #include <atf-c.h>
38d4961618Sriastradh #include <err.h>
39d4961618Sriastradh #include <errno.h>
40d4961618Sriastradh #include <inttypes.h>
41d4961618Sriastradh #include <pthread.h>
42d4961618Sriastradh #include <stdint.h>
43d4961618Sriastradh #include <stdio.h>
44d4961618Sriastradh #include <unistd.h>
45d4961618Sriastradh 
46d4961618Sriastradh #ifdef	BROKEN_SYNC
47d4961618Sriastradh #undef	membar_sync
48d4961618Sriastradh #define	membar_sync()	asm volatile("" ::: "memory")
49d4961618Sriastradh #endif	/* BROKEN_SYNC */
50d4961618Sriastradh 
51d4961618Sriastradh volatile sig_atomic_t times_up;
52d4961618Sriastradh 
53d4961618Sriastradh volatile unsigned turn __aligned(COHERENCY_UNIT);
54d4961618Sriastradh volatile struct {
55d4961618Sriastradh 	unsigned v;
56d4961618Sriastradh } __aligned(COHERENCY_UNIT) waiting[2];
57d4961618Sriastradh __CTASSERT(sizeof(waiting) == 2*COHERENCY_UNIT);
58d4961618Sriastradh 
59d4961618Sriastradh volatile uint64_t C;
60d4961618Sriastradh uint64_t TC[2];
61d4961618Sriastradh 
62d4961618Sriastradh static void
lock(unsigned me)63d4961618Sriastradh lock(unsigned me)
64d4961618Sriastradh {
65d4961618Sriastradh 
66d4961618Sriastradh top:	waiting[me].v = 1;
67d4961618Sriastradh 	membar_sync();
68d4961618Sriastradh 	while (waiting[1 - me].v) {
69d4961618Sriastradh 		if (turn != me) {
70d4961618Sriastradh 			waiting[me].v = 0;
71d4961618Sriastradh 			while (turn != me)
72d4961618Sriastradh 				continue;
73d4961618Sriastradh 			goto top;
74d4961618Sriastradh 		}
75d4961618Sriastradh 	}
76d4961618Sriastradh 	membar_acquire();
77d4961618Sriastradh }
78d4961618Sriastradh 
79d4961618Sriastradh static void
unlock(unsigned me)80d4961618Sriastradh unlock(unsigned me)
81d4961618Sriastradh {
82d4961618Sriastradh 
83d4961618Sriastradh 	membar_release();
84d4961618Sriastradh 	turn = 1 - me;
85d4961618Sriastradh 	waiting[me].v = 0;
86d4961618Sriastradh 
87d4961618Sriastradh 	/*
88d4961618Sriastradh 	 * Not needed for correctness, but this helps on Cavium Octeon
89d4961618Sriastradh 	 * cnMIPS CPUs which require issuing a sync plunger to unclog
90d4961618Sriastradh 	 * store buffers which can otherwise stay clogged for hundreds
91d4961618Sriastradh 	 * of thousands of cycles, giving very little concurrency to
92d4961618Sriastradh 	 * this test.
93d4961618Sriastradh 	 */
94d4961618Sriastradh 	membar_producer();
95d4961618Sriastradh }
96d4961618Sriastradh 
97d4961618Sriastradh static void *
thread(void * cookie)98d4961618Sriastradh thread(void *cookie)
99d4961618Sriastradh {
100d4961618Sriastradh 	unsigned me = (unsigned)(uintptr_t)cookie;
101d4961618Sriastradh 	uint64_t C_local = 0;
102d4961618Sriastradh 
103d4961618Sriastradh 	while (!times_up) {
104d4961618Sriastradh 		C_local++;
105d4961618Sriastradh 		lock(me);
106d4961618Sriastradh 		C++;
107d4961618Sriastradh 		unlock(me);
108d4961618Sriastradh 	}
109d4961618Sriastradh 
110d4961618Sriastradh 	TC[me] = C_local;
111d4961618Sriastradh 
112d4961618Sriastradh 	return NULL;
113d4961618Sriastradh }
114d4961618Sriastradh 
115d4961618Sriastradh ATF_TC(dekker);
ATF_TC_HEAD(dekker,tc)116d4961618Sriastradh ATF_TC_HEAD(dekker, tc)
117d4961618Sriastradh {
118d4961618Sriastradh 	atf_tc_set_md_var(tc, "descr",
119d4961618Sriastradh 	    "Verify membar_sync works for Dekker's algorithm");
120d4961618Sriastradh }
ATF_TC_BODY(dekker,tc)121d4961618Sriastradh ATF_TC_BODY(dekker, tc)
122d4961618Sriastradh {
123d4961618Sriastradh 	pthread_t t[2];
124d4961618Sriastradh 	unsigned i;
125d4961618Sriastradh 	int ncpu;
126d4961618Sriastradh 	size_t ncpulen = sizeof(ncpu);
127d4961618Sriastradh 	int error;
128d4961618Sriastradh 
129*ea43e3d5Sriastradh 	alarm(10);
130*ea43e3d5Sriastradh 
131d4961618Sriastradh 	if (sysctlbyname("hw.ncpu", &ncpu, &ncpulen, NULL, 0) == -1)
132d4961618Sriastradh 		atf_tc_fail("hw.ncpu: (%d) %s", errno, strerror(errno));
133d4961618Sriastradh 	assert(ncpulen == sizeof(ncpu));
134d4961618Sriastradh 	if (ncpu == 1)
135d4961618Sriastradh 		atf_tc_skip("membar tests are only for multicore systems");
136d4961618Sriastradh 
137d4961618Sriastradh 	for (i = 0; i < 2; i++) {
138d4961618Sriastradh 		error = pthread_create(&t[i], NULL, &thread,
139d4961618Sriastradh 		    (void *)(uintptr_t)i);
140d4961618Sriastradh 		if (error)
141d4961618Sriastradh 			errc(1, error, "pthread_create");
142d4961618Sriastradh 	}
143*ea43e3d5Sriastradh 	sleep(5);
144*ea43e3d5Sriastradh 	times_up = 1;
145d4961618Sriastradh 	for (i = 0; i < 2; i++) {
146d4961618Sriastradh 		error = pthread_join(t[i], NULL);
147d4961618Sriastradh 		if (error)
148d4961618Sriastradh 			errc(1, error, "pthread_join");
149d4961618Sriastradh 	}
150d4961618Sriastradh 	ATF_REQUIRE_MSG(C == TC[0] + TC[1],
151d4961618Sriastradh 	    "%"PRIu64" != %"PRIu64" + %"PRIu64" (off by %"PRIdMAX")",
152d4961618Sriastradh 	    C, TC[0], TC[1], TC[0] + TC[1] - C);
153d4961618Sriastradh }
154d4961618Sriastradh 
ATF_TP_ADD_TCS(tp)155d4961618Sriastradh ATF_TP_ADD_TCS(tp)
156d4961618Sriastradh {
157d4961618Sriastradh 
158d4961618Sriastradh 	ATF_TP_ADD_TC(tp, dekker);
159d4961618Sriastradh 	return atf_no_error();
160d4961618Sriastradh }
161