timer_gettime: add time64 syscall support, decouple 32-bit time_t
authorRich Felker <dalias@aerifal.cx>
Mon, 29 Jul 2019 02:46:19 +0000 (22:46 -0400)
committerRich Felker <dalias@aerifal.cx>
Mon, 29 Jul 2019 04:19:21 +0000 (00:19 -0400)
the time64 syscall has to be used if time_t is 64-bit, since there's
no way of knowing before making a syscall whether the result will fit
in 32 bits, and the 32-bit syscalls do not report overflow as an
error.

on 64-bit archs, there is no change to the code after preprocessing.
on current 32-bit archs, the result is now read from the kernel
through long[4] array, then copied into the timespec, to remove the
assumption that time_t is the same as long.

src/time/timer_gettime.c

index ed6d8d65ce1ac0b488002e5a9503b1fbd84ddea3..21c9d32c3fe52e7502f10af91380ce4faead2c55 100644 (file)
@@ -8,5 +8,21 @@ int timer_gettime(timer_t t, struct itimerspec *val)
                pthread_t td = (void *)((uintptr_t)t << 1);
                t = (void *)(uintptr_t)(td->timer_id & INT_MAX);
        }
+#ifdef SYS_timer_gettime64
+       int r = -ENOSYS;
+       if (sizeof(time_t) > 4)
+               r = __syscall(SYS_timer_gettime64, t, val);
+       if (SYS_timer_gettime == SYS_timer_gettime64 || r!=-ENOSYS)
+               return __syscall_ret(r);
+       long val32[4];
+       r = __syscall(SYS_timer_gettime, t, val32);
+       if (!r) {
+               val->it_interval.tv_sec = val32[0];
+               val->it_interval.tv_nsec = val32[1];
+               val->it_value.tv_sec = val32[2];
+               val->it_value.tv_nsec = val32[3];
+       }
+       return __syscall_ret(r);
+#endif
        return syscall(SYS_timer_gettime, t, val);
 }