| // SPDX-License-Identifier: GPL-2.0-or-later |
| /* |
| * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz> |
| */ |
| |
| #include <time.h> |
| |
| #define TST_NO_DEFAULT_MAIN |
| #include "tst_test.h" |
| #include "tst_timer.h" |
| #include "tst_clocks.h" |
| #include "lapi/syscalls.h" |
| #include "lapi/posix_clocks.h" |
| |
| typedef int (*mysyscall)(clockid_t clk_id, void *ts); |
| |
| int syscall_supported_by_kernel(long sysnr) |
| { |
| int ret; |
| |
| ret = syscall(sysnr, 0, NULL); |
| if (ret == -1 && errno == ENOSYS) |
| return 0; |
| |
| return 1; |
| } |
| |
| int tst_clock_getres(clockid_t clk_id, struct timespec *res) |
| { |
| static struct tst_ts tts = { 0, }; |
| static mysyscall func; |
| int ret; |
| |
| #if (__NR_clock_getres_time64 != __LTP__NR_INVALID_SYSCALL) |
| if (!func && syscall_supported_by_kernel(__NR_clock_getres_time64)) { |
| func = sys_clock_getres64; |
| tts.type = TST_KERN_TIMESPEC; |
| } |
| #endif |
| |
| if (!func && syscall_supported_by_kernel(__NR_clock_getres)) { |
| func = sys_clock_getres; |
| tts.type = TST_KERN_OLD_TIMESPEC; |
| } |
| |
| if (!func) { |
| tst_res(TCONF, "clock_getres() not available"); |
| errno = ENOSYS; |
| return -1; |
| } |
| |
| ret = func(clk_id, tst_ts_get(&tts)); |
| res->tv_sec = tst_ts_get_sec(tts); |
| res->tv_nsec = tst_ts_get_nsec(tts); |
| return ret; |
| } |
| |
| int tst_clock_gettime(clockid_t clk_id, struct timespec *ts) |
| { |
| static struct tst_ts tts = { 0, }; |
| static mysyscall func; |
| int ret; |
| |
| #if (__NR_clock_gettime64 != __LTP__NR_INVALID_SYSCALL) |
| if (!func && syscall_supported_by_kernel(__NR_clock_gettime64)) { |
| func = sys_clock_gettime64; |
| tts.type = TST_KERN_TIMESPEC; |
| } |
| #endif |
| |
| if (!func && syscall_supported_by_kernel(__NR_clock_gettime)) { |
| func = sys_clock_gettime; |
| tts.type = TST_KERN_OLD_TIMESPEC; |
| } |
| |
| if (!func) { |
| tst_res(TCONF, "clock_gettime() not available"); |
| errno = ENOSYS; |
| return -1; |
| } |
| |
| ret = func(clk_id, tst_ts_get(&tts)); |
| ts->tv_sec = tst_ts_get_sec(tts); |
| ts->tv_nsec = tst_ts_get_nsec(tts); |
| return ret; |
| } |
| |
| int tst_clock_settime(clockid_t clk_id, struct timespec *ts) |
| { |
| static struct tst_ts tts = { 0, }; |
| static mysyscall func; |
| |
| #if (__NR_clock_settime64 != __LTP__NR_INVALID_SYSCALL) |
| if (!func && syscall_supported_by_kernel(__NR_clock_settime64)) { |
| func = sys_clock_settime64; |
| tts.type = TST_KERN_TIMESPEC; |
| } |
| #endif |
| |
| if (!func && syscall_supported_by_kernel(__NR_clock_settime)) { |
| func = sys_clock_settime; |
| tts.type = TST_KERN_OLD_TIMESPEC; |
| } |
| |
| if (!func) { |
| tst_res(TCONF, "clock_settime() not available"); |
| errno = ENOSYS; |
| return -1; |
| } |
| |
| tst_ts_set_sec(&tts, ts->tv_sec); |
| tst_ts_set_nsec(&tts, ts->tv_nsec); |
| return func(clk_id, tst_ts_get(&tts)); |
| } |
| |
| const char *tst_clock_name(clockid_t clk_id) |
| { |
| switch (clk_id) { |
| case CLOCK_REALTIME: |
| return "CLOCK_REALTIME"; |
| case CLOCK_MONOTONIC: |
| return "CLOCK_MONOTONIC"; |
| case CLOCK_PROCESS_CPUTIME_ID: |
| return "CLOCK_PROCESS_CPUTIME_ID"; |
| case CLOCK_THREAD_CPUTIME_ID: |
| return "CLOCK_THREAD_CPUTIME_ID"; |
| case CLOCK_MONOTONIC_RAW: |
| return "CLOCK_MONOTONIC_RAW"; |
| case CLOCK_REALTIME_COARSE: |
| return "CLOCK_REALTIME_COARSE"; |
| case CLOCK_MONOTONIC_COARSE: |
| return "CLOCK_MONOTONIC_COARSE"; |
| case CLOCK_BOOTTIME: |
| return "CLOCK_BOOTTIME"; |
| case CLOCK_REALTIME_ALARM: |
| return "CLOCK_REALTIME_ALARM"; |
| case CLOCK_BOOTTIME_ALARM: |
| return "CLOCK_BOOTTIME_ALARM"; |
| case CLOCK_TAI: |
| return "CLOCK_TAI"; |
| default: |
| return "INVALID/UNKNOWN CLOCK"; |
| } |
| } |