6
6
//
7
7
// ===----------------------------------------------------------------------===//
8
8
9
+ #include " hdr/signal_macros.h"
9
10
#include " hdr/time_macros.h"
10
11
#include " hdr/types/clockid_t.h"
12
+ #include " hdr/types/struct_sigaction.h"
11
13
#include " hdr/types/struct_timespec.h"
12
14
#include " hdr/types/struct_timeval.h"
13
- #include " include/llvm-libc-macros/linux/time-macros .h"
15
+ #include " hdr/types/time_t .h"
14
16
#include " src/__support/OSUtil/linux/vdso.h"
17
+ #include " src/__support/OSUtil/syscall.h"
18
+ #include " src/signal/raise.h"
19
+ #include " src/signal/sigaction.h"
20
+ #include " test/UnitTest/ErrnoSetterMatcher.h"
15
21
#include " test/UnitTest/LibcTest.h"
16
22
#include " test/UnitTest/Test.h"
23
+ #include < linux/time_types.h>
24
+ #include < sys/syscall.h>
17
25
18
26
namespace LIBC_NAMESPACE {
19
- TEST (LlvmLibcOSUtilVDSOTest, SymbolsDefined) {
20
- for (size_t i = 0 ; i < static_cast <size_t >(vdso::VDSOSym::VDSOSymCount);
21
- ++i) {
22
- // riscv_hwprobe is provided only on >=6.4 kernels. Skip it for now.
23
- #ifdef LIBC_VDSO_HAS_RISCV_HWPROBE
24
- if (static_cast <vdso::VDSOSym>(i) == vdso::VDSOSym::RiscvHwProbe)
25
- continue ;
26
- #endif
27
- EXPECT_NE (vdso::get_symbol (static_cast <vdso::VDSOSym>(i)),
28
- static_cast <void *>(nullptr ));
29
- }
30
- }
31
-
32
27
#ifdef LIBC_VDSO_HAS_GETTIMEOFDAY
33
28
TEST (LlvmLibcOSUtilVDSOTest, GetTimeOfDay) {
34
29
using FuncTy = int (*)(timeval *, struct timezone *);
35
30
auto func =
36
31
reinterpret_cast <FuncTy>(vdso::get_symbol (vdso::VDSOSym::GetTimeOfDay));
32
+ if (func == nullptr )
33
+ return ;
37
34
timeval tv;
38
35
EXPECT_EQ (func (&tv, nullptr ), 0 );
39
36
// hopefully people are not building time machines using our libc.
40
37
EXPECT_GT (tv.tv_sec , static_cast <decltype (tv.tv_sec )>(0 ));
41
38
}
42
39
#endif
43
40
41
+ #ifdef LIBC_VDSO_HAS_TIME
42
+ TEST (LlvmLibcOSUtilVDSOTest, Time) {
43
+ using FuncTy = time_t (*)(time_t *);
44
+ auto func = reinterpret_cast <FuncTy>(vdso::get_symbol (vdso::VDSOSym::Time));
45
+ if (func == nullptr )
46
+ return ;
47
+ time_t a, b;
48
+ EXPECT_GT (func (&a), static_cast <time_t >(0 ));
49
+ EXPECT_GT (func (&b), static_cast <time_t >(0 ));
50
+ EXPECT_GE (b, a);
51
+ }
52
+ #endif
53
+
44
54
#ifdef LIBC_VDSO_HAS_CLOCK_GETTIME
45
55
TEST (LlvmLibcOSUtilVDSOTest, ClockGetTime) {
46
56
using FuncTy = int (*)(clockid_t , timespec *);
47
57
auto func =
48
58
reinterpret_cast <FuncTy>(vdso::get_symbol (vdso::VDSOSym::ClockGetTime));
59
+ if (func == nullptr )
60
+ return ;
49
61
timespec a, b;
50
62
EXPECT_EQ (func (CLOCK_MONOTONIC, &a), 0 );
51
63
EXPECT_EQ (func (CLOCK_MONOTONIC, &b), 0 );
@@ -57,15 +69,137 @@ TEST(LlvmLibcOSUtilVDSOTest, ClockGetTime) {
57
69
}
58
70
#endif
59
71
72
+ #ifdef LIBC_VDSO_HAS_CLOCK_GETTIME64
73
+ TEST (LlvmLibcOSUtilVDSOTest, ClockGetTime64) {
74
+ using FuncTy = int (*)(clockid_t , __kernel_timespec *);
75
+ auto func =
76
+ reinterpret_cast <FuncTy>(vdso::get_symbol (vdso::VDSOSym::ClockGetTime64));
77
+ if (func == nullptr )
78
+ return ;
79
+ // See kernel API at
80
+ // https://elixir.bootlin.com/linux/latest/source/tools/testing/selftests/vDSO/vdso_test_correctness.c#L155
81
+ __kernel_timespec a, b;
82
+ EXPECT_EQ (func (CLOCK_MONOTONIC, &a), 0 );
83
+ EXPECT_EQ (func (CLOCK_MONOTONIC, &b), 0 );
84
+ if (a.tv_sec == b.tv_sec ) {
85
+ EXPECT_LT (a.tv_nsec , b.tv_nsec );
86
+ } else {
87
+ EXPECT_LT (a.tv_sec , b.tv_sec );
88
+ }
89
+ }
90
+ #endif
91
+
60
92
#ifdef LIBC_VDSO_HAS_CLOCK_GETRES
61
93
TEST (LlvmLibcOSUtilVDSOTest, ClockGetRes) {
62
94
using FuncTy = int (*)(clockid_t , timespec *);
63
95
auto func =
64
96
reinterpret_cast <FuncTy>(vdso::get_symbol (vdso::VDSOSym::ClockGetRes));
97
+ if (func == nullptr )
98
+ return ;
65
99
timespec res{};
66
100
EXPECT_EQ (func (CLOCK_MONOTONIC, &res), 0 );
67
101
EXPECT_TRUE (res.tv_sec > 0 || res.tv_nsec > 0 );
68
102
}
69
103
#endif
70
104
105
+ #ifdef LIBC_VDSO_HAS_GETCPU
106
+ TEST (LlvmLibcOSUtilVDSOTest, GetCpu) {
107
+ // The kernel system call has a third argument, which should be passed as
108
+ // nullptr.
109
+ using FuncTy = int (*)(int *, int *, void *);
110
+ auto func = reinterpret_cast <FuncTy>(vdso::get_symbol (vdso::VDSOSym::GetCpu));
111
+ if (func == nullptr )
112
+ return ;
113
+ int cpu = -1 , node = -1 ;
114
+ EXPECT_EQ (func (&cpu, &node, nullptr ), 0 );
115
+ EXPECT_GE (cpu, 0 );
116
+ EXPECT_GE (node, 0 );
117
+ }
118
+ #endif
119
+
120
+ // TODO: apply this change to __restore_rt in
121
+ // libc/src/signal/linux/sigaction.cpp
122
+ // Caution: user application typically should not play with the trampoline.
123
+ // Let the libc handle it.
124
+ [[gnu::noreturn]] static void __restore_rt () {
125
+ #ifdef LIBC_VDSO_HAS_RT_SIGRETURN
126
+ using FuncTy = void (*)();
127
+ auto func =
128
+ reinterpret_cast <FuncTy>(vdso::get_symbol (vdso::VDSOSym::RTSigReturn));
129
+ if (func) {
130
+ func ();
131
+ __builtin_trap ();
132
+ }
133
+ #endif
134
+ LIBC_NAMESPACE::syscall_impl<long >(SYS_rt_sigreturn);
135
+ __builtin_trap ();
136
+ }
137
+
138
+ static bool flag = false ;
139
+
140
+ static void sigprof_handler [[gnu::used]] (int ) { flag = true ; }
141
+
142
+ TEST (LlvmLibcOSUtilVDSOTest, RtSigReturn) {
143
+ using namespace testing ::ErrnoSetterMatcher;
144
+ // must use struct since there is a function of the same name in the same
145
+ // scope.
146
+ struct sigaction sa{};
147
+ struct sigaction old_sa{};
148
+ sa.sa_handler = sigprof_handler;
149
+ sa.sa_flags = SA_RESTORER;
150
+ sa.sa_restorer = __restore_rt;
151
+ ASSERT_THAT (LIBC_NAMESPACE::sigaction (SIGPROF, &sa, &old_sa), Succeeds ());
152
+ raise (SIGPROF);
153
+ ASSERT_TRUE (flag);
154
+ flag = false ;
155
+ ASSERT_THAT (LIBC_NAMESPACE::sigaction (SIGPROF, &old_sa, nullptr ), Succeeds ());
156
+ }
157
+
158
+ #ifdef LIBC_VDSO_HAS_FLUSH_ICACHE
159
+ TEST (LlvmLibcOSUtilVDSOTest, FlushICache) {
160
+ using FuncTy = void (*)(void *, void *, unsigned long );
161
+ auto func =
162
+ reinterpret_cast <FuncTy>(vdso::get_symbol (vdso::VDSOSym::FlushICache));
163
+ if (func == nullptr )
164
+ return ;
165
+ char buf[512 ];
166
+ // we just check that the flush will not panic the program.
167
+ // the flags part only take 0/1 as up to kernel 6.10, which is used to
168
+ // indicate whether the flush is local to the core or global.
169
+ func (buf, buf + sizeof (buf), 0 );
170
+ func (buf, buf + sizeof (buf), 1 );
171
+ }
172
+ #endif
173
+
174
+ // https://docs.kernel.org/6.5/riscv/hwprobe.html
175
+
176
+ #ifdef LIBC_VDSO_HAS_RISCV_HWPROBE
177
+ TEST (LlvmLibcOSUtilVDSOTest, RiscvHwProbe) {
178
+ using namespace testing ::ErrnoSetterMatcher;
179
+ struct riscv_hwprobe {
180
+ int64_t key;
181
+ uint64_t value;
182
+ };
183
+ using FuncTy =
184
+ long (*)(riscv_hwprobe *, size_t , size_t , struct cpu_set_t *, unsigned );
185
+ auto func =
186
+ reinterpret_cast <FuncTy>(vdso::get_symbol (vdso::VDSOSym::RiscvHwProbe));
187
+ if (func == nullptr )
188
+ return ;
189
+ // If a key is unknown to the kernel, its key field will be cleared to -1, and
190
+ // its value set to 0. We expect probes.value are all 0.
191
+ // Usermode can supply NULL for cpus and 0 for cpu_count as a shortcut for all
192
+ // online CPUs
193
+ riscv_hwprobe probes[2 ] = {{-1 , 1 }, {-1 , 1 }};
194
+ ASSERT_THAT (func (/* pairs=*/ probes, /* count=*/ 2 , /* cpusetsize=*/ 0 ,
195
+ /* cpuset=*/ nullptr ,
196
+ /* flags=*/ 0 ),
197
+ Succeeds ());
198
+ for (auto &probe : probes) {
199
+ EXPECT_EQ (probe.key , static_cast <decltype (probe.key )>(-1 ));
200
+ EXPECT_EQ (probe.value , static_cast <decltype (probe.value )>(0 ));
201
+ }
202
+ }
203
+ #endif
204
+
71
205
} // namespace LIBC_NAMESPACE
0 commit comments