[PATCH vdsotest] Add support for clock_gettime64() on powerpc32

Christophe Leroy christophe.leroy at csgroup.eu
Sun May 10 02:12:20 AEST 2020


libc test is commented out because at the time being
very few libc if any supports clock_gettime64()

syscall number is hardcoded when it doesn't exists in unistd.h

Signed-off-by: Christophe Leroy <christophe.leroy at csgroup.eu>
---
Based on master from https://github.com/nathanlynch/vdsotest.git

 src/clock-boottime.c           |   4 +
 src/clock-monotonic-coarse.c   |   4 +
 src/clock-monotonic-raw.c      |   4 +
 src/clock-monotonic.c          |   4 +
 src/clock-realtime-coarse.c    |   4 +
 src/clock-realtime.c           |   4 +
 src/clock-tai.c                |   4 +
 src/clock_gettime64_template.c | 401 +++++++++++++++++++++++++++++++++
 8 files changed, 429 insertions(+)
 create mode 100644 src/clock_gettime64_template.c

diff --git a/src/clock-boottime.c b/src/clock-boottime.c
index 9fb1ac48501d..07ef31d08614 100644
--- a/src/clock-boottime.c
+++ b/src/clock-boottime.c
@@ -3,3 +3,7 @@
 
 #include "clock_gettime_template.c"
 #include "clock_getres_template.c"
+
+#if defined(__powerpc__) && !defined(__powerpc64__)
+#include "clock_gettime64_template.c"
+#endif
diff --git a/src/clock-monotonic-coarse.c b/src/clock-monotonic-coarse.c
index ca1df58691ca..da064188756f 100644
--- a/src/clock-monotonic-coarse.c
+++ b/src/clock-monotonic-coarse.c
@@ -3,3 +3,7 @@
 
 #include "clock_gettime_template.c"
 #include "clock_getres_template.c"
+
+#if defined(__powerpc__) && !defined(__powerpc64__)
+#include "clock_gettime64_template.c"
+#endif
diff --git a/src/clock-monotonic-raw.c b/src/clock-monotonic-raw.c
index 5dbb1842e698..55373b94ecfd 100644
--- a/src/clock-monotonic-raw.c
+++ b/src/clock-monotonic-raw.c
@@ -3,3 +3,7 @@
 
 #include "clock_gettime_template.c"
 #include "clock_getres_template.c"
+
+#if defined(__powerpc__) && !defined(__powerpc64__)
+#include "clock_gettime64_template.c"
+#endif
diff --git a/src/clock-monotonic.c b/src/clock-monotonic.c
index 44318ae1e1c2..a900d24598a1 100644
--- a/src/clock-monotonic.c
+++ b/src/clock-monotonic.c
@@ -3,3 +3,7 @@
 
 #include "clock_gettime_template.c"
 #include "clock_getres_template.c"
+
+#if defined(__powerpc__) && !defined(__powerpc64__)
+#include "clock_gettime64_template.c"
+#endif
diff --git a/src/clock-realtime-coarse.c b/src/clock-realtime-coarse.c
index 8f33f9a2d30b..8f2e6242bf0d 100644
--- a/src/clock-realtime-coarse.c
+++ b/src/clock-realtime-coarse.c
@@ -3,3 +3,7 @@
 
 #include "clock_gettime_template.c"
 #include "clock_getres_template.c"
+
+#if defined(__powerpc__) && !defined(__powerpc64__)
+#include "clock_gettime64_template.c"
+#endif
diff --git a/src/clock-realtime.c b/src/clock-realtime.c
index 079fd801e654..ab76329a6676 100644
--- a/src/clock-realtime.c
+++ b/src/clock-realtime.c
@@ -3,3 +3,7 @@
 
 #include "clock_gettime_template.c"
 #include "clock_getres_template.c"
+
+#if defined(__powerpc__) && !defined(__powerpc64__)
+#include "clock_gettime64_template.c"
+#endif
diff --git a/src/clock-tai.c b/src/clock-tai.c
index ad0448adeba5..cb2511039ddc 100644
--- a/src/clock-tai.c
+++ b/src/clock-tai.c
@@ -7,3 +7,7 @@
 
 #include "clock_gettime_template.c"
 #include "clock_getres_template.c"
