| Index: fusl/src/time/clock_gettime.c
|
| diff --git a/fusl/src/time/clock_gettime.c b/fusl/src/time/clock_gettime.c
|
| index 1572de0ef0029eb94b53a9928cd0a9fc57684d6a..241288042d64c36ce13f4506a5d0f5a8695a7ac1 100644
|
| --- a/fusl/src/time/clock_gettime.c
|
| +++ b/fusl/src/time/clock_gettime.c
|
| @@ -5,37 +5,54 @@
|
| #include "libc.h"
|
| #include "atomic.h"
|
|
|
| -static int sc_clock_gettime(clockid_t clk, struct timespec *ts)
|
| +#ifdef VDSO_CGT_SYM
|
| +
|
| +void *__vdsosym(const char *, const char *);
|
| +
|
| +static void *volatile vdso_func;
|
| +
|
| +static int cgt_init(clockid_t clk, struct timespec *ts)
|
| {
|
| - int r = __syscall(SYS_clock_gettime, clk, ts);
|
| - if (!r) return r;
|
| - if (r == -ENOSYS) {
|
| - if (clk == CLOCK_REALTIME) {
|
| - __syscall(SYS_gettimeofday, ts, 0);
|
| - ts->tv_nsec = (int)ts->tv_nsec * 1000;
|
| - return 0;
|
| - }
|
| - r = -EINVAL;
|
| - }
|
| - errno = -r;
|
| - return -1;
|
| + void *p = __vdsosym(VDSO_CGT_VER, VDSO_CGT_SYM);
|
| + 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;
|
| }
|
|
|
| -void *__vdsosym(const char *, const char *);
|
| +static void *volatile vdso_func = (void *)cgt_init;
|
| +
|
| +#endif
|
|
|
| int __clock_gettime(clockid_t clk, struct timespec *ts)
|
| {
|
| + int r;
|
| +
|
| #ifdef VDSO_CGT_SYM
|
| - static int (*volatile cgt)(clockid_t, struct timespec *);
|
| - if (!cgt) {
|
| - void *f = __vdsosym(VDSO_CGT_VER, VDSO_CGT_SYM);
|
| - if (!f) f = (void *)sc_clock_gettime;
|
| - a_cas_p(&cgt, 0, f);
|
| + 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. */
|
| }
|
| - return cgt(clk, ts);
|
| -#else
|
| - return sc_clock_gettime(clk, ts);
|
| #endif
|
| +
|
| + r = __syscall(SYS_clock_gettime, clk, ts);
|
| + if (r == -ENOSYS) {
|
| + if (clk == CLOCK_REALTIME) {
|
| + __syscall(SYS_gettimeofday, ts, 0);
|
| + ts->tv_nsec = (int)ts->tv_nsec * 1000;
|
| + return 0;
|
| + }
|
| + r = -EINVAL;
|
| + }
|
| + return __syscall_ret(r);
|
| }
|
|
|
| weak_alias(__clock_gettime, clock_gettime);
|
|
|