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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
#include <time.h>
#include <errno.h>
#include <stdint.h>
#include "syscall.h"
#include "atomic.h"
#ifdef VDSO_CGT_SYM
static void *volatile vdso_func;
#ifdef VDSO_CGT32_SYM
static void *volatile vdso_func_32;
static int cgt_time32_wrap(clockid_t clk, struct timespec *ts)
{
long ts32[2];
int (*f)(clockid_t, long[2]) =
(int (*)(clockid_t, long[2]))vdso_func_32;
int r = f(clk, ts32);
if (!r) {
/* Fallback to syscalls if time32 overflowed. Maybe
* we lucked out and somehow migrated to a kernel with
* time64 syscalls available. */
if (ts32[0] < 0) {
a_cas_p(&vdso_func, (void *)cgt_time32_wrap, 0);
return -ENOSYS;
}
ts->tv_sec = ts32[0];
ts->tv_nsec = ts32[1];
}
return r;
}
#endif
static int cgt_init(clockid_t clk, struct timespec *ts)
{
void *p = __vdsosym(VDSO_CGT_VER, VDSO_CGT_SYM);
#ifdef VDSO_CGT32_SYM
if (!p) {
void *q = __vdsosym(VDSO_CGT32_VER, VDSO_CGT32_SYM);
if (q) {
a_cas_p(&vdso_func_32, 0, q);
p = cgt_time32_wrap;
}
}
#ifdef VDSO_CGT_WORKAROUND
if (!__vdsosym(VDSO_CGT32_VER, VDSO_CGT32_SYM)) p = 0;
#endif
#endif
int (*f)(clockid_t, struct timespec *) =
(int (*)(clockid_t, struct timespec *))p;
a_cas_p(&vdso_func, (void *)cgt_init, p);
return f ? f(clk, ts) : -ENOSYS;
}
static void *volatile vdso_func = (void *)cgt_init;
#endif
#if __EMSCRIPTEN__
_Static_assert(CLOCK_REALTIME == __WASI_CLOCKID_REALTIME, "monotonic clock must match");
_Static_assert(CLOCK_MONOTONIC == __WASI_CLOCKID_MONOTONIC, "monotonic clock must match");
int __clock_gettime(clockid_t clk, struct timespec *ts) {
__wasi_timestamp_t timestamp;
// See https://github.com/bytecodealliance/wasmtime/issues/3714
if (clk > __WASI_CLOCKID_THREAD_CPUTIME_ID || clk < 0) {
errno = EINVAL;
return -1;
}
if (__wasi_syscall_ret(__wasi_clock_time_get(clk, 1, ×tamp))) {
return -1;
}
*ts = __wasi_timestamp_to_timespec(timestamp);
return 0;
}
#else // __EMSCRIPTEN__
int __clock_gettime(clockid_t clk, struct timespec *ts)
{
int r;
#ifdef VDSO_CGT_SYM
int (*f)(clockid_t, struct timespec *) =
(int (*)(clockid_t, struct timespec *))vdso_func;
if (f) {
r = f(clk, ts);
if (!r) return r;
if (r == -EINVAL) return __syscall_ret(r);
/* Fall through on errors other than EINVAL. Some buggy
* vdso implementations return ENOSYS for clocks they
* can't handle, rather than making the syscall. This
* also handles the case where cgt_init fails to find
* a vdso function to use. */
}
#endif
#ifdef SYS_clock_gettime64
r = -ENOSYS;
if (sizeof(time_t) > 4)
r = __syscall(SYS_clock_gettime64, clk, ts);
if (SYS_clock_gettime == SYS_clock_gettime64 || r!=-ENOSYS)
return __syscall_ret(r);
long ts32[2];
r = __syscall(SYS_clock_gettime, clk, ts32);
#ifdef SYS_gettimeofday
if (r==-ENOSYS && clk==CLOCK_REALTIME) {
r = __syscall(SYS_gettimeofday, ts32, 0);
ts32[1] *= 1000;
}
#endif
if (!r) {
ts->tv_sec = ts32[0];
ts->tv_nsec = ts32[1];
return r;
}
return __syscall_ret(r);
#else
r = __syscall(SYS_clock_gettime, clk, ts);
#ifdef SYS_gettimeofday
if (r == -ENOSYS) {
if (clk == CLOCK_REALTIME) {
__syscall(SYS_gettimeofday, ts, 0);
ts->tv_nsec = (int)ts->tv_nsec * 1000;
return 0;
}
r = -EINVAL;
}
#endif
return __syscall_ret(r);
#endif
}
#endif //__EMSCRIPTEN__
weak_alias(__clock_gettime, clock_gettime);
|