+
+#if defined(__powerpc__) && !defined(__powerpc64__)
+#include "clock_gettime64_template.c"
+#endif
diff --git a/src/clock_gettime64_template.c b/src/clock_gettime64_template.c
new file mode 100644
index 000000000000..4752845148d6
--- /dev/null
+++ b/src/clock_gettime64_template.c
@@ -0,0 +1,401 @@
+/*
+ * Copyright 2014 Mentor Graphics Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <errno.h>
+#include <error.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "compiler.h"
+#include "vdsotest.h"
+
+struct timespec64 {
+	long long tv_sec;
+	long tv_nsec;
+};
+
+#ifndef SYS_clock_gettime64
+#define SYS_clock_gettime64 403
+#endif
+
+static int (*clock_gettime64_vdso)(clockid_t id, struct timespec64 *ts);
+
+static bool vdso_has_clock_gettime64(void)
+{
+	return clock_gettime64_vdso != NULL;
+}
+
+static int clock_gettime64_syscall_wrapper(clockid_t id, struct timespec64 *ts)
+{
+	return syscall(SYS_clock_gettime64, id, ts);
+}
+
+static void clock_gettime64_syscall_nofail(clockid_t id, struct timespec64 *ts)
+{
+	int err;
+
+	err = clock_gettime64_syscall_wrapper(id, ts);
+	if (err)
+		error(EXIT_FAILURE, errno, "SYS_clock_gettime64");
+}
+
+static int clock_gettime64_vdso_wrapper(clockid_t id, struct timespec64 *ts)
+{
+	return DO_VDSO_CALL(clock_gettime64_vdso, int, 2, id, ts);
+}
+
+static void clock_gettime64_vdso_nofail(clockid_t id, struct timespec64 *ts)
+{
+	int err;
+
+	err = clock_gettime64_vdso_wrapper(id, ts);
+	if (err)
+		error(EXIT_FAILURE, errno, "clock_gettime");
+}
+
+static bool timespecs64_ordered(const struct timespec64 *first,
+				const struct timespec64 *second)
+{
+	if (first->tv_sec < second->tv_sec)
+		return true;
+
+	if (first->tv_sec == second->tv_sec)
+		return first->tv_nsec <= second->tv_nsec;
+
+	return false;
+}
+
+static bool timespec64_normalized(const struct timespec64 *ts)
+{
+	if (ts->tv_sec < 0)
+		return false;
+	if (ts->tv_nsec < 0)
+		return false;
+	if (ts->tv_nsec >= NSEC_PER_SEC)
+		return false;
+	return true;
+}
+
+static void clock_gettime64_verify(struct ctx *ctx)
+{
+	struct timespec64 now;
+
+	clock_gettime64_syscall_nofail(CLOCK_ID, &now);
+
+	ctx_start_timer(ctx);
+
+	while (!test_should_stop(ctx)) {
+		struct timespec64 prev;
+
+		if (!vdso_has_clock_gettime64())
+			goto skip_vdso;
+
+		prev = now;
+
+		clock_gettime64_vdso_nofail(CLOCK_ID, &now);
+
+		if (!timespec64_normalized(&now)) {
+			log_failure(ctx, "timestamp obtained from libc/vDSO "
+				    "not normalized:\n"
+				    "\t[%ld, %ld]\n",
+				    (long int)now.tv_sec, (long int)now.tv_nsec);
+		}
+
+		if (!timespecs64_ordered(&prev, &now)) {
+			log_failure(ctx, "timestamp obtained from libc/vDSO "
+				    "predates timestamp\n"
+				    "previously obtained from kernel:\n"
+				    "\t[%ld, %ld] (kernel)\n"
+				    "\t[%ld, %ld] (vDSO)\n",
+				    (long int)prev.tv_sec, (long int)prev.tv_nsec,
+				    (long int)now.tv_sec, (long int)now.tv_nsec);
+		}
+
+	skip_vdso:
+		prev = now;
+
+		clock_gettime64_syscall_nofail(CLOCK_ID, &now);
+
+		if (!timespec64_normalized(&now)) {
+			log_failure(ctx, "timestamp obtained from kernel "
+				    "not normalized:\n"
+				    "\t[%ld, %ld]\n",
+				    (long int)now.tv_sec, (long int)now.tv_nsec);
+		}
+
+		if (!timespecs64_ordered(&prev, &now)) {
+			log_failure(ctx, "timestamp obtained from kernel "
+				    "predates timestamp\n"
+				    "previously obtained from libc/vDSO:\n"
+				    "\t[%ld, %ld] (vDSO)\n"
+				    "\t[%ld, %ld] (kernel)\n",
+				    (long int)prev.tv_sec, (long int)prev.tv_nsec,
+				    (long int)now.tv_sec, (long int)now.tv_nsec);
+		}
+
+	}
+
+	ctx_cleanup_timer(ctx);
+}
+
+static void clock_gettime64_bench(struct ctx *ctx, struct bench_results *res)
+{
+	struct timespec64 ts;
+
+	if (vdso_has_clock_gettime64()) {
+		BENCH(ctx, clock_gettime64_vdso_wrapper(CLOCK_ID, &ts),
+		      &res->vdso_interval);
+	}
+
+/*	BENCH(ctx, clock_gettime64(CLOCK_ID, &ts),
+	      &res->libc_interval);
+*/
+	BENCH(ctx, clock_gettime64_syscall_wrapper(CLOCK_ID, &ts),
+	      &res->sys_interval);
+}
+
+static void sys_clock_gettime64_simple(void *arg, struct syscall_result *res)
+{
+	int err;
+
+	syscall_prepare();
+	err = clock_gettime64_syscall_wrapper(CLOCK_ID, arg);
+	record_syscall_result(res, err, errno);
+}
+
+static void sys_clock_gettime64_prot(void *arg, struct syscall_result *res)
+{
+	void *buf;
+	int err;
+
+	buf = alloc_page((int)(unsigned long)arg);
+	syscall_prepare();
+	err = clock_gettime64_syscall_wrapper(CLOCK_ID, buf);
+	record_syscall_result(res, err, errno);
+	free_page(buf);
+}
+
+static void vdso_clock_gettime64_simple(void *arg, struct syscall_result *res)
+{
+	int err;
+
+	syscall_prepare();
+	err = clock_gettime64_vdso_wrapper(CLOCK_ID, arg);
+	record_syscall_result(res, err, errno);
+}
+
+static void vdso_clock_gettime64_prot(void *arg, struct syscall_result *res)
+{
+	void *buf;
+	int err;
+
+	buf = alloc_page((int)(unsigned long)arg);
+	syscall_prepare();
+	err = clock_gettime64_vdso_wrapper(CLOCK_ID, buf);
+	record_syscall_result(res, err, errno);
+	free_page(buf);
+}
+
+static void clock_gettime64_bogus_id(void *arg, struct syscall_result *res)
+{
+	struct timespec64 ts;
+	int err;
+
+	syscall_prepare();
+	err = arg ? clock_gettime64_syscall_wrapper((clockid_t)-1, &ts) :
+		clock_gettime64_vdso_wrapper((clockid_t)-1, &ts);
+
+	record_syscall_result(res, err, errno);
+}
+
+static void clock_gettime64_bogus_id_null(void *arg, struct syscall_result *res)
+{
+	int err;
+
+	syscall_prepare();
+	err = arg ? clock_gettime64_syscall_wrapper((clockid_t)-1, NULL) :
+		clock_gettime64_vdso_wrapper((clockid_t)-1, NULL);
+
+	record_syscall_result(res, err, errno);
+}
+
+static const struct child_params sys_clock_gettime64_abi_params[] = {
+
+	/* Kernel sanity checks */
+
+	{
+		.desc = "passing NULL to clock_gettime (syscall)",
+		.func = sys_clock_gettime64_simple,
+		.arg = NULL,
+		.expected_ret = -1,
+		.expected_errno = EFAULT,
+	},
+	{
+		.desc = "passing UINTPTR_MAX to clock_gettime (syscall)",
+		.func = sys_clock_gettime64_simple,
+		.arg = (void *)ADDR_SPACE_END,
+		.expected_ret = -1,
+		.expected_errno = EFAULT,
+	},
+	{
+		.desc = "passing PROT_NONE page to clock_gettime (syscall)",
+		.func = sys_clock_gettime64_prot,
+		.arg = (void *)PROT_NONE,
+		.expected_ret = -1,
+		.expected_errno = EFAULT,
+	},
+	{
+		.desc = "passing PROT_READ page to clock_gettime (syscall)",
+		.func = sys_clock_gettime64_prot,
+		.arg = (void *)PROT_READ,
+		.expected_ret = -1,
+		.expected_errno = EFAULT,
+	},
+	{
+		/* This will be duplicated across the different clock
+		 * id modules.  Oh well.
+		 */
+		.desc = "passing bogus clock id to clock_gettime (syscall)",
+		.func = clock_gettime64_bogus_id,
+		.arg = (void *)true, /* force syscall */
+		.expected_ret = -1,
+		.expected_errno = EINVAL,
+	},
+	{
+		/* This one too. */
+		.desc = "passing bogus clock id and NULL to clock_gettime (syscall)",
+		.func = clock_gettime64_bogus_id_null,
+		.arg = (void *)true, /* force syscall */
+		.expected_ret = -1,
+		.expected_errno = EINVAL,
+	},
+};
+
+static const struct child_params vdso_clock_gettime64_abi_params[] = {
+	/* The below will be serviced by a vDSO, if present. */
+
+	{
+		.desc = "passing NULL to clock_gettime (VDSO)",
+		.func = vdso_clock_gettime64_simple,
+		.arg = NULL,
+		.expected_ret = -1,
+		.expected_errno = EFAULT,
+		.signal_set = {
+			.mask = SIGNO_TO_BIT(SIGSEGV),
+		},
+	},
+	{
+		.desc = "passing UINTPTR_MAX to clock_gettime (VDSO)",
+		.func = vdso_clock_gettime64_simple,
+		.arg = (void *)ADDR_SPACE_END,
+		.expected_ret = -1,
+		.expected_errno = EFAULT,
+		.signal_set = {
+			.mask = SIGNO_TO_BIT(SIGSEGV),
+		},
+	},
+	{
+		.desc = "passing PROT_NONE page to clock_gettime (VDSO)",
+		.func = vdso_clock_gettime64_prot,
+		.arg = (void *)PROT_NONE,
+		.expected_ret = -1,
+		.expected_errno = EFAULT,
+		.signal_set = {
+			.mask = SIGNO_TO_BIT(SIGSEGV),
+		},
+	},
+	{
+		.desc = "passing PROT_READ page to clock_gettime (VDSO)",
+		.func = vdso_clock_gettime64_prot,
+		.arg = (void *)PROT_READ,
+		.expected_ret = -1,
+		.expected_errno = EFAULT,
+		.signal_set = {
+			.mask = SIGNO_TO_BIT(SIGSEGV),
+		},
+	},
+	{
+		/* This will be duplicated across the different clock
+		 * id modules.  Oh well.
+		 */
+		.desc = "passing bogus clock id to clock_gettime (VDSO)",
+		.func = clock_gettime64_bogus_id,
+		.arg = (void *)false, /* use vdso */
+		.expected_ret = -1,
+		.expected_errno = EINVAL,
+	},
+	{
+		/* This one too. */
+		.desc = "passing bogus clock id and NULL to clock_gettime (VDSO)",
+		.func = clock_gettime64_bogus_id_null,
+		.arg = (void *)false, /* use vdso */
+		.expected_ret = -1,
+		.expected_errno = EINVAL,
+	},
+};
+
+static void clock_gettime64_abi(struct ctx *ctx)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(sys_clock_gettime64_abi_params); i++)
+		run_as_child(ctx, &sys_clock_gettime64_abi_params[i]);
+
+	if (vdso_has_clock_gettime64()) {
+		for (i = 0; i < ARRAY_SIZE(vdso_clock_gettime64_abi_params); i++)
+			run_as_child(ctx, &vdso_clock_gettime64_abi_params[i]);
+	}
+}
+
+static void clock_gettime64_notes(struct ctx *ctx)
+{
+	if (!vdso_has_clock_gettime64())
+		printf("Note: vDSO version of clock_gettime64 not found\n");
+}
+
+static const char *clock_gettime64_vdso_names[] = {
+	"__kernel_clock_gettime64",
+	"__vdso_clock_gettime64",
+	NULL,
+};
+
+static void clock_gettime64_bind(void *sym)
+{
+	clock_gettime64_vdso = sym;
+}
+
+static const struct test_suite clock_gettime64_ts = {
+	.name = "clock-gettime64-" TS_SFX,
+	.bench = clock_gettime64_bench,
+	.verify = clock_gettime64_verify,
+	.abi = clock_gettime64_abi,
+	.notes = clock_gettime64_notes,
+	.vdso_names = clock_gettime64_vdso_names,
+	.bind = clock_gettime64_bind,
+};
+
+static void __constructor clock_gettime64_init(void)
+{
+	register_testsuite(&clock_gettime64_ts);
+}

base-commit: 7e4796a0695bdff3daca22630761264f5dff4680
-- 
2.25.0



More information about the Linuxppc-dev mailing list