1717#include <errno.h>
1818#include <sched.h>
1919#include <stdbool.h>
20+ #include <limits.h>
2021
2122#ifndef SYS_getcpu
2223# ifdef __x86_64__
3132
3233int nerrs = 0 ;
3334
35+ typedef int (* vgettime_t )(clockid_t , struct timespec * );
36+
37+ vgettime_t vdso_clock_gettime ;
38+
3439typedef long (* getcpu_t )(unsigned * , unsigned * , void * );
3540
3641getcpu_t vgetcpu ;
@@ -95,6 +100,10 @@ static void fill_function_pointers()
95100 printf ("Warning: failed to find getcpu in vDSO\n" );
96101
97102 vgetcpu = (getcpu_t ) vsyscall_getcpu ();
103+
104+ vdso_clock_gettime = (vgettime_t )dlsym (vdso , "__vdso_clock_gettime" );
105+ if (!vdso_clock_gettime )
106+ printf ("Warning: failed to find clock_gettime in vDSO\n" );
98107}
99108
100109static long sys_getcpu (unsigned * cpu , unsigned * node ,
@@ -103,6 +112,11 @@ static long sys_getcpu(unsigned * cpu, unsigned * node,
103112 return syscall (__NR_getcpu , cpu , node , cache );
104113}
105114
115+ static inline int sys_clock_gettime (clockid_t id , struct timespec * ts )
116+ {
117+ return syscall (__NR_clock_gettime , id , ts );
118+ }
119+
106120static void test_getcpu (void )
107121{
108122 printf ("[RUN]\tTesting getcpu...\n" );
@@ -155,10 +169,95 @@ static void test_getcpu(void)
155169 }
156170}
157171
172+ static bool ts_leq (const struct timespec * a , const struct timespec * b )
173+ {
174+ if (a -> tv_sec != b -> tv_sec )
175+ return a -> tv_sec < b -> tv_sec ;
176+ else
177+ return a -> tv_nsec <= b -> tv_nsec ;
178+ }
179+
180+ static char const * const clocknames [] = {
181+ [0 ] = "CLOCK_REALTIME" ,
182+ [1 ] = "CLOCK_MONOTONIC" ,
183+ [2 ] = "CLOCK_PROCESS_CPUTIME_ID" ,
184+ [3 ] = "CLOCK_THREAD_CPUTIME_ID" ,
185+ [4 ] = "CLOCK_MONOTONIC_RAW" ,
186+ [5 ] = "CLOCK_REALTIME_COARSE" ,
187+ [6 ] = "CLOCK_MONOTONIC_COARSE" ,
188+ [7 ] = "CLOCK_BOOTTIME" ,
189+ [8 ] = "CLOCK_REALTIME_ALARM" ,
190+ [9 ] = "CLOCK_BOOTTIME_ALARM" ,
191+ [10 ] = "CLOCK_SGI_CYCLE" ,
192+ [11 ] = "CLOCK_TAI" ,
193+ };
194+
195+ static void test_one_clock_gettime (int clock , const char * name )
196+ {
197+ struct timespec start , vdso , end ;
198+ int vdso_ret , end_ret ;
199+
200+ printf ("[RUN]\tTesting clock_gettime for clock %s (%d)...\n" , name , clock );
201+
202+ if (sys_clock_gettime (clock , & start ) < 0 ) {
203+ if (errno == EINVAL ) {
204+ vdso_ret = vdso_clock_gettime (clock , & vdso );
205+ if (vdso_ret == - EINVAL ) {
206+ printf ("[OK]\tNo such clock.\n" );
207+ } else {
208+ printf ("[FAIL]\tNo such clock, but __vdso_clock_gettime returned %d\n" , vdso_ret );
209+ nerrs ++ ;
210+ }
211+ } else {
212+ printf ("[WARN]\t clock_gettime(%d) syscall returned error %d\n" , clock , errno );
213+ }
214+ return ;
215+ }
216+
217+ vdso_ret = vdso_clock_gettime (clock , & vdso );
218+ end_ret = sys_clock_gettime (clock , & end );
219+
220+ if (vdso_ret != 0 || end_ret != 0 ) {
221+ printf ("[FAIL]\tvDSO returned %d, syscall errno=%d\n" ,
222+ vdso_ret , errno );
223+ nerrs ++ ;
224+ return ;
225+ }
226+
227+ printf ("\t%llu.%09ld %llu.%09ld %llu.%09ld\n" ,
228+ (unsigned long long )start .tv_sec , start .tv_nsec ,
229+ (unsigned long long )vdso .tv_sec , vdso .tv_nsec ,
230+ (unsigned long long )end .tv_sec , end .tv_nsec );
231+
232+ if (!ts_leq (& start , & vdso ) || !ts_leq (& vdso , & end )) {
233+ printf ("[FAIL]\tTimes are out of sequence\n" );
234+ nerrs ++ ;
235+ }
236+ }
237+
238+ static void test_clock_gettime (void )
239+ {
240+ for (int clock = 0 ; clock < sizeof (clocknames ) / sizeof (clocknames [0 ]);
241+ clock ++ ) {
242+ test_one_clock_gettime (clock , clocknames [clock ]);
243+ }
244+
245+ /* Also test some invalid clock ids */
246+ test_one_clock_gettime (-1 , "invalid" );
247+ test_one_clock_gettime (INT_MIN , "invalid" );
248+ test_one_clock_gettime (INT_MAX , "invalid" );
249+ }
250+
158251int main (int argc , char * * argv )
159252{
160253 fill_function_pointers ();
161254
255+ test_clock_gettime ();
256+
257+ /*
258+ * Test getcpu() last so that, if something goes wrong setting affinity,
259+ * we still run the other tests.
260+ */
162261 test_getcpu ();
163262
164263 return nerrs ? 1 : 0 ;
0 commit comments