1*d00da145SAlexander Leidinger /*-
2*d00da145SAlexander Leidinger * SPDX-License-Identifier: BSD-2-Clause
3*d00da145SAlexander Leidinger *
4*d00da145SAlexander Leidinger * Copyright (c) 2026 Alexander Leidinger <netchild@FreeBSD.org>
5*d00da145SAlexander Leidinger *
6*d00da145SAlexander Leidinger * Redistribution and use in source and binary forms, with or without
7*d00da145SAlexander Leidinger * modification, are permitted provided that the following conditions
8*d00da145SAlexander Leidinger * are met:
9*d00da145SAlexander Leidinger * 1. Redistributions of source code must retain the above copyright
10*d00da145SAlexander Leidinger * notice, this list of conditions and the following disclaimer.
11*d00da145SAlexander Leidinger * 2. Redistributions in binary form must reproduce the above copyright
12*d00da145SAlexander Leidinger * notice, this list of conditions and the following disclaimer in the
13*d00da145SAlexander Leidinger * documentation and/or other advertising materials provided with the
14*d00da145SAlexander Leidinger * distribution.
15*d00da145SAlexander Leidinger *
16*d00da145SAlexander Leidinger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*d00da145SAlexander Leidinger * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*d00da145SAlexander Leidinger * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*d00da145SAlexander Leidinger * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*d00da145SAlexander Leidinger * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*d00da145SAlexander Leidinger * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*d00da145SAlexander Leidinger * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*d00da145SAlexander Leidinger * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*d00da145SAlexander Leidinger * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*d00da145SAlexander Leidinger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*d00da145SAlexander Leidinger * SUCH DAMAGE.
27*d00da145SAlexander Leidinger */
28*d00da145SAlexander Leidinger
29*d00da145SAlexander Leidinger /**
30*d00da145SAlexander Leidinger * @file
31*d00da145SAlexander Leidinger * Tests for hwpmc(4)'s process-attachment lifecycle: what happens as a PMC
32*d00da145SAlexander Leidinger * is attached, inherited, and torn down, especially when the teardown does
33*d00da145SAlexander Leidinger * not happen in the tidy order the common path assumes.
34*d00da145SAlexander Leidinger *
35*d00da145SAlexander Leidinger * The orderings driven here are a target that exits before it is
36*d00da145SAlexander Leidinger * detached, an owner that exits before its target (which reaches the
37*d00da145SAlexander Leidinger * REMOVE side of pmc_find_process_descriptor()),
38*d00da145SAlexander Leidinger * a release of a still-running attached PMC, row exhaustion released out
39*d00da145SAlexander Leidinger * of order, and PMC_F_DESCENDANTS, where the teardown has to account for a
40*d00da145SAlexander Leidinger * target the owner never attached by hand.
41*d00da145SAlexander Leidinger *
42*d00da145SAlexander Leidinger * All PMCs are SOFT-class, so nothing here needs a hardware counter.
43*d00da145SAlexander Leidinger */
44*d00da145SAlexander Leidinger
45*d00da145SAlexander Leidinger #include <sys/param.h>
46*d00da145SAlexander Leidinger #include <sys/wait.h>
47*d00da145SAlexander Leidinger
48*d00da145SAlexander Leidinger #include <errno.h>
49*d00da145SAlexander Leidinger #include <pmc.h>
50*d00da145SAlexander Leidinger #include <signal.h>
51*d00da145SAlexander Leidinger #include <stdint.h>
52*d00da145SAlexander Leidinger #include <stdio.h>
53*d00da145SAlexander Leidinger #include <stdlib.h>
54*d00da145SAlexander Leidinger #include <string.h>
55*d00da145SAlexander Leidinger #include <unistd.h>
56*d00da145SAlexander Leidinger
57*d00da145SAlexander Leidinger #include <atf-c.h>
58*d00da145SAlexander Leidinger
59*d00da145SAlexander Leidinger static void
require_hwpmc(void)60*d00da145SAlexander Leidinger require_hwpmc(void)
61*d00da145SAlexander Leidinger {
62*d00da145SAlexander Leidinger
63*d00da145SAlexander Leidinger if (pmc_init() != 0)
64*d00da145SAlexander Leidinger atf_tc_skip("hwpmc(4) is not available");
65*d00da145SAlexander Leidinger }
66*d00da145SAlexander Leidinger
67*d00da145SAlexander Leidinger /**
68*d00da145SAlexander Leidinger * @internal
69*d00da145SAlexander Leidinger * Allocate the first SOFT event this mode and flag set accept. Which event
70*d00da145SAlexander Leidinger * it is does not matter; that one exists is what the case needs.
71*d00da145SAlexander Leidinger */
72*d00da145SAlexander Leidinger static pmc_id_t
allocate_soft_pmc_flags(enum pmc_mode mode,uint32_t flags)73*d00da145SAlexander Leidinger allocate_soft_pmc_flags(enum pmc_mode mode, uint32_t flags)
74*d00da145SAlexander Leidinger {
75*d00da145SAlexander Leidinger const char **names;
76*d00da145SAlexander Leidinger char spec[128];
77*d00da145SAlexander Leidinger pmc_id_t id;
78*d00da145SAlexander Leidinger int nnames, i;
79*d00da145SAlexander Leidinger
80*d00da145SAlexander Leidinger if (pmc_event_names_of_class(PMC_CLASS_SOFT, &names, &nnames) != 0)
81*d00da145SAlexander Leidinger return (PMC_ID_INVALID);
82*d00da145SAlexander Leidinger for (i = 0; i < nnames; i++) {
83*d00da145SAlexander Leidinger (void)snprintf(spec, sizeof(spec), "SOFT-%s", names[i]);
84*d00da145SAlexander Leidinger if (pmc_allocate(spec, mode, flags, PMC_CPU_ANY, &id, 0) == 0)
85*d00da145SAlexander Leidinger return (id);
86*d00da145SAlexander Leidinger }
87*d00da145SAlexander Leidinger return (PMC_ID_INVALID);
88*d00da145SAlexander Leidinger }
89*d00da145SAlexander Leidinger
90*d00da145SAlexander Leidinger static pmc_id_t
require_soft_pmc(enum pmc_mode mode)91*d00da145SAlexander Leidinger require_soft_pmc(enum pmc_mode mode)
92*d00da145SAlexander Leidinger {
93*d00da145SAlexander Leidinger pmc_id_t id;
94*d00da145SAlexander Leidinger
95*d00da145SAlexander Leidinger if ((id = allocate_soft_pmc_flags(mode, 0)) == PMC_ID_INVALID)
96*d00da145SAlexander Leidinger atf_tc_skip("no SOFT-class PMC is allocatable");
97*d00da145SAlexander Leidinger return (id);
98*d00da145SAlexander Leidinger }
99*d00da145SAlexander Leidinger
100*d00da145SAlexander Leidinger /**
101*d00da145SAlexander Leidinger * @internal
102*d00da145SAlexander Leidinger * A child that does nothing until killed, for use as an attach target.
103*d00da145SAlexander Leidinger */
104*d00da145SAlexander Leidinger static pid_t
spawn_idle_child(void)105*d00da145SAlexander Leidinger spawn_idle_child(void)
106*d00da145SAlexander Leidinger {
107*d00da145SAlexander Leidinger pid_t pid;
108*d00da145SAlexander Leidinger
109*d00da145SAlexander Leidinger pid = fork();
110*d00da145SAlexander Leidinger if (pid == 0) {
111*d00da145SAlexander Leidinger for (;;)
112*d00da145SAlexander Leidinger (void)pause();
113*d00da145SAlexander Leidinger }
114*d00da145SAlexander Leidinger return (pid);
115*d00da145SAlexander Leidinger }
116*d00da145SAlexander Leidinger
117*d00da145SAlexander Leidinger static void
reap(pid_t pid)118*d00da145SAlexander Leidinger reap(pid_t pid)
119*d00da145SAlexander Leidinger {
120*d00da145SAlexander Leidinger int status;
121*d00da145SAlexander Leidinger
122*d00da145SAlexander Leidinger (void)kill(pid, SIGKILL);
123*d00da145SAlexander Leidinger (void)waitpid(pid, &status, 0);
124*d00da145SAlexander Leidinger }
125*d00da145SAlexander Leidinger
126*d00da145SAlexander Leidinger /**
127*d00da145SAlexander Leidinger * @internal
128*d00da145SAlexander Leidinger * The bookkeeping around attach and detach.
129*d00da145SAlexander Leidinger */
130*d00da145SAlexander Leidinger ATF_TC_WITHOUT_HEAD(attach_detach_bookkeeping);
ATF_TC_BODY(attach_detach_bookkeeping,tc)131*d00da145SAlexander Leidinger ATF_TC_BODY(attach_detach_bookkeeping, tc)
132*d00da145SAlexander Leidinger {
133*d00da145SAlexander Leidinger pmc_id_t id;
134*d00da145SAlexander Leidinger pid_t other;
135*d00da145SAlexander Leidinger
136*d00da145SAlexander Leidinger require_hwpmc();
137*d00da145SAlexander Leidinger id = require_soft_pmc(PMC_MODE_TC);
138*d00da145SAlexander Leidinger other = spawn_idle_child();
139*d00da145SAlexander Leidinger ATF_REQUIRE(other > 0);
140*d00da145SAlexander Leidinger
141*d00da145SAlexander Leidinger ATF_REQUIRE_MSG(pmc_attach(id, getpid()) == 0, "pmc_attach: %s",
142*d00da145SAlexander Leidinger strerror(errno));
143*d00da145SAlexander Leidinger
144*d00da145SAlexander Leidinger /* A second attach of the same target must be refused, not doubled. */
145*d00da145SAlexander Leidinger errno = 0;
146*d00da145SAlexander Leidinger ATF_CHECK_MSG(pmc_attach(id, getpid()) != 0,
147*d00da145SAlexander Leidinger "a second attach of the same target succeeded");
148*d00da145SAlexander Leidinger
149*d00da145SAlexander Leidinger /* Detaching a pid that was never attached must be refused. */
150*d00da145SAlexander Leidinger errno = 0;
151*d00da145SAlexander Leidinger ATF_CHECK_MSG(pmc_detach(id, other) != 0,
152*d00da145SAlexander Leidinger "detached a target that was never attached");
153*d00da145SAlexander Leidinger
154*d00da145SAlexander Leidinger /* One detach undoes the one attach. */
155*d00da145SAlexander Leidinger ATF_CHECK_MSG(pmc_detach(id, getpid()) == 0, "pmc_detach: %s",
156*d00da145SAlexander Leidinger strerror(errno));
157*d00da145SAlexander Leidinger
158*d00da145SAlexander Leidinger /* A second detach must now be refused. */
159*d00da145SAlexander Leidinger errno = 0;
160*d00da145SAlexander Leidinger ATF_CHECK_MSG(pmc_detach(id, getpid()) != 0,
161*d00da145SAlexander Leidinger "a second detach of the same target succeeded");
162*d00da145SAlexander Leidinger
163*d00da145SAlexander Leidinger ATF_CHECK_MSG(pmc_release(id) == 0, "pmc_release: %s",
164*d00da145SAlexander Leidinger strerror(errno));
165*d00da145SAlexander Leidinger reap(other);
166*d00da145SAlexander Leidinger }
167*d00da145SAlexander Leidinger
168*d00da145SAlexander Leidinger /**
169*d00da145SAlexander Leidinger * @internal
170*d00da145SAlexander Leidinger * Detach a target that has already exited and been reaped. The
171*d00da145SAlexander Leidinger * kernel's own eventhandler removes an exiting process's descriptor, so by
172*d00da145SAlexander Leidinger * the time we detach there is nothing there; it must say so cleanly, and
173*d00da145SAlexander Leidinger * the PMC must still release.
174*d00da145SAlexander Leidinger */
175*d00da145SAlexander Leidinger ATF_TC_WITHOUT_HEAD(detach_after_target_reaped);
ATF_TC_BODY(detach_after_target_reaped,tc)176*d00da145SAlexander Leidinger ATF_TC_BODY(detach_after_target_reaped, tc)
177*d00da145SAlexander Leidinger {
178*d00da145SAlexander Leidinger pmc_id_t id;
179*d00da145SAlexander Leidinger pid_t target;
180*d00da145SAlexander Leidinger
181*d00da145SAlexander Leidinger require_hwpmc();
182*d00da145SAlexander Leidinger id = require_soft_pmc(PMC_MODE_TC);
183*d00da145SAlexander Leidinger target = spawn_idle_child();
184*d00da145SAlexander Leidinger ATF_REQUIRE(target > 0);
185*d00da145SAlexander Leidinger
186*d00da145SAlexander Leidinger ATF_REQUIRE_MSG(pmc_attach(id, target) == 0, "pmc_attach: %s",
187*d00da145SAlexander Leidinger strerror(errno));
188*d00da145SAlexander Leidinger
189*d00da145SAlexander Leidinger /* Kill and fully reap the target before detaching. */
190*d00da145SAlexander Leidinger reap(target);
191*d00da145SAlexander Leidinger
192*d00da145SAlexander Leidinger errno = 0;
193*d00da145SAlexander Leidinger ATF_CHECK_MSG(pmc_detach(id, target) != 0,
194*d00da145SAlexander Leidinger "detached a target that had exited and been reaped");
195*d00da145SAlexander Leidinger
196*d00da145SAlexander Leidinger ATF_CHECK_MSG(pmc_release(id) == 0, "pmc_release: %s",
197*d00da145SAlexander Leidinger strerror(errno));
198*d00da145SAlexander Leidinger }
199*d00da145SAlexander Leidinger
200*d00da145SAlexander Leidinger /**
201*d00da145SAlexander Leidinger * @internal
202*d00da145SAlexander Leidinger * Release a PMC that is still attached and still running, with no
203*d00da145SAlexander Leidinger * prior detach or stop: the release path has to reclaim the reference
204*d00da145SAlexander Leidinger * the running PMC still holds rather than wedge.
205*d00da145SAlexander Leidinger */
206*d00da145SAlexander Leidinger ATF_TC_WITHOUT_HEAD(release_running_attached);
ATF_TC_BODY(release_running_attached,tc)207*d00da145SAlexander Leidinger ATF_TC_BODY(release_running_attached, tc)
208*d00da145SAlexander Leidinger {
209*d00da145SAlexander Leidinger pmc_id_t id;
210*d00da145SAlexander Leidinger
211*d00da145SAlexander Leidinger require_hwpmc();
212*d00da145SAlexander Leidinger id = require_soft_pmc(PMC_MODE_TC);
213*d00da145SAlexander Leidinger
214*d00da145SAlexander Leidinger ATF_REQUIRE_MSG(pmc_attach(id, getpid()) == 0, "pmc_attach: %s",
215*d00da145SAlexander Leidinger strerror(errno));
216*d00da145SAlexander Leidinger ATF_REQUIRE_MSG(pmc_start(id) == 0, "pmc_start: %s", strerror(errno));
217*d00da145SAlexander Leidinger
218*d00da145SAlexander Leidinger /* Run a little, so the PMC is actually loaded on a CPU. */
219*d00da145SAlexander Leidinger {
220*d00da145SAlexander Leidinger volatile unsigned long s = 0;
221*d00da145SAlexander Leidinger int i;
222*d00da145SAlexander Leidinger
223*d00da145SAlexander Leidinger for (i = 0; i < 5000000; i++)
224*d00da145SAlexander Leidinger s += i;
225*d00da145SAlexander Leidinger }
226*d00da145SAlexander Leidinger (void)usleep(100000);
227*d00da145SAlexander Leidinger
228*d00da145SAlexander Leidinger /* Straight to release: no stop, no detach. */
229*d00da145SAlexander Leidinger ATF_CHECK_MSG(pmc_release(id) == 0,
230*d00da145SAlexander Leidinger "release of a running, attached PMC failed: %s", strerror(errno));
231*d00da145SAlexander Leidinger
232*d00da145SAlexander Leidinger /* The driver is still usable afterwards. */
233*d00da145SAlexander Leidinger {
234*d00da145SAlexander Leidinger pmc_id_t again = allocate_soft_pmc_flags(PMC_MODE_TC, 0);
235*d00da145SAlexander Leidinger
236*d00da145SAlexander Leidinger ATF_CHECK_MSG(again != PMC_ID_INVALID,
237*d00da145SAlexander Leidinger "hwpmc is unusable after the release");
238*d00da145SAlexander Leidinger if (again != PMC_ID_INVALID)
239*d00da145SAlexander Leidinger (void)pmc_release(again);
240*d00da145SAlexander Leidinger }
241*d00da145SAlexander Leidinger }
242*d00da145SAlexander Leidinger
243*d00da145SAlexander Leidinger /**
244*d00da145SAlexander Leidinger * @internal
245*d00da145SAlexander Leidinger * The owner exits before the target. A child process is the owner:
246*d00da145SAlexander Leidinger * it allocates a PMC and attaches it to a sibling that outlives it, then
247*d00da145SAlexander Leidinger * exits without releasing. The kernel tears the owner's PMCs down through
248*d00da145SAlexander Leidinger * the REMOVE side of pmc_find_process_descriptor() - the other of its two
249*d00da145SAlexander Leidinger * unlink mechanisms, which no test exercised. The parent then confirms
250*d00da145SAlexander Leidinger * the driver is still usable and the target still alive.
251*d00da145SAlexander Leidinger */
252*d00da145SAlexander Leidinger ATF_TC_WITHOUT_HEAD(owner_exit_before_target);
ATF_TC_BODY(owner_exit_before_target,tc)253*d00da145SAlexander Leidinger ATF_TC_BODY(owner_exit_before_target, tc)
254*d00da145SAlexander Leidinger {
255*d00da145SAlexander Leidinger pmc_id_t id;
256*d00da145SAlexander Leidinger pid_t target, owner;
257*d00da145SAlexander Leidinger int status;
258*d00da145SAlexander Leidinger
259*d00da145SAlexander Leidinger require_hwpmc();
260*d00da145SAlexander Leidinger
261*d00da145SAlexander Leidinger target = spawn_idle_child();
262*d00da145SAlexander Leidinger ATF_REQUIRE(target > 0);
263*d00da145SAlexander Leidinger
264*d00da145SAlexander Leidinger owner = fork();
265*d00da145SAlexander Leidinger ATF_REQUIRE(owner >= 0);
266*d00da145SAlexander Leidinger if (owner == 0) {
267*d00da145SAlexander Leidinger /* Owner: attach to the sibling target, then just exit. */
268*d00da145SAlexander Leidinger if (pmc_init() != 0)
269*d00da145SAlexander Leidinger _exit(10);
270*d00da145SAlexander Leidinger id = allocate_soft_pmc_flags(PMC_MODE_TC, 0);
271*d00da145SAlexander Leidinger if (id == PMC_ID_INVALID)
272*d00da145SAlexander Leidinger _exit(11);
273*d00da145SAlexander Leidinger if (pmc_attach(id, target) != 0)
274*d00da145SAlexander Leidinger _exit(12);
275*d00da145SAlexander Leidinger if (pmc_start(id) != 0)
276*d00da145SAlexander Leidinger _exit(13);
277*d00da145SAlexander Leidinger /* Exit with the PMC still allocated, attached and running. */
278*d00da145SAlexander Leidinger _exit(0);
279*d00da145SAlexander Leidinger }
280*d00da145SAlexander Leidinger
281*d00da145SAlexander Leidinger ATF_REQUIRE(waitpid(owner, &status, 0) == owner);
282*d00da145SAlexander Leidinger ATF_REQUIRE_MSG(WIFEXITED(status),
283*d00da145SAlexander Leidinger "the owner did not exit normally (it may have panicked the "
284*d00da145SAlexander Leidinger "kernel; status 0x%x)", status);
285*d00da145SAlexander Leidinger ATF_REQUIRE_MSG(WEXITSTATUS(status) == 0,
286*d00da145SAlexander Leidinger "the owner's setup failed (exit %d): 10=init 11=alloc 12=attach "
287*d00da145SAlexander Leidinger "13=start", WEXITSTATUS(status));
288*d00da145SAlexander Leidinger
289*d00da145SAlexander Leidinger /*
290*d00da145SAlexander Leidinger * The owner is gone. Its descriptor teardown must have run without
291*d00da145SAlexander Leidinger * wedging: prove the driver still works and the target is still here.
292*d00da145SAlexander Leidinger */
293*d00da145SAlexander Leidinger id = allocate_soft_pmc_flags(PMC_MODE_TC, 0);
294*d00da145SAlexander Leidinger ATF_CHECK_MSG(id != PMC_ID_INVALID,
295*d00da145SAlexander Leidinger "hwpmc is unusable after the owner exited with a live target");
296*d00da145SAlexander Leidinger if (id != PMC_ID_INVALID) {
297*d00da145SAlexander Leidinger ATF_CHECK(pmc_attach(id, getpid()) == 0);
298*d00da145SAlexander Leidinger ATF_CHECK(pmc_detach(id, getpid()) == 0);
299*d00da145SAlexander Leidinger ATF_CHECK(pmc_release(id) == 0);
300*d00da145SAlexander Leidinger }
301*d00da145SAlexander Leidinger ATF_CHECK_MSG(kill(target, 0) == 0,
302*d00da145SAlexander Leidinger "the target did not survive the owner's exit");
303*d00da145SAlexander Leidinger reap(target);
304*d00da145SAlexander Leidinger }
305*d00da145SAlexander Leidinger
306*d00da145SAlexander Leidinger /**
307*d00da145SAlexander Leidinger * @internal
308*d00da145SAlexander Leidinger * Allocate SOFT PMCs until the rows are exhausted, then release them
309*d00da145SAlexander Leidinger * in an order other than allocation order. Exercises the row free-list
310*d00da145SAlexander Leidinger * against out-of-order frees.
311*d00da145SAlexander Leidinger */
312*d00da145SAlexander Leidinger ATF_TC_WITHOUT_HEAD(exhaust_then_release_reverse);
ATF_TC_BODY(exhaust_then_release_reverse,tc)313*d00da145SAlexander Leidinger ATF_TC_BODY(exhaust_then_release_reverse, tc)
314*d00da145SAlexander Leidinger {
315*d00da145SAlexander Leidinger pmc_id_t ids[64];
316*d00da145SAlexander Leidinger int n, i;
317*d00da145SAlexander Leidinger
318*d00da145SAlexander Leidinger require_hwpmc();
319*d00da145SAlexander Leidinger
320*d00da145SAlexander Leidinger n = 0;
321*d00da145SAlexander Leidinger while (n < (int)nitems(ids)) {
322*d00da145SAlexander Leidinger pmc_id_t id = allocate_soft_pmc_flags(PMC_MODE_TC, 0);
323*d00da145SAlexander Leidinger
324*d00da145SAlexander Leidinger if (id == PMC_ID_INVALID)
325*d00da145SAlexander Leidinger break;
326*d00da145SAlexander Leidinger ids[n++] = id;
327*d00da145SAlexander Leidinger }
328*d00da145SAlexander Leidinger ATF_REQUIRE_MSG(n > 0, "not one SOFT PMC could be allocated");
329*d00da145SAlexander Leidinger
330*d00da145SAlexander Leidinger /* At least one allocation should have failed at exhaustion. */
331*d00da145SAlexander Leidinger ATF_CHECK_MSG(n < (int)nitems(ids),
332*d00da145SAlexander Leidinger "allocation never hit a limit in %zu tries", nitems(ids));
333*d00da145SAlexander Leidinger
334*d00da145SAlexander Leidinger /* Release in reverse order; every one must succeed. */
335*d00da145SAlexander Leidinger for (i = n - 1; i >= 0; i--)
336*d00da145SAlexander Leidinger ATF_CHECK_MSG(pmc_release(ids[i]) == 0,
337*d00da145SAlexander Leidinger "reverse release of id 0x%08x (slot %d) failed: %s",
338*d00da145SAlexander Leidinger ids[i], i, strerror(errno));
339*d00da145SAlexander Leidinger }
340*d00da145SAlexander Leidinger
341*d00da145SAlexander Leidinger /**
342*d00da145SAlexander Leidinger * @internal
343*d00da145SAlexander Leidinger * A PMC_F_DESCENDANTS counter, whose child inherits the attachment.
344*d00da145SAlexander Leidinger * The owner attaches to itself with descendants set, forks a child that
345*d00da145SAlexander Leidinger * does a little work and exits, reaps it, and releases. The teardown has
346*d00da145SAlexander Leidinger * to account for the child the owner never attached to by hand.
347*d00da145SAlexander Leidinger */
348*d00da145SAlexander Leidinger ATF_TC_WITHOUT_HEAD(descendants_inherit_and_release);
ATF_TC_BODY(descendants_inherit_and_release,tc)349*d00da145SAlexander Leidinger ATF_TC_BODY(descendants_inherit_and_release, tc)
350*d00da145SAlexander Leidinger {
351*d00da145SAlexander Leidinger pmc_id_t id;
352*d00da145SAlexander Leidinger pid_t child;
353*d00da145SAlexander Leidinger int status;
354*d00da145SAlexander Leidinger
355*d00da145SAlexander Leidinger require_hwpmc();
356*d00da145SAlexander Leidinger id = allocate_soft_pmc_flags(PMC_MODE_TC, PMC_F_DESCENDANTS);
357*d00da145SAlexander Leidinger if (id == PMC_ID_INVALID)
358*d00da145SAlexander Leidinger atf_tc_skip("no SOFT PMC allocatable with PMC_F_DESCENDANTS");
359*d00da145SAlexander Leidinger
360*d00da145SAlexander Leidinger ATF_REQUIRE_MSG(pmc_attach(id, getpid()) == 0, "pmc_attach: %s",
361*d00da145SAlexander Leidinger strerror(errno));
362*d00da145SAlexander Leidinger ATF_REQUIRE_MSG(pmc_start(id) == 0, "pmc_start: %s", strerror(errno));
363*d00da145SAlexander Leidinger
364*d00da145SAlexander Leidinger child = fork();
365*d00da145SAlexander Leidinger ATF_REQUIRE(child >= 0);
366*d00da145SAlexander Leidinger if (child == 0) {
367*d00da145SAlexander Leidinger volatile unsigned long s = 0;
368*d00da145SAlexander Leidinger int i;
369*d00da145SAlexander Leidinger
370*d00da145SAlexander Leidinger for (i = 0; i < 2000000; i++)
371*d00da145SAlexander Leidinger s += i;
372*d00da145SAlexander Leidinger _exit(0);
373*d00da145SAlexander Leidinger }
374*d00da145SAlexander Leidinger ATF_REQUIRE(waitpid(child, &status, 0) == child);
375*d00da145SAlexander Leidinger ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0,
376*d00da145SAlexander Leidinger "the descendant did not exit cleanly (status 0x%x)", status);
377*d00da145SAlexander Leidinger
378*d00da145SAlexander Leidinger ATF_CHECK(pmc_stop(id) == 0);
379*d00da145SAlexander Leidinger ATF_CHECK_MSG(pmc_release(id) == 0,
380*d00da145SAlexander Leidinger "release of a descendants PMC failed: %s", strerror(errno));
381*d00da145SAlexander Leidinger }
382*d00da145SAlexander Leidinger
383*d00da145SAlexander Leidinger /**
384*d00da145SAlexander Leidinger * @internal
385*d00da145SAlexander Leidinger * The fork-storm variant: descendants set, then many short-lived children,
386*d00da145SAlexander Leidinger * so several inherit-and-exit teardowns overlap, then release.
387*d00da145SAlexander Leidinger */
388*d00da145SAlexander Leidinger ATF_TC_WITHOUT_HEAD(descendants_fork_storm);
ATF_TC_BODY(descendants_fork_storm,tc)389*d00da145SAlexander Leidinger ATF_TC_BODY(descendants_fork_storm, tc)
390*d00da145SAlexander Leidinger {
391*d00da145SAlexander Leidinger pmc_id_t id;
392*d00da145SAlexander Leidinger int i, status;
393*d00da145SAlexander Leidinger
394*d00da145SAlexander Leidinger require_hwpmc();
395*d00da145SAlexander Leidinger id = allocate_soft_pmc_flags(PMC_MODE_TC, PMC_F_DESCENDANTS);
396*d00da145SAlexander Leidinger if (id == PMC_ID_INVALID)
397*d00da145SAlexander Leidinger atf_tc_skip("no SOFT PMC allocatable with PMC_F_DESCENDANTS");
398*d00da145SAlexander Leidinger
399*d00da145SAlexander Leidinger ATF_REQUIRE_MSG(pmc_attach(id, getpid()) == 0, "pmc_attach: %s",
400*d00da145SAlexander Leidinger strerror(errno));
401*d00da145SAlexander Leidinger ATF_REQUIRE_MSG(pmc_start(id) == 0, "pmc_start: %s", strerror(errno));
402*d00da145SAlexander Leidinger
403*d00da145SAlexander Leidinger for (i = 0; i < 32; i++) {
404*d00da145SAlexander Leidinger pid_t c = fork();
405*d00da145SAlexander Leidinger
406*d00da145SAlexander Leidinger if (c == 0) {
407*d00da145SAlexander Leidinger volatile unsigned long s = 0;
408*d00da145SAlexander Leidinger int j;
409*d00da145SAlexander Leidinger
410*d00da145SAlexander Leidinger for (j = 0; j < 200000; j++)
411*d00da145SAlexander Leidinger s += j;
412*d00da145SAlexander Leidinger _exit(0);
413*d00da145SAlexander Leidinger }
414*d00da145SAlexander Leidinger if (c > 0)
415*d00da145SAlexander Leidinger (void)waitpid(c, &status, 0);
416*d00da145SAlexander Leidinger }
417*d00da145SAlexander Leidinger
418*d00da145SAlexander Leidinger ATF_CHECK(pmc_stop(id) == 0);
419*d00da145SAlexander Leidinger ATF_CHECK_MSG(pmc_release(id) == 0,
420*d00da145SAlexander Leidinger "release after a descendants fork storm failed: %s",
421*d00da145SAlexander Leidinger strerror(errno));
422*d00da145SAlexander Leidinger }
423*d00da145SAlexander Leidinger
ATF_TP_ADD_TCS(tp)424*d00da145SAlexander Leidinger ATF_TP_ADD_TCS(tp)
425*d00da145SAlexander Leidinger {
426*d00da145SAlexander Leidinger
427*d00da145SAlexander Leidinger ATF_TP_ADD_TC(tp, attach_detach_bookkeeping);
428*d00da145SAlexander Leidinger ATF_TP_ADD_TC(tp, detach_after_target_reaped);
429*d00da145SAlexander Leidinger ATF_TP_ADD_TC(tp, release_running_attached);
430*d00da145SAlexander Leidinger ATF_TP_ADD_TC(tp, owner_exit_before_target);
431*d00da145SAlexander Leidinger ATF_TP_ADD_TC(tp, exhaust_then_release_reverse);
432*d00da145SAlexander Leidinger ATF_TP_ADD_TC(tp, descendants_inherit_and_release);
433*d00da145SAlexander Leidinger ATF_TP_ADD_TC(tp, descendants_fork_storm);
434*d00da145SAlexander Leidinger
435*d00da145SAlexander Leidinger return (atf_no_error());
436*d00da145SAlexander Leidinger }
437