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.le...@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

Reply via email to