1*3c3f886eSAlexander Leidinger /*-
2*3c3f886eSAlexander Leidinger * SPDX-License-Identifier: BSD-2-Clause
3*3c3f886eSAlexander Leidinger *
4*3c3f886eSAlexander Leidinger * Copyright (c) 2026 Alexander Leidinger <netchild@FreeBSD.org>
5*3c3f886eSAlexander Leidinger *
6*3c3f886eSAlexander Leidinger * Redistribution and use in source and binary forms, with or without
7*3c3f886eSAlexander Leidinger * modification, are permitted provided that the following conditions
8*3c3f886eSAlexander Leidinger * are met:
9*3c3f886eSAlexander Leidinger * 1. Redistributions of source code must retain the above copyright
10*3c3f886eSAlexander Leidinger * notice, this list of conditions and the following disclaimer.
11*3c3f886eSAlexander Leidinger * 2. Redistributions in binary form must reproduce the above copyright
12*3c3f886eSAlexander Leidinger * notice, this list of conditions and the following disclaimer in the
13*3c3f886eSAlexander Leidinger * documentation and/or other advertising materials provided with the
14*3c3f886eSAlexander Leidinger * distribution.
15*3c3f886eSAlexander Leidinger *
16*3c3f886eSAlexander Leidinger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*3c3f886eSAlexander Leidinger * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*3c3f886eSAlexander Leidinger * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*3c3f886eSAlexander Leidinger * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*3c3f886eSAlexander Leidinger * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*3c3f886eSAlexander Leidinger * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*3c3f886eSAlexander Leidinger * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*3c3f886eSAlexander Leidinger * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*3c3f886eSAlexander Leidinger * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*3c3f886eSAlexander Leidinger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*3c3f886eSAlexander Leidinger * SUCH DAMAGE.
27*3c3f886eSAlexander Leidinger */
28*3c3f886eSAlexander Leidinger
29*3c3f886eSAlexander Leidinger /*
30*3c3f886eSAlexander Leidinger * Regression tests for detaching a process-mode PMC from a target that
31*3c3f886eSAlexander Leidinger * still has it loaded on hardware. The runcount reference for a live
32*3c3f886eSAlexander Leidinger * PMC is dropped only by the context-switch-out reclaim, which the
33*3c3f886eSAlexander Leidinger * scheduler gates on P_HWPMC; detaching used to clear P_HWPMC without
34*3c3f886eSAlexander Leidinger * draining the reference, so the following release spun forever in
35*3c3f886eSAlexander Leidinger * pmc_wait_for_pmc_idle() - a panic ("waiting too long for pmc to be
36*3c3f886eSAlexander Leidinger * free") on an INVARIANTS kernel, an unkillable loop holding the hwpmc
37*3c3f886eSAlexander Leidinger * lock otherwise.
38*3c3f886eSAlexander Leidinger *
39*3c3f886eSAlexander Leidinger * The failure is deterministic: attaching a counting PMC to the current
40*3c3f886eSAlexander Leidinger * (running) thread and detaching it before release always left the
41*3c3f886eSAlexander Leidinger * reference live. On a kernel that carries the fix these tests complete
42*3c3f886eSAlexander Leidinger * immediately; run against a kernel that lacks it they would wedge, so
43*3c3f886eSAlexander Leidinger * (like any hwpmc regression test) they ship alongside the fix.
44*3c3f886eSAlexander Leidinger *
45*3c3f886eSAlexander Leidinger * They need an allocatable process-mode counting event, and skip where
46*3c3f886eSAlexander Leidinger * none is available (hwpmc(4) not loaded, or a VM without a vPMU).
47*3c3f886eSAlexander Leidinger */
48*3c3f886eSAlexander Leidinger
49*3c3f886eSAlexander Leidinger #include <sys/types.h>
50*3c3f886eSAlexander Leidinger
51*3c3f886eSAlexander Leidinger #include <errno.h>
52*3c3f886eSAlexander Leidinger #include <pmc.h>
53*3c3f886eSAlexander Leidinger #include <pthread.h>
54*3c3f886eSAlexander Leidinger #include <stdio.h>
55*3c3f886eSAlexander Leidinger #include <string.h>
56*3c3f886eSAlexander Leidinger #include <unistd.h>
57*3c3f886eSAlexander Leidinger
58*3c3f886eSAlexander Leidinger #include <atf-c.h>
59*3c3f886eSAlexander Leidinger
60*3c3f886eSAlexander Leidinger static const char *counting_events[] = {
61*3c3f886eSAlexander Leidinger "instructions",
62*3c3f886eSAlexander Leidinger "cycles",
63*3c3f886eSAlexander Leidinger "branches",
64*3c3f886eSAlexander Leidinger "unhalted-core-cycles",
65*3c3f886eSAlexander Leidinger "inst_retired.any",
66*3c3f886eSAlexander Leidinger "cpu_clk_unhalted.thread",
67*3c3f886eSAlexander Leidinger "ls_not_halted_cyc",
68*3c3f886eSAlexander Leidinger NULL
69*3c3f886eSAlexander Leidinger };
70*3c3f886eSAlexander Leidinger
71*3c3f886eSAlexander Leidinger static volatile int spin_stop;
72*3c3f886eSAlexander Leidinger
73*3c3f886eSAlexander Leidinger static void *
spinner(void * arg __unused)74*3c3f886eSAlexander Leidinger spinner(void *arg __unused)
75*3c3f886eSAlexander Leidinger {
76*3c3f886eSAlexander Leidinger volatile unsigned long s = 0;
77*3c3f886eSAlexander Leidinger
78*3c3f886eSAlexander Leidinger while (spin_stop == 0)
79*3c3f886eSAlexander Leidinger s += 1;
80*3c3f886eSAlexander Leidinger return (NULL);
81*3c3f886eSAlexander Leidinger }
82*3c3f886eSAlexander Leidinger
83*3c3f886eSAlexander Leidinger static void
burn_cpu(void)84*3c3f886eSAlexander Leidinger burn_cpu(void)
85*3c3f886eSAlexander Leidinger {
86*3c3f886eSAlexander Leidinger volatile unsigned long s = 0;
87*3c3f886eSAlexander Leidinger int i;
88*3c3f886eSAlexander Leidinger
89*3c3f886eSAlexander Leidinger for (i = 0; i < 1000000; i++)
90*3c3f886eSAlexander Leidinger s += i;
91*3c3f886eSAlexander Leidinger }
92*3c3f886eSAlexander Leidinger
93*3c3f886eSAlexander Leidinger /* Allocate the first available process-mode counting PMC, or skip. */
94*3c3f886eSAlexander Leidinger static pmc_id_t
alloc_counting_pmc(void)95*3c3f886eSAlexander Leidinger alloc_counting_pmc(void)
96*3c3f886eSAlexander Leidinger {
97*3c3f886eSAlexander Leidinger pmc_id_t id;
98*3c3f886eSAlexander Leidinger int i;
99*3c3f886eSAlexander Leidinger
100*3c3f886eSAlexander Leidinger if (pmc_init() != 0)
101*3c3f886eSAlexander Leidinger atf_tc_skip("hwpmc(4) is not available: %s", strerror(errno));
102*3c3f886eSAlexander Leidinger
103*3c3f886eSAlexander Leidinger for (i = 0; counting_events[i] != NULL; i++) {
104*3c3f886eSAlexander Leidinger id = PMC_ID_INVALID;
105*3c3f886eSAlexander Leidinger if (pmc_allocate(counting_events[i], PMC_MODE_TC, 0,
106*3c3f886eSAlexander Leidinger PMC_CPU_ANY, &id, 0) == 0)
107*3c3f886eSAlexander Leidinger return (id);
108*3c3f886eSAlexander Leidinger }
109*3c3f886eSAlexander Leidinger atf_tc_skip("no allocatable process-mode counting event "
110*3c3f886eSAlexander Leidinger "(no vPMU?)");
111*3c3f886eSAlexander Leidinger return (PMC_ID_INVALID); /* not reached */
112*3c3f886eSAlexander Leidinger }
113*3c3f886eSAlexander Leidinger
114*3c3f886eSAlexander Leidinger ATF_TC(detach_live_self);
ATF_TC_HEAD(detach_live_self,tc)115*3c3f886eSAlexander Leidinger ATF_TC_HEAD(detach_live_self, tc)
116*3c3f886eSAlexander Leidinger {
117*3c3f886eSAlexander Leidinger atf_tc_set_md_var(tc, "descr",
118*3c3f886eSAlexander Leidinger "Detaching a running counting PMC from the current thread and "
119*3c3f886eSAlexander Leidinger "then releasing it does not leak its runcount reference");
120*3c3f886eSAlexander Leidinger atf_tc_set_md_var(tc, "require.user", "root");
121*3c3f886eSAlexander Leidinger }
ATF_TC_BODY(detach_live_self,tc)122*3c3f886eSAlexander Leidinger ATF_TC_BODY(detach_live_self, tc)
123*3c3f886eSAlexander Leidinger {
124*3c3f886eSAlexander Leidinger pmc_id_t id;
125*3c3f886eSAlexander Leidinger
126*3c3f886eSAlexander Leidinger id = alloc_counting_pmc();
127*3c3f886eSAlexander Leidinger
128*3c3f886eSAlexander Leidinger ATF_REQUIRE(pmc_attach(id, 0) == 0); /* 0 == current process */
129*3c3f886eSAlexander Leidinger ATF_REQUIRE(pmc_start(id) == 0);
130*3c3f886eSAlexander Leidinger burn_cpu(); /* make the counter live */
131*3c3f886eSAlexander Leidinger
132*3c3f886eSAlexander Leidinger /* Detach while still loaded on this CPU, then release. */
133*3c3f886eSAlexander Leidinger ATF_REQUIRE(pmc_detach(id, 0) == 0);
134*3c3f886eSAlexander Leidinger ATF_REQUIRE(pmc_release(id) == 0); /* wedged before the fix */
135*3c3f886eSAlexander Leidinger }
136*3c3f886eSAlexander Leidinger
137*3c3f886eSAlexander Leidinger ATF_TC(detach_live_multithread);
ATF_TC_HEAD(detach_live_multithread,tc)138*3c3f886eSAlexander Leidinger ATF_TC_HEAD(detach_live_multithread, tc)
139*3c3f886eSAlexander Leidinger {
140*3c3f886eSAlexander Leidinger atf_tc_set_md_var(tc, "descr",
141*3c3f886eSAlexander Leidinger "Detaching a running process-scope counting PMC drains the "
142*3c3f886eSAlexander Leidinger "references held by the process' other threads");
143*3c3f886eSAlexander Leidinger atf_tc_set_md_var(tc, "require.user", "root");
144*3c3f886eSAlexander Leidinger }
ATF_TC_BODY(detach_live_multithread,tc)145*3c3f886eSAlexander Leidinger ATF_TC_BODY(detach_live_multithread, tc)
146*3c3f886eSAlexander Leidinger {
147*3c3f886eSAlexander Leidinger pthread_t th[3];
148*3c3f886eSAlexander Leidinger pmc_id_t id;
149*3c3f886eSAlexander Leidinger int i, n;
150*3c3f886eSAlexander Leidinger
151*3c3f886eSAlexander Leidinger id = alloc_counting_pmc();
152*3c3f886eSAlexander Leidinger
153*3c3f886eSAlexander Leidinger /* Sibling threads keep the process-scope PMC live on other CPUs. */
154*3c3f886eSAlexander Leidinger spin_stop = 0;
155*3c3f886eSAlexander Leidinger for (n = 0; n < 3; n++)
156*3c3f886eSAlexander Leidinger ATF_REQUIRE(pthread_create(&th[n], NULL, spinner, NULL) == 0);
157*3c3f886eSAlexander Leidinger
158*3c3f886eSAlexander Leidinger ATF_REQUIRE(pmc_attach(id, 0) == 0);
159*3c3f886eSAlexander Leidinger ATF_REQUIRE(pmc_start(id) == 0);
160*3c3f886eSAlexander Leidinger burn_cpu();
161*3c3f886eSAlexander Leidinger /* Let the siblings be scheduled and pick up the PMC. */
162*3c3f886eSAlexander Leidinger usleep(200 * 1000);
163*3c3f886eSAlexander Leidinger
164*3c3f886eSAlexander Leidinger ATF_REQUIRE(pmc_detach(id, 0) == 0);
165*3c3f886eSAlexander Leidinger ATF_REQUIRE(pmc_release(id) == 0); /* must drain the siblings */
166*3c3f886eSAlexander Leidinger
167*3c3f886eSAlexander Leidinger spin_stop = 1;
168*3c3f886eSAlexander Leidinger for (i = 0; i < n; i++)
169*3c3f886eSAlexander Leidinger pthread_join(th[i], NULL);
170*3c3f886eSAlexander Leidinger }
171*3c3f886eSAlexander Leidinger
ATF_TP_ADD_TCS(tp)172*3c3f886eSAlexander Leidinger ATF_TP_ADD_TCS(tp)
173*3c3f886eSAlexander Leidinger {
174*3c3f886eSAlexander Leidinger ATF_TP_ADD_TC(tp, detach_live_self);
175*3c3f886eSAlexander Leidinger ATF_TP_ADD_TC(tp, detach_live_multithread);
176*3c3f886eSAlexander Leidinger
177*3c3f886eSAlexander Leidinger return (atf_no_error());
178*3c3f886eSAlexander Leidinger }
179