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