From: "Thomas Weißschuh" <thomas.weissschuh@linutronix.de>
To: Andy Lutomirski <luto@kernel.org>,
Thomas Gleixner <tglx@linutronix.de>,
Vincenzo Frascino <vincenzo.frascino@arm.com>,
Shuah Khan <shuah@kernel.org>,
Anna-Maria Behnsen <anna-maria@linutronix.de>,
Frederic Weisbecker <frederic@kernel.org>,
John Stultz <jstultz@google.com>,
Stephen Boyd <sboyd@kernel.org>,
Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>, Arnd Bergmann <arnd@arndb.de>
Cc: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-arch@vger.kernel.org,
"Richard Cochran" <richardcochran@gmail.com>,
"Christopher Hall" <christopher.s.hall@intel.com>,
"Frederic Weisbecker" <frederic@kernel.org>,
"Anna-Maria Behnsen" <anna-maria@linutronix.de>,
"Miroslav Lichvar" <mlichvar@redhat.com>,
"Werner Abt" <werner.abt@meinberg-usa.com>,
"David Woodhouse" <dwmw2@infradead.org>,
"Stephen Boyd" <sboyd@kernel.org>,
"Kurt Kanzenbach" <kurt@linutronix.de>,
"Nam Cao" <namcao@linutronix.de>,
"Antoine Tenart" <atenart@kernel.org>,
"Thomas Weißschuh" <thomas.weissschuh@linutronix.de>
Subject: [PATCH 01/14] selftests/timers: Add testcase for auxiliary clocks
Date: Tue, 01 Jul 2025 10:57:55 +0200 [thread overview]
Message-ID: <20250701-vdso-auxclock-v1-1-df7d9f87b9b8@linutronix.de> (raw)
In-Reply-To: <20250701-vdso-auxclock-v1-0-df7d9f87b9b8@linutronix.de>
Auxiliary clocks behave differently from regular ones.
Add a testcase to validate their functionality.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
tools/testing/selftests/timers/.gitignore | 1 +
tools/testing/selftests/timers/Makefile | 2 +-
tools/testing/selftests/timers/auxclock.c | 319 ++++++++++++++++++++++++++++++
3 files changed, 321 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/timers/.gitignore b/tools/testing/selftests/timers/.gitignore
index bb5326ff900b8edc3aa2d8d596599973593fbaf0..dcee43b3ecd9351c9bb0483088d712ccd7b57367 100644
--- a/tools/testing/selftests/timers/.gitignore
+++ b/tools/testing/selftests/timers/.gitignore
@@ -20,3 +20,4 @@ valid-adjtimex
adjtick
set-tz
freq-step
+auxclock
diff --git a/tools/testing/selftests/timers/Makefile b/tools/testing/selftests/timers/Makefile
index 32203593c62e1e0cdfd3de6f567ea1e82913f2ef..3a8833b3fb7449495c66a92c4d82e35a6755b5e8 100644
--- a/tools/testing/selftests/timers/Makefile
+++ b/tools/testing/selftests/timers/Makefile
@@ -5,7 +5,7 @@ LDLIBS += -lrt -lpthread -lm
# these are all "safe" tests that don't modify
# system time or require escalated privileges
TEST_GEN_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \
- inconsistency-check raw_skew threadtest rtcpie
+ inconsistency-check raw_skew threadtest rtcpie auxclock
DESTRUCTIVE_TESTS = alarmtimer-suspend valid-adjtimex adjtick change_skew \
skew_consistency clocksource-switch freq-step leap-a-day \
diff --git a/tools/testing/selftests/timers/auxclock.c b/tools/testing/selftests/timers/auxclock.c
new file mode 100644
index 0000000000000000000000000000000000000000..0ba2f9996114ade3147f0f3aec49904556a23cd4
--- /dev/null
+++ b/tools/testing/selftests/timers/auxclock.c
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Work around type conflicts between libc and the UAPI headers */
+#define _SYS_TIME_H
+#define __timeval_defined
+#define _GNU_SOURCE
+
+#include <fcntl.h>
+#include <linux/types.h>
+#include <linux/timex.h>
+#include <sched.h>
+#include <stdio.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "../kselftest_harness.h"
+
+#ifndef CLOCK_AUX
+#define CLOCK_AUX 16
+#endif
+
+#ifndef NSEC_PER_SEC
+#define NSEC_PER_SEC 1000000000ULL
+#endif
+
+#define AUXCLOCK_SELFTEST_TIMENS_OFFSET 10000
+
+static int configure_auxclock(__kernel_clockid_t clockid, bool enable)
+{
+ char path[100];
+ int fd, ret;
+
+ ret = snprintf(path, sizeof(path),
+ "/sys/kernel/time/aux_clocks/%d/aux_clock_enable",
+ (int)clockid - CLOCK_AUX);
+ if (ret >= sizeof(path))
+ return -ENOSPC;
+
+ fd = open(path, O_WRONLY);
+ if (fd == -1)
+ return -errno;
+
+ /* Always disable to reset */
+ ret = dprintf(fd, "0\n");
+ if (enable)
+ ret = dprintf(fd, "1\n");
+ close(fd);
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/* Everything is done in terms of 64bit time values to keep the code readable */
+
+static inline void timespec_to_kernel_timespec(const struct timespec *ts,
+ struct __kernel_timespec *kts)
+{
+ if (!kts)
+ return;
+
+ kts->tv_sec = ts->tv_sec;
+ kts->tv_nsec = ts->tv_nsec;
+}
+
+static inline void kernel_timespec_to_timespec(const struct __kernel_timespec *kts,
+ struct timespec *ts)
+{
+ if (!kts)
+ return;
+
+ ts->tv_sec = kts->tv_sec;
+ ts->tv_nsec = kts->tv_nsec;
+}
+
+static int sys_clock_getres_time64(__kernel_clockid_t clockid, struct __kernel_timespec *ts)
+{
+#if defined(__NR_clock_getres_time64)
+ return syscall(__NR_clock_getres_time64, clockid, ts);
+#elif defined(__NR_clock_getres)
+ struct timespec _ts;
+ int ret;
+
+ ret = syscall(__NR_clock_getres, clockid, &_ts);
+ if (!ret)
+ timespec_to_kernel_timespec(&_ts, ts);
+ return ret;
+#else
+#error "No clock_getres() support"
+#endif
+}
+
+static int sys_clock_gettime64(__kernel_clockid_t clockid, struct __kernel_timespec *ts)
+{
+#if defined(__NR_clock_gettime64)
+ return syscall(__NR_clock_gettime64, clockid, ts);
+#elif defined(__NR_clock_gettime)
+ struct timespec _ts;
+ int ret;
+
+ ret = syscall(__NR_clock_gettime, clockid, &_ts);
+ if (!ret)
+ timespec_to_kernel_timespec(&_ts, ts);
+ return ret;
+#else
+#error "No clock_gettime() support"
+#endif
+}
+
+static int sys_clock_settime64(__kernel_clockid_t clockid, const struct __kernel_timespec *ts)
+{
+#if defined(__NR_clock_settime64)
+ return syscall(__NR_clock_settime64, clockid, ts);
+#elif defined(__NR_clock_settime)
+ struct timespec _ts;
+
+ kernel_timespec_to_timespec(ts, &_ts);
+ return syscall(__NR_clock_settime, clockid, &_ts);
+#else
+#error "No clock_settime() support"
+#endif
+}
+
+static int sys_clock_adjtime64(__kernel_clockid_t clockid, struct __kernel_timex *tx)
+{
+#if defined(__NR_clock_adjtime64)
+ return syscall(__NR_clock_adjtime64, clockid, tx);
+#elif __LONG_WIDTH__ == 64 && defined(__NR_clock_adjtime)
+ return syscall(__NR_clock_adjtime, clockid, tx);
+#else
+#error "No clock_adjtime() support"
+#endif
+}
+
+FIXTURE(auxclock) {};
+
+FIXTURE_VARIANT(auxclock) {
+ __kernel_clockid_t clock;
+ bool clock_enabled;
+ bool use_timens;
+};
+
+FIXTURE_VARIANT_ADD(auxclock, default) {
+ .clock = CLOCK_AUX,
+ .clock_enabled = true,
+ .use_timens = false,
+};
+
+FIXTURE_VARIANT_ADD(auxclock, timens) {
+ .clock = CLOCK_AUX,
+ .clock_enabled = true,
+ .use_timens = true,
+};
+
+FIXTURE_VARIANT_ADD(auxclock, disabled) {
+ .clock = CLOCK_AUX,
+ .clock_enabled = false,
+ .use_timens = false,
+};
+
+/* No timens_disabled to keep the testmatrix smaller. */
+
+static void enter_timens(struct __test_metadata *_metadata)
+{
+ int ret, fd;
+ char buf[100];
+
+ ret = unshare(CLONE_NEWTIME);
+ if (ret != 0 && errno == EPERM)
+ SKIP(return, "no permissions for unshare(CLONE_NEWTIME)");
+ if (ret != 0 && errno == EINVAL)
+ SKIP(return, "time namespaces not available");
+ ASSERT_EQ(0, ret) TH_LOG("unshare(CLONE_NEWTIME) failed: %s", strerror(errno));
+ fd = open("/proc/self/timens_offsets", O_WRONLY);
+ if (fd == -1 && errno == ENOENT)
+ SKIP(return, "no support for time namespaces");
+ ASSERT_NE(-1, fd);
+ /* Fiddle with the namespace to make the tests more meaningful */
+ ret = snprintf(buf, sizeof(buf), "monotonic %d 0\nboottime %d 0\n",
+ AUXCLOCK_SELFTEST_TIMENS_OFFSET, AUXCLOCK_SELFTEST_TIMENS_OFFSET);
+ ASSERT_TRUE(ret > 0 && ret < sizeof(buf));
+ ret = write(fd, buf, ret);
+ ASSERT_NE(-1, ret);
+ close(fd);
+ fd = open("/proc/self/ns/time_for_children", O_RDONLY);
+ ASSERT_NE(-1, fd);
+ ret = setns(fd, CLONE_NEWTIME);
+ close(fd);
+ ASSERT_EQ(0, ret);
+}
+
+FIXTURE_SETUP(auxclock) {
+ int ret;
+
+ ret = configure_auxclock(variant->clock, variant->clock_enabled);
+ if (ret == -ENOENT)
+ SKIP(return, "auxclocks not enabled");
+ ASSERT_EQ(0, ret);
+
+ if (variant->use_timens)
+ enter_timens(_metadata);
+}
+
+FIXTURE_TEARDOWN(auxclock) {
+ int ret;
+
+ ret = configure_auxclock(variant->clock, false);
+ ASSERT_EQ(0, ret);
+}
+
+TEST_F(auxclock, sys_clock_getres) {
+ struct __kernel_timespec ts;
+ int ret;
+
+ /* clock_getres() is always expected to work */
+ ret = sys_clock_getres_time64(variant->clock, &ts);
+ ASSERT_EQ(0, ret);
+ ASSERT_EQ(0, ts.tv_sec);
+ ASSERT_EQ(1, ts.tv_nsec);
+}
+
+TEST_F(auxclock, sys_clock_gettime) {
+ struct __kernel_timespec ts;
+ int ret;
+
+ ret = sys_clock_gettime64(variant->clock, &ts);
+ if (variant->clock_enabled) {
+ ASSERT_EQ(0, ret);
+ } else {
+ ASSERT_EQ(-1, ret);
+ ASSERT_EQ(ENODEV, errno);
+ }
+}
+
+static void auxclock_validate_progression(struct __test_metadata *_metadata,
+ const struct __kernel_timespec *a,
+ const struct __kernel_timespec *b)
+{
+ int64_t diff;
+
+ diff = (b->tv_sec - a->tv_sec) * NSEC_PER_SEC;
+ diff += b->tv_nsec - a->tv_nsec;
+
+ /* Arbitrary values */
+ ASSERT_LT(1, diff);
+ ASSERT_GT(1 * NSEC_PER_SEC, diff);
+}
+
+TEST_F(auxclock, sys_clock_settime) {
+ struct __kernel_timespec a, b = {};
+ int ret;
+
+ a.tv_sec = 1234;
+ a.tv_nsec = 5678;
+
+ ret = sys_clock_settime64(variant->clock, &a);
+ if (!variant->clock_enabled) {
+ ASSERT_EQ(-1, ret);
+ ASSERT_EQ(ENODEV, errno);
+ return;
+ }
+
+ ASSERT_EQ(0, ret);
+
+ ret = sys_clock_gettime64(variant->clock, &b);
+ ASSERT_EQ(0, ret);
+
+ auxclock_validate_progression(_metadata, &a, &b);
+}
+
+TEST_F(auxclock, sys_clock_adjtime) {
+ struct __kernel_timex tx;
+ int ret, realtime_freq;
+
+ memset(&tx, 0, sizeof(tx));
+ tx.modes = ADJ_FREQUENCY;
+ ret = sys_clock_adjtime64(CLOCK_REALTIME, &tx);
+ ASSERT_NE(-1, ret);
+ ASSERT_TRUE(tx.modes & ADJ_FREQUENCY);
+ realtime_freq = tx.freq;
+
+ ret = sys_clock_adjtime64(variant->clock, &tx);
+ if (variant->clock_enabled) {
+ ASSERT_NE(-1, ret);
+ ASSERT_EQ(realtime_freq, tx.freq);
+ } else {
+ ASSERT_EQ(-1, ret);
+ ASSERT_EQ(ENODEV, errno);
+ }
+}
+
+TEST_F(auxclock, progression) {
+ struct __kernel_timespec a, b;
+ int ret;
+
+ if (!variant->clock_enabled) {
+ TH_LOG("no progression on disabled clocks");
+ return;
+ }
+
+ /* set up reference */
+ ret = sys_clock_gettime64(variant->clock, &a);
+ ASSERT_EQ(0, ret);
+
+ for (int i = 0; i < 100; i++) {
+ memset(&b, 0, sizeof(b));
+ ret = sys_clock_gettime64(variant->clock, &b);
+ ASSERT_EQ(0, ret);
+ auxclock_validate_progression(_metadata, &a, &b);
+
+ memset(&a, 0, sizeof(a));
+ ret = sys_clock_gettime64(variant->clock, &a);
+ ASSERT_EQ(0, ret);
+ auxclock_validate_progression(_metadata, &b, &a);
+ }
+}
+
+TEST_HARNESS_MAIN
--
2.50.0
next prev parent reply other threads:[~2025-07-01 8:58 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-01 8:57 [PATCH 00/14] vdso: Add support for auxiliary clocks Thomas Weißschuh
2025-07-01 8:57 ` Thomas Weißschuh [this message]
2025-07-01 8:57 ` [PATCH 02/14] vdso/vsyscall: Introduce a helper to fill clock configurations Thomas Weißschuh
2025-07-01 8:57 ` [PATCH 03/14] vdso/vsyscall: Split up __arch_update_vsyscall() into __arch_update_vdso_clock() Thomas Weißschuh
2025-07-01 8:57 ` [PATCH 04/14] vdso/helpers: Add helpers for seqlocks of single vdso_clock Thomas Weißschuh
2025-07-01 8:57 ` [PATCH 05/14] vdso/gettimeofday: Return bool from clock_getres() helpers Thomas Weißschuh
2025-07-01 8:58 ` [PATCH 06/14] vdso/gettimeofday: Return bool from clock_gettime() helpers Thomas Weißschuh
[not found] ` <CGME20250708151720eucas1p260f984fd95d3460d3e9f6c9b48e0e25c@eucas1p2.samsung.com>
2025-07-08 15:17 ` Marek Szyprowski
[not found] ` <CGME20250708154921eucas1p1fd8fa4374610a991ca5c67bd612ca0c2@eucas1p1.samsung.com>
2025-07-08 15:49 ` Marek Szyprowski
2025-07-09 7:34 ` Thomas Weißschuh
2025-07-09 8:04 ` Marek Szyprowski
2025-07-16 12:25 ` Mark Brown
2025-07-16 12:34 ` Thomas Weißschuh
2025-07-16 12:50 ` Mark Brown
2025-07-16 13:23 ` Thomas Weißschuh
2025-07-16 14:35 ` Mark Brown
2025-07-18 12:02 ` Thomas Weißschuh
2025-07-19 11:16 ` David Laight
2025-07-09 8:29 ` Mark Brown
2025-07-01 8:58 ` [PATCH 07/14] vdso/gettimeofday: Introduce vdso_clockid_valid() Thomas Weißschuh
2025-07-01 8:58 ` [PATCH 08/14] vdso/gettimeofday: Introduce vdso_set_timespec() Thomas Weißschuh
2025-07-01 8:58 ` [PATCH 09/14] vdso/gettimeofday: Introduce vdso_get_timestamp() Thomas Weißschuh
2025-07-01 8:58 ` [PATCH 10/14] vdso: Introduce aux_clock_resolution_ns() Thomas Weißschuh
2025-07-01 8:58 ` [PATCH 11/14] vdso/vsyscall: Update auxiliary clock data in the datapage Thomas Weißschuh
2025-07-07 6:57 ` Thomas Gleixner
2025-07-07 11:34 ` Arnd Bergmann
2025-07-07 13:16 ` Thomas Gleixner
2025-07-07 14:48 ` Arnd Bergmann
2025-07-01 8:58 ` [PATCH 12/14] vdso/gettimeofday: Add support for auxiliary clocks Thomas Weißschuh
2025-07-06 19:31 ` Thomas Gleixner
2025-08-20 8:03 ` John Stultz
2025-08-20 10:15 ` Thomas Weißschuh
2025-07-01 8:58 ` [PATCH 13/14] Revert "selftests: vDSO: parse_vdso: Use UAPI headers instead of libc headers" Thomas Weißschuh
2025-07-06 20:43 ` Thomas Gleixner
2025-07-07 6:21 ` Thomas Weißschuh
2025-07-01 8:58 ` [PATCH 14/14] selftests/timers/auxclock: Test vDSO functionality Thomas Weißschuh
2025-07-06 20:26 ` Thomas Gleixner
2025-07-07 7:17 ` Thomas Weißschuh
2025-07-07 13:18 ` Thomas Gleixner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250701-vdso-auxclock-v1-1-df7d9f87b9b8@linutronix.de \
--to=thomas.weissschuh@linutronix.de \
--cc=anna-maria@linutronix.de \
--cc=arnd@arndb.de \
--cc=atenart@kernel.org \
--cc=catalin.marinas@arm.com \
--cc=christopher.s.hall@intel.com \
--cc=dwmw2@infradead.org \
--cc=frederic@kernel.org \
--cc=jstultz@google.com \
--cc=kurt@linutronix.de \
--cc=linux-arch@vger.kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=luto@kernel.org \
--cc=mlichvar@redhat.com \
--cc=namcao@linutronix.de \
--cc=richardcochran@gmail.com \
--cc=sboyd@kernel.org \
--cc=shuah@kernel.org \
--cc=tglx@linutronix.de \
--cc=vincenzo.frascino@arm.com \
--cc=werner.abt@meinberg-usa.com \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).