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