18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#define _GNU_SOURCE 38c2ecf20Sopenharmony_ci#include <sys/types.h> 48c2ecf20Sopenharmony_ci#include <sys/stat.h> 58c2ecf20Sopenharmony_ci#include <errno.h> 68c2ecf20Sopenharmony_ci#include <fcntl.h> 78c2ecf20Sopenharmony_ci#include <sched.h> 88c2ecf20Sopenharmony_ci#include <time.h> 98c2ecf20Sopenharmony_ci#include <stdio.h> 108c2ecf20Sopenharmony_ci#include <unistd.h> 118c2ecf20Sopenharmony_ci#include <sys/syscall.h> 128c2ecf20Sopenharmony_ci#include <dlfcn.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "log.h" 158c2ecf20Sopenharmony_ci#include "timens.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_citypedef int (*vgettime_t)(clockid_t, struct timespec *); 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_civgettime_t vdso_clock_gettime; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic void fill_function_pointers(void) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci void *vdso = dlopen("linux-vdso.so.1", 248c2ecf20Sopenharmony_ci RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); 258c2ecf20Sopenharmony_ci if (!vdso) 268c2ecf20Sopenharmony_ci vdso = dlopen("linux-gate.so.1", 278c2ecf20Sopenharmony_ci RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); 288c2ecf20Sopenharmony_ci if (!vdso) { 298c2ecf20Sopenharmony_ci pr_err("[WARN]\tfailed to find vDSO\n"); 308c2ecf20Sopenharmony_ci return; 318c2ecf20Sopenharmony_ci } 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__vdso_clock_gettime"); 348c2ecf20Sopenharmony_ci if (!vdso_clock_gettime) 358c2ecf20Sopenharmony_ci pr_err("Warning: failed to find clock_gettime in vDSO\n"); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic void test(clock_t clockid, char *clockstr, bool in_ns) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct timespec tp, start; 428c2ecf20Sopenharmony_ci long i = 0; 438c2ecf20Sopenharmony_ci const int timeout = 3; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci vdso_clock_gettime(clockid, &start); 468c2ecf20Sopenharmony_ci tp = start; 478c2ecf20Sopenharmony_ci for (tp = start; start.tv_sec + timeout > tp.tv_sec || 488c2ecf20Sopenharmony_ci (start.tv_sec + timeout == tp.tv_sec && 498c2ecf20Sopenharmony_ci start.tv_nsec > tp.tv_nsec); i++) { 508c2ecf20Sopenharmony_ci vdso_clock_gettime(clockid, &tp); 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci ksft_test_result_pass("%s:\tclock: %10s\tcycles:\t%10ld\n", 548c2ecf20Sopenharmony_ci in_ns ? "ns" : "host", clockstr, i); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciint main(int argc, char *argv[]) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci time_t offset = 10; 608c2ecf20Sopenharmony_ci int nsfd; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci ksft_set_plan(8); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci fill_function_pointers(); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci test(CLOCK_MONOTONIC, "monotonic", false); 678c2ecf20Sopenharmony_ci test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", false); 688c2ecf20Sopenharmony_ci test(CLOCK_MONOTONIC_RAW, "monotonic-raw", false); 698c2ecf20Sopenharmony_ci test(CLOCK_BOOTTIME, "boottime", false); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci nscheck(); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (unshare_timens()) 748c2ecf20Sopenharmony_ci return 1; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci nsfd = open("/proc/self/ns/time_for_children", O_RDONLY); 778c2ecf20Sopenharmony_ci if (nsfd < 0) 788c2ecf20Sopenharmony_ci return pr_perror("Can't open a time namespace"); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (_settime(CLOCK_MONOTONIC, offset)) 818c2ecf20Sopenharmony_ci return 1; 828c2ecf20Sopenharmony_ci if (_settime(CLOCK_BOOTTIME, offset)) 838c2ecf20Sopenharmony_ci return 1; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (setns(nsfd, CLONE_NEWTIME)) 868c2ecf20Sopenharmony_ci return pr_perror("setns"); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci test(CLOCK_MONOTONIC, "monotonic", true); 898c2ecf20Sopenharmony_ci test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", true); 908c2ecf20Sopenharmony_ci test(CLOCK_MONOTONIC_RAW, "monotonic-raw", true); 918c2ecf20Sopenharmony_ci test(CLOCK_BOOTTIME, "boottime", true); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci ksft_exit_pass(); 948c2ecf20Sopenharmony_ci return 0; 958c2ecf20Sopenharmony_ci} 96