about summary refs log tree commit diff
path: root/src/time
diff options
context:
space:
mode:
Diffstat (limited to 'src/time')
-rw-r--r--src/time/clock_gettime.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/src/time/clock_gettime.c b/src/time/clock_gettime.c
index 46083759..63e9f9c8 100644
--- a/src/time/clock_gettime.c
+++ b/src/time/clock_gettime.c
@@ -8,9 +8,41 @@
 
 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;
+		}
+	}
+#endif
 	int (*f)(clockid_t, struct timespec *) =
 		(int (*)(clockid_t, struct timespec *))p;
 	a_cas_p(&vdso_func, (void *)cgt_init, p);