clock_settime: add time64 syscall support, decouple 32-bit time_t
authorRich Felker <dalias@aerifal.cx>
Sun, 28 Jul 2019 22:43:51 +0000 (18:43 -0400)
committerRich Felker <dalias@aerifal.cx>
Mon, 29 Jul 2019 04:17:02 +0000 (00:17 -0400)
time64 syscall is used only if it's the only one defined for the arch,
or if the requested time does not fit in 32 bits. on current 32-bit
archs where time_t is a 32-bit type, this makes it statically
unreachable.

if the time64 syscall is needed because the requested time does not
fit in 32 bits, we define this as an error ENOTSUP, for "The
implementation does not support the requested feature or value".

on 64-bit archs, there is no change to the code after preprocessing.
on current 32-bit archs, the time is moved through an intermediate
copy to remove the assumption that time_t is a 32-bit type.

src/time/clock_settime.c

index 66b8162d72b540de5cefdbb62e8af6d3963d166c..5fdaeb9e424eba594d304a387529cb61c06a22c6 100644 (file)
@@ -1,7 +1,24 @@
 #include <time.h>
+#include <errno.h>
 #include "syscall.h"
 
+#define IS32BIT(x) !((x)+0x80000000ULL>>32)
+
 int clock_settime(clockid_t clk, const struct timespec *ts)
 {
+#ifdef SYS_clock_settime64
+       time_t s = ts->tv_sec;
+       long ns = ts->tv_nsec;
+       int r = -ENOSYS;
+       if (SYS_clock_settime == SYS_clock_settime64 || !IS32BIT(s))
+               r = __syscall(SYS_clock_settime64, clk,
+                       ((long long[]){s, ns}));
+       if (SYS_clock_settime == SYS_clock_settime64 || r!=-ENOSYS)
+               return __syscall_ret(r);
+       if (!IS32BIT(s))
+               return __syscall_ret(-ENOTSUP);
+       return syscall(SYS_clock_settime, clk, ts ? ((long[]){s, ns}) : 0);
+#else
        return syscall(SYS_clock_settime, clk, ts);
+#endif
 }