github.com/afumu/libc@v0.0.6/musl/src/time/clock_gettime.c (about) 1 #include <time.h> 2 #include <errno.h> 3 #include <stdint.h> 4 #include "syscall.h" 5 #include "atomic.h" 6 7 #ifdef VDSO_CGT_SYM 8 9 static void *volatile vdso_func; 10 11 #ifdef VDSO_CGT32_SYM 12 static void *volatile vdso_func_32; 13 static int cgt_time32_wrap(clockid_t clk, struct timespec *ts) 14 { 15 long ts32[2]; 16 int (*f)(clockid_t, long[2]) = 17 (int (*)(clockid_t, long[2]))vdso_func_32; 18 int r = f(clk, ts32); 19 if (!r) { 20 /* Fallback to syscalls if time32 overflowed. Maybe 21 * we lucked out and somehow migrated to a kernel with 22 * time64 syscalls available. */ 23 if (ts32[0] < 0) { 24 a_cas_p(&vdso_func, (void *)cgt_time32_wrap, 0); 25 return -ENOSYS; 26 } 27 ts->tv_sec = ts32[0]; 28 ts->tv_nsec = ts32[1]; 29 } 30 return r; 31 } 32 #endif 33 34 static int cgt_init(clockid_t clk, struct timespec *ts) 35 { 36 void *p = __vdsosym(VDSO_CGT_VER, VDSO_CGT_SYM); 37 #ifdef VDSO_CGT32_SYM 38 if (!p) { 39 void *q = __vdsosym(VDSO_CGT32_VER, VDSO_CGT32_SYM); 40 if (q) { 41 a_cas_p(&vdso_func_32, 0, q); 42 p = cgt_time32_wrap; 43 } 44 } 45 #endif 46 int (*f)(clockid_t, struct timespec *) = 47 (int (*)(clockid_t, struct timespec *))p; 48 a_cas_p(&vdso_func, (void *)cgt_init, p); 49 return f ? f(clk, ts) : -ENOSYS; 50 } 51 52 static void *volatile vdso_func = (void *)cgt_init; 53 54 #endif 55 56 int __clock_gettime(clockid_t clk, struct timespec *ts) 57 { 58 int r; 59 60 #ifdef VDSO_CGT_SYM 61 int (*f)(clockid_t, struct timespec *) = 62 (int (*)(clockid_t, struct timespec *))vdso_func; 63 if (f) { 64 r = f(clk, ts); 65 if (!r) return r; 66 if (r == -EINVAL) return __syscall_ret(r); 67 /* Fall through on errors other than EINVAL. Some buggy 68 * vdso implementations return ENOSYS for clocks they 69 * can't handle, rather than making the syscall. This 70 * also handles the case where cgt_init fails to find 71 * a vdso function to use. */ 72 } 73 #endif 74 75 #ifdef SYS_clock_gettime64 76 r = -ENOSYS; 77 if (sizeof(time_t) > 4) 78 r = __syscall(SYS_clock_gettime64, clk, ts); 79 if (SYS_clock_gettime == SYS_clock_gettime64 || r!=-ENOSYS) 80 return __syscall_ret(r); 81 long ts32[2]; 82 r = __syscall(SYS_clock_gettime, clk, ts32); 83 if (r==-ENOSYS && clk==CLOCK_REALTIME) { 84 r = __syscall(SYS_gettimeofday, ts32, 0); 85 ts32[1] *= 1000; 86 } 87 if (!r) { 88 ts->tv_sec = ts32[0]; 89 ts->tv_nsec = ts32[1]; 90 return r; 91 } 92 return __syscall_ret(r); 93 #else 94 r = __syscall(SYS_clock_gettime, clk, ts); 95 if (r == -ENOSYS) { 96 if (clk == CLOCK_REALTIME) { 97 __syscall(SYS_gettimeofday, ts, 0); 98 ts->tv_nsec = (int)ts->tv_nsec * 1000; 99 return 0; 100 } 101 r = -EINVAL; 102 } 103 return __syscall_ret(r); 104 #endif 105 } 106 107 weak_alias(__clock_gettime, clock_gettime);