setitimer, getitimer: decouple time_t from long
authorRich Felker <dalias@aerifal.cx>
Tue, 30 Jul 2019 00:57:05 +0000 (20:57 -0400)
committerRich Felker <dalias@aerifal.cx>
Tue, 30 Jul 2019 00:57:05 +0000 (20:57 -0400)
these functions have no new time64 syscall, so the existence of a
time64 syscall cannot be used as the condition for the new code.
instead, assume the syscall takes timevals as longs, which is true
everywhere but x32, and interface with the kernel through long[4]
objects.

rather than adding new hacks to special-case x32 here, just add
x32-specific source files since a trivial syscall wrapper suffices
there.

the new code paths added in this commit are statically unreachable on
all current archs, but will become reachable when 32-bit archs get
64-bit time_t.

src/signal/getitimer.c
src/signal/setitimer.c
src/signal/x32/getitimer.c [new file with mode: 0644]
src/signal/x32/setitimer.c [new file with mode: 0644]

index 8a8046a76b5c6511b8b8a81614622a39dd6ced97..36d1eb9dc6e991af1ed4b5d0c85b851eb243d697 100644 (file)
@@ -3,5 +3,16 @@
 
 int getitimer(int which, struct itimerval *old)
 {
+       if (sizeof(time_t) > sizeof(long)) {
+               long old32[4];
+               int r = __syscall(SYS_getitimer, which, old32);
+               if (!r) {
+                       old->it_interval.tv_sec = old32[0];
+                       old->it_interval.tv_usec = old32[1];
+                       old->it_value.tv_sec = old32[2];
+                       old->it_value.tv_usec = old32[3];
+               }
+               return __syscall_ret(r);
+       }
        return syscall(SYS_getitimer, which, old);
 }
index 21b1f45da9b7a87a67568e20991d1f4b73188f0a..0dfbeb4db5a7ad65faeac76e6039a11807645f2b 100644 (file)
@@ -1,7 +1,26 @@
 #include <sys/time.h>
+#include <errno.h>
 #include "syscall.h"
 
+#define IS32BIT(x) !((x)+0x80000000ULL>>32)
+
 int setitimer(int which, const struct itimerval *restrict new, struct itimerval *restrict old)
 {
+       if (sizeof(time_t) > sizeof(long)) {
+               time_t is = new->it_interval.tv_sec, vs = new->it_value.tv_sec;
+               long ius = new->it_interval.tv_usec, vus = new->it_value.tv_usec;
+               if (!IS32BIT(is) || !IS32BIT(vs))
+                       return __syscall_ret(-ENOTSUP);
+               long old32[4];
+               int r = __syscall(SYS_setitimer, which,
+                       ((long[]){is, ius, vs, vus}), old32);
+               if (!r && old) {
+                       old->it_interval.tv_sec = old32[0];
+                       old->it_interval.tv_usec = old32[1];
+                       old->it_value.tv_sec = old32[2];
+                       old->it_value.tv_usec = old32[3];
+               }
+               return __syscall_ret(r);
+       }
        return syscall(SYS_setitimer, which, new, old);
 }
diff --git a/src/signal/x32/getitimer.c b/src/signal/x32/getitimer.c
new file mode 100644 (file)
index 0000000..8a8046a
--- /dev/null
@@ -0,0 +1,7 @@
+#include <sys/time.h>
+#include "syscall.h"
+
+int getitimer(int which, struct itimerval *old)
+{
+       return syscall(SYS_getitimer, which, old);
+}
diff --git a/src/signal/x32/setitimer.c b/src/signal/x32/setitimer.c
new file mode 100644 (file)
index 0000000..21b1f45
--- /dev/null
@@ -0,0 +1,7 @@
+#include <sys/time.h>
+#include "syscall.h"
+
+int setitimer(int which, const struct itimerval *restrict new, struct itimerval *restrict old)
+{
+       return syscall(SYS_setitimer, which, new, old);
+}