hc
2024-05-14 bedbef8ad3e75a304af6361af235302bcc61d06b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// SPDX-License-Identifier: GPL-2.0
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <sched.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <dlfcn.h>
 
#include "log.h"
#include "timens.h"
 
typedef int (*vgettime_t)(clockid_t, struct timespec *);
 
vgettime_t vdso_clock_gettime;
 
static void fill_function_pointers(void)
{
   void *vdso = dlopen("linux-vdso.so.1",
               RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
   if (!vdso)
       vdso = dlopen("linux-gate.so.1",
                 RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
   if (!vdso) {
       pr_err("[WARN]\tfailed to find vDSO\n");
       return;
   }
 
   vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__vdso_clock_gettime");
   if (!vdso_clock_gettime)
       pr_err("Warning: failed to find clock_gettime in vDSO\n");
 
}
 
static void test(clock_t clockid, char *clockstr, bool in_ns)
{
   struct timespec tp, start;
   long i = 0;
   const int timeout = 3;
 
   vdso_clock_gettime(clockid, &start);
   tp = start;
   for (tp = start; start.tv_sec + timeout > tp.tv_sec ||
            (start.tv_sec + timeout == tp.tv_sec &&
             start.tv_nsec > tp.tv_nsec); i++) {
       vdso_clock_gettime(clockid, &tp);
   }
 
   ksft_test_result_pass("%s:\tclock: %10s\tcycles:\t%10ld\n",
                 in_ns ? "ns" : "host", clockstr, i);
}
 
int main(int argc, char *argv[])
{
   time_t offset = 10;
   int nsfd;
 
   ksft_set_plan(8);
 
   fill_function_pointers();
 
   test(CLOCK_MONOTONIC, "monotonic", false);
   test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", false);
   test(CLOCK_MONOTONIC_RAW, "monotonic-raw", false);
   test(CLOCK_BOOTTIME, "boottime", false);
 
   nscheck();
 
   if (unshare_timens())
       return 1;
 
   nsfd = open("/proc/self/ns/time_for_children", O_RDONLY);
   if (nsfd < 0)
       return pr_perror("Can't open a time namespace");
 
   if (_settime(CLOCK_MONOTONIC, offset))
       return 1;
   if (_settime(CLOCK_BOOTTIME, offset))
       return 1;
 
   if (setns(nsfd, CLONE_NEWTIME))
       return pr_perror("setns");
 
   test(CLOCK_MONOTONIC, "monotonic", true);
   test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", true);
   test(CLOCK_MONOTONIC_RAW, "monotonic-raw", true);
   test(CLOCK_BOOTTIME, "boottime", true);
 
   ksft_exit_pass();
   return 0;
}