From nobody Mon Jul 20 10:25:17 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4h3c8t0ZS1z6ljv7 for ; Mon, 20 Jul 2026 10:25:18 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4h3c8s3vGqz457G for ; Mon, 20 Jul 2026 10:25:17 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1784543117; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=IGMSlDBVo58QNp6JnTU9A3WGCOVMg8JazClC4/z1+sM=; b=qYQAhXiUAvo8m9ws8gnC/BPa9CiHaIYMrAs8SUl0GCza7FBqu/73EeTSvI/Z+CTCoGyS4I FBgoQeWJ4A2t3u0oOzIuwUKEWKxz/k56vW153VPmqUO+3tMJeJ1R72XcxIsG7i3igDepXd g1b6iJBg5f2ahXdcNbmrZ2F11G68nEVHo03iyMKvi9ly1OMFQaj1L212EuAagmbJucTGLR Ij1xXeVPat8LwGcXv1KE52gRg8vmsDUcZhGc+BkgR3NWjvawMHsw13FJUNYtbbadsHcHXQ NzCxcF8il2AtleAmjPmobCSpemvNWl9Zro7SJciG7FRhp1npmfUhALfDGh9APw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1784543117; a=rsa-sha256; cv=none; b=ePun5qocASUHvvWrsOEN48DwMrxirm79B+L03O8wEZgdvHPEk9Z+42eUc+Z/3Xl5IzZPFu n+smEBhBcwk3G0of7VGz7jqb+3FmXDMVBiWYVPV0NQGVKl57rBiohkdvvZ2IaLeTHT+tfO 59AzTld5z1tZ0jUAWuYrI51EMaHYbGwjSzDutYbYNpO0a9PC2YUwHQt+U47Xv65PMkoeJz SXfrIPdhOj8CAY5L5nZNPXN9fCSC0GSEUe8WtPaummePH04EN/Wmf8HlgzB6dCY4VlPsly 6vvfsbxiVlt5x+X0lriSFg0VAL6xjrTWndOuJORiNmnsH0HedSyq/L+YpUaoAQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1784543117; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=IGMSlDBVo58QNp6JnTU9A3WGCOVMg8JazClC4/z1+sM=; b=FTTS5a3IhnpjMowp1B+wlpG1+6uWkPvbfKgrs5Na/ukf8I6auIw6/Qucx1nKFJW3xiJstc G6xwvTfiGdbeRLrxRUUNzJOS+4HCcNMMBPSWE7Gz6cuHSFiKryKpCfiq8BMID4Tl7VV6Yt SRRg+nlJhouu6Du+to9Jq4p57X0bVFQLuLEBtgkut8zons62rFDqN4gIzFcdUffiC9A9Ut IEsjnMHry5rngfUmdCPRIisEQSqDr4DoTrRc56thlnI8zviy6AFTNtLAqEvE0HU6pBA4w2 6etpYVynA3eXBczEUl9TAJAaQZcXFcJW9U+78nRIfptRd/kGLjTtZstJ1cj9Yg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4h3c8s2Tr5zy11 for ; Mon, 20 Jul 2026 10:25:17 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 32690 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 20 Jul 2026 10:25:17 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Alexander Leidinger Subject: git: 3c3f886e4bc7 - main - hwpmc: add regression tests for detaching a live process-mode PMC List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: netchild X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 3c3f886e4bc7619f7847ad0d0f996088ddf5915a Auto-Submitted: auto-generated Date: Mon, 20 Jul 2026 10:25:17 +0000 Message-Id: <6a5df78d.32690.55283cc0@gitrepo.freebsd.org> The branch main has been updated by netchild: URL: https://cgit.FreeBSD.org/src/commit/?id=3c3f886e4bc7619f7847ad0d0f996088ddf5915a commit 3c3f886e4bc7619f7847ad0d0f996088ddf5915a Author: Alexander Leidinger AuthorDate: 2026-07-19 12:15:20 +0000 Commit: Alexander Leidinger CommitDate: 2026-07-20 10:24:55 +0000 hwpmc: add regression tests for detaching a live process-mode PMC Attach a process-mode counting PMC to the current process, start it, then detach and release it while it is still loaded on the hardware - the case that previously leaked the PMC's runcount reference and wedged pmc_wait_for_pmc_idle() at release. A second case does the same from a multi-threaded process so the sibling threads' references have to be drained too. The tests need an allocatable process-mode counting event and skip where none is available (hwpmc(4) not loaded, or a VM without a vPMU). Reviewed by: adrian MFC after: 2 weeks Assisted-by: Claude Code (Fable 5) Differential Revision: https://reviews.freebsd.org/D58343 --- tests/sys/pmc/Makefile | 2 + tests/sys/pmc/pmc_detach_test.c | 178 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) diff --git a/tests/sys/pmc/Makefile b/tests/sys/pmc/Makefile index 403acd0311ce..305a3e65c8b3 100644 --- a/tests/sys/pmc/Makefile +++ b/tests/sys/pmc/Makefile @@ -1,7 +1,9 @@ TESTSDIR= ${TESTSBASE}/sys/pmc ATF_TESTS_C= pmc_wrap_test +ATF_TESTS_C+= pmc_detach_test LIBADD+= pmc +LIBADD.pmc_detach_test+= pthread .include diff --git a/tests/sys/pmc/pmc_detach_test.c b/tests/sys/pmc/pmc_detach_test.c new file mode 100644 index 000000000000..05fda61b2836 --- /dev/null +++ b/tests/sys/pmc/pmc_detach_test.c @@ -0,0 +1,178 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2026 Alexander Leidinger + * + * 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 advertising materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +/* + * Regression tests for detaching a process-mode PMC from a target that + * still has it loaded on hardware. The runcount reference for a live + * PMC is dropped only by the context-switch-out reclaim, which the + * scheduler gates on P_HWPMC; detaching used to clear P_HWPMC without + * draining the reference, so the following release spun forever in + * pmc_wait_for_pmc_idle() - a panic ("waiting too long for pmc to be + * free") on an INVARIANTS kernel, an unkillable loop holding the hwpmc + * lock otherwise. + * + * The failure is deterministic: attaching a counting PMC to the current + * (running) thread and detaching it before release always left the + * reference live. On a kernel that carries the fix these tests complete + * immediately; run against a kernel that lacks it they would wedge, so + * (like any hwpmc regression test) they ship alongside the fix. + * + * They need an allocatable process-mode counting event, and skip where + * none is available (hwpmc(4) not loaded, or a VM without a vPMU). + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +static const char *counting_events[] = { + "instructions", + "cycles", + "branches", + "unhalted-core-cycles", + "inst_retired.any", + "cpu_clk_unhalted.thread", + "ls_not_halted_cyc", + NULL +}; + +static volatile int spin_stop; + +static void * +spinner(void *arg __unused) +{ + volatile unsigned long s = 0; + + while (spin_stop == 0) + s += 1; + return (NULL); +} + +static void +burn_cpu(void) +{ + volatile unsigned long s = 0; + int i; + + for (i = 0; i < 1000000; i++) + s += i; +} + +/* Allocate the first available process-mode counting PMC, or skip. */ +static pmc_id_t +alloc_counting_pmc(void) +{ + pmc_id_t id; + int i; + + if (pmc_init() != 0) + atf_tc_skip("hwpmc(4) is not available: %s", strerror(errno)); + + for (i = 0; counting_events[i] != NULL; i++) { + id = PMC_ID_INVALID; + if (pmc_allocate(counting_events[i], PMC_MODE_TC, 0, + PMC_CPU_ANY, &id, 0) == 0) + return (id); + } + atf_tc_skip("no allocatable process-mode counting event " + "(no vPMU?)"); + return (PMC_ID_INVALID); /* not reached */ +} + +ATF_TC(detach_live_self); +ATF_TC_HEAD(detach_live_self, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Detaching a running counting PMC from the current thread and " + "then releasing it does not leak its runcount reference"); + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(detach_live_self, tc) +{ + pmc_id_t id; + + id = alloc_counting_pmc(); + + ATF_REQUIRE(pmc_attach(id, 0) == 0); /* 0 == current process */ + ATF_REQUIRE(pmc_start(id) == 0); + burn_cpu(); /* make the counter live */ + + /* Detach while still loaded on this CPU, then release. */ + ATF_REQUIRE(pmc_detach(id, 0) == 0); + ATF_REQUIRE(pmc_release(id) == 0); /* wedged before the fix */ +} + +ATF_TC(detach_live_multithread); +ATF_TC_HEAD(detach_live_multithread, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Detaching a running process-scope counting PMC drains the " + "references held by the process' other threads"); + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(detach_live_multithread, tc) +{ + pthread_t th[3]; + pmc_id_t id; + int i, n; + + id = alloc_counting_pmc(); + + /* Sibling threads keep the process-scope PMC live on other CPUs. */ + spin_stop = 0; + for (n = 0; n < 3; n++) + ATF_REQUIRE(pthread_create(&th[n], NULL, spinner, NULL) == 0); + + ATF_REQUIRE(pmc_attach(id, 0) == 0); + ATF_REQUIRE(pmc_start(id) == 0); + burn_cpu(); + /* Let the siblings be scheduled and pick up the PMC. */ + usleep(200 * 1000); + + ATF_REQUIRE(pmc_detach(id, 0) == 0); + ATF_REQUIRE(pmc_release(id) == 0); /* must drain the siblings */ + + spin_stop = 1; + for (i = 0; i < n; i++) + pthread_join(th[i], NULL); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, detach_live_self); + ATF_TP_ADD_TC(tp, detach_live_multithread); + + return (atf_no_error()); +}