This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Y2038: add struct __timespec64


* include/bits/types/struct_timespec64.h:
  Include time/bits/types/struct_timespec64.h
* include/time.h (valid_timeval_to_timespec64): Add.
* include/time.h (valid_timespec_to_timespec64): Likewise.
* include/time.h (valid_timespec64_to_timespec): Likewise.
* include/time.h (valid_timespec64_to_timeval): Likewise.
* include/time.h (IS_VALID_NANOSECONDS): Likewise.
* include/time.h (timespec_to_timespec64): Likewise.
* include/time.h (timespec64_to_timespec): Likewise.
* include/time.h (timespec64_to_timeval): Likewise.
* io/fcntl.h: Include bits/types/struct_timespec64.h.
* io/sys/poll.h: Likewise.
* io/sys/stat.h: Likewise.
* misc/sys/select.h: Likewise.
* posix/sched.h: Likewise.
* posix/netdb.h: Likewise.
* rt/aio.h: Likewise.
* rt/mqueue.h: Likewise.
* signal/signal.h: Likewise.
* sysdeps/nptl/pthread.h: Likewise.
* sysdeps/pthread/semaphore.h: Likewise.
* sysdeps/unix/sysv/linux/hppa/pthread.h: Likewise.
* sysvipc/sys/sem.h: Likewise.
* time/Makefile: Add bits/types/struct_timespec64.h
* time/bits/types/struct_itimerspec.h:
  Include bits/types/struct_timespec64.h
* time/bits/types/struct_itimerspec64.h: Add.
* time/time.h: Include bits/types/struct_timespec64.h
---
To be Y2038-proof, struct __timespec64 needs its tv_sec field to
be a __time64_t rather than a __time_t. However, the question is
which type should the tv_nsec field be.

Keeping tv_nsec a long (32-bit) would be compatible with Posix
requirements but would result in the GLIBC struct timespec being
binary-incompatible with the Linux 64-bit struct timespec, which
contains a 64-bit, not 32-bit, signed tv_nsec field.

In order to maintain Posix compatibility yet simplify conversion
between Posix and Linux struct timespec values, the Y2038-proof
struct time stores its tv_nsec field as a 32-bit signed integer
plus a padding which can serve as a 64-bit sign extension. This
both meets Posix requirements and makes the GLIBC and Linux
struct timespec binary compatible.

Note that in the API (which is not modified here, and will be
later alongside all Y2038-sensitive APIs), this padding is made
'invisible' by defining it as an anonymous bitfield, whereas
the struct __timespec64 introduced here has a named field for
the padding, allowing implementations to read and write it.

Also, provide static inline functions and macros for checking
and converting between 32-bit itimevals and timespecs to 64-bit
timespecs.

This patch is part of the Y2038 patch series, which is available at
<https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/aaribaud/y2038>.
Warning: this branch may be rebased on current master and/or updated based on
feedback from the list at any time.

 include/bits/types/struct_timespec64.h |  1 +
 include/time.h                         | 82 ++++++++++++++++++++++++++
 io/fcntl.h                             |  1 +
 io/sys/poll.h                          |  1 +
 io/sys/stat.h                          |  1 +
 misc/sys/select.h                      |  1 +
 posix/sched.h                          |  1 +
 resolv/netdb.h                         |  1 +
 rt/aio.h                               |  1 +
 rt/mqueue.h                            |  1 +
 signal/signal.h                        |  1 +
 sysdeps/nptl/pthread.h                 |  1 +
 sysdeps/pthread/semaphore.h            |  1 +
 sysdeps/unix/sysv/linux/hppa/pthread.h |  1 +
 sysvipc/sys/sem.h                      |  1 +
 time/Makefile                          |  2 +-
 time/bits/types/struct_itimerspec.h    |  1 +
 time/bits/types/struct_timespec64.h    | 29 +++++++++
 time/time.h                            |  1 +
 19 files changed, 128 insertions(+), 1 deletion(-)
 create mode 100644 include/bits/types/struct_timespec64.h
 create mode 100644 time/bits/types/struct_timespec64.h

diff --git a/include/bits/types/struct_timespec64.h b/include/bits/types/struct_timespec64.h
new file mode 100644
index 0000000000..42869680b8
--- /dev/null
+++ b/include/bits/types/struct_timespec64.h
@@ -0,0 +1 @@
+#include <time/bits/types/struct_timespec64.h>
diff --git a/include/time.h b/include/time.h
index 0c5c00218a..162afa1012 100644
--- a/include/time.h
+++ b/include/time.h
@@ -145,5 +145,87 @@ fits_in_time_t (__time64_t t64)
   return t == t64;
 }
 
+/* convert a known valid struct timeval into a struct __timespec64 */
+static inline void
+valid_timeval_to_timespec64 (const struct timeval *tv32,
+			     struct __timespec64 *ts64)
+{
+  ts64->tv_sec = tv32->tv_sec;
+  ts64->tv_nsec = tv32->tv_usec * 1000;
+}
+
+/* convert a known valid struct timespec into a struct __timespec64 */
+static inline void
+valid_timespec_to_timespec64 (const struct timespec *ts32,
+			      struct __timespec64 *ts64)
+{
+  ts64->tv_sec = ts32->tv_sec;
+  ts64->tv_nsec = ts32->tv_nsec;
+  /* we only need to zero ts64->tv_pad if we pass it to the kernel */
+}
+
+/* convert a known valid struct __timespec64 into a struct timespec */
+static inline void
+valid_timespec64_to_timespec (const struct __timespec64 *ts64,
+			      struct timespec *ts32)
+{
+  ts32->tv_sec = (time_t) ts64->tv_sec;
+  ts32->tv_nsec = ts64->tv_nsec;
+}
+
+/* convert a known valid struct __timespec64 into a struct timeval */
+static inline void
+valid_timespec64_to_timeval (const struct __timespec64 *ts64,
+			     struct timeval *tv32)
+{
+  tv32->tv_sec = (time_t) ts64->tv_sec;
+  tv32->tv_usec = ts64->tv_nsec / 1000;
+}
+
+/* check if a value lies with the valid nanoseconds range */
+#define IS_VALID_NANOSECONDS(ns) (ns >= 0 && ns <= 999999999)
+
+/* check and convert a struct timespec into a struct __timespec64 */
+static inline bool timespec_to_timespec64 (const struct timespec *ts32,
+					   struct __timespec64 *ts64)
+{
+  /* check that ts32 holds a valid count of nanoseconds */
+  if (! IS_VALID_NANOSECONDS (ts32->tv_nsec))
+    return false;
+  /* all ts32 fields can fit in ts64, so copy them */
+  valid_timespec_to_timespec64 (ts32, ts64);
+  /* we only need to zero ts64->tv_pad if we pass it to the kernel */
+  return true;
+}
+
+/* check and convert a struct __timespec64 into a struct timespec */
+static inline bool timespec64_to_timespec (const struct __timespec64 *ts64,
+					   struct timespec *ts32)
+{
+  /* check that tv_nsec holds a valid count of nanoseconds */
+  if (! IS_VALID_NANOSECONDS (ts64->tv_nsec))
+    return false;
+  /* check that tv_sec can fit in a __time_t */
+  if (! fits_in_time_t (ts64->tv_sec))
+    return false;
+  /* all ts64 fields can fit in ts32, so copy them */
+  valid_timespec64_to_timespec (ts64, ts32);
+  return true;
+}
+
+/* check and convert a struct __timespec64 into a struct timeval */
+static inline bool timespec64_to_timeval (const struct __timespec64 *ts64,
+					  struct timeval *tv32)
+{
+  /* check that tv_nsec holds a valid count of nanoseconds */
+  if (! IS_VALID_NANOSECONDS (ts64->tv_nsec))
+    return false;
+  /* check that tv_sec can fit in a __time_t */
+  if (! fits_in_time_t (ts64->tv_sec))
+    return false;
+  /* all ts64 fields can fit in tv32, so copy them */
+  valid_timespec64_to_timeval (ts64, tv32);
+  return true;
+}
 #endif
 #endif
diff --git a/io/fcntl.h b/io/fcntl.h
index 6b0e9fa1fa..db0064294f 100644
--- a/io/fcntl.h
+++ b/io/fcntl.h
@@ -73,6 +73,7 @@ typedef __pid_t pid_t;
 /* For XPG all symbols from <sys/stat.h> should also be available.  */
 #ifdef __USE_XOPEN2K8
 # include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
 #endif
 #if defined __USE_XOPEN || defined __USE_XOPEN2K8
 # include <bits/stat.h>
diff --git a/io/sys/poll.h b/io/sys/poll.h
index 68f68ca412..a4c2547dd6 100644
--- a/io/sys/poll.h
+++ b/io/sys/poll.h
@@ -26,6 +26,7 @@
 #ifdef __USE_GNU
 # include <bits/types/__sigset_t.h>
 # include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
 #endif
 
 
diff --git a/io/sys/stat.h b/io/sys/stat.h
index 762c8538ba..a1092f5fb4 100644
--- a/io/sys/stat.h
+++ b/io/sys/stat.h
@@ -28,6 +28,7 @@
 
 #ifdef __USE_XOPEN2K8
 # include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
 #endif
 
 #if defined __USE_XOPEN || defined __USE_XOPEN2K
diff --git a/misc/sys/select.h b/misc/sys/select.h
index 6dd0c83227..1285dc4a8b 100644
--- a/misc/sys/select.h
+++ b/misc/sys/select.h
@@ -37,6 +37,7 @@
 #include <bits/types/struct_timeval.h>
 #ifdef __USE_XOPEN2K
 # include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
 #endif
 
 #ifndef __suseconds_t_defined
diff --git a/posix/sched.h b/posix/sched.h
index 619b3b3a81..732c12baab 100644
--- a/posix/sched.h
+++ b/posix/sched.h
@@ -30,6 +30,7 @@
 
 #include <bits/types/time_t.h>
 #include <bits/types/struct_timespec.h>
+#include <bits/types/struct_timespec64.h>
 #ifndef __USE_XOPEN2K
 # include <time.h>
 #endif
diff --git a/resolv/netdb.h b/resolv/netdb.h
index 003800e882..96f675de75 100644
--- a/resolv/netdb.h
+++ b/resolv/netdb.h
@@ -35,6 +35,7 @@
 #ifdef __USE_GNU
 # include <bits/types/sigevent_t.h>
 # include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
 #endif
 
 #include <bits/netdb.h>
diff --git a/rt/aio.h b/rt/aio.h
index c3a1f4bd90..ffda0de906 100644
--- a/rt/aio.h
+++ b/rt/aio.h
@@ -27,6 +27,7 @@
 #include <bits/types/sigevent_t.h>
 #include <bits/sigevent-consts.h>
 #include <bits/types/struct_timespec.h>
+#include <bits/types/struct_timespec64.h>
 
 __BEGIN_DECLS
 
diff --git a/rt/mqueue.h b/rt/mqueue.h
index 5f354b4d76..39e2a243ca 100644
--- a/rt/mqueue.h
+++ b/rt/mqueue.h
@@ -23,6 +23,7 @@
 #include <fcntl.h>
 #include <bits/types/sigevent_t.h>
 #include <bits/types/struct_timespec.h>
+#include <bits/types/struct_timespec64.h>
 /* Get the definition of mqd_t and struct mq_attr.  */
 #include <bits/mqueue.h>
 
diff --git a/signal/signal.h b/signal/signal.h
index 87dc82a998..caa291587b 100644
--- a/signal/signal.h
+++ b/signal/signal.h
@@ -51,6 +51,7 @@ typedef __uid_t uid_t;
 #ifdef __USE_POSIX199309
 /* We need `struct timespec' later on.  */
 # include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
 #endif
 
 #if defined __USE_POSIX199309 || defined __USE_XOPEN_EXTENDED
diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
index df049abf74..41b915ec07 100644
--- a/sysdeps/nptl/pthread.h
+++ b/sysdeps/nptl/pthread.h
@@ -27,6 +27,7 @@
 #include <bits/setjmp.h>
 #include <bits/wordsize.h>
 #include <bits/types/struct_timespec.h>
+#include <bits/types/struct_timespec64.h>
 
 
 /* Detach state.  */
diff --git a/sysdeps/pthread/semaphore.h b/sysdeps/pthread/semaphore.h
index ff672ebd24..312433f544 100644
--- a/sysdeps/pthread/semaphore.h
+++ b/sysdeps/pthread/semaphore.h
@@ -22,6 +22,7 @@
 #include <sys/types.h>
 #ifdef __USE_XOPEN2K
 # include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
 #endif
 
 /* Get the definition for sem_t.  */
diff --git a/sysdeps/unix/sysv/linux/hppa/pthread.h b/sysdeps/unix/sysv/linux/hppa/pthread.h
index 11a024db59..e4640b3717 100644
--- a/sysdeps/unix/sysv/linux/hppa/pthread.h
+++ b/sysdeps/unix/sysv/linux/hppa/pthread.h
@@ -27,6 +27,7 @@
 #include <bits/setjmp.h>
 #include <bits/wordsize.h>
 #include <bits/types/struct_timespec.h>
+#include <bits/types/struct_timespec64.h>
 
 
 /* Detach state.  */
diff --git a/sysvipc/sys/sem.h b/sysvipc/sys/sem.h
index 200765bcba..b6a7eb2ada 100644
--- a/sysvipc/sys/sem.h
+++ b/sysvipc/sys/sem.h
@@ -31,6 +31,7 @@
 
 #ifdef __USE_GNU
 # include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
 #endif
 
 /* The following System V style IPC functions implement a semaphore
diff --git a/time/Makefile b/time/Makefile
index ec3e39dcea..61b8904dfc 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -27,7 +27,7 @@ headers := time.h sys/time.h sys/timeb.h bits/time.h			\
 	   bits/types/struct_itimerspec.h				\
 	   bits/types/struct_timespec.h bits/types/struct_timeval.h	\
 	   bits/types/struct_tm.h bits/types/timer_t.h			\
-	   bits/types/time_t.h
+	   bits/types/time_t.h bits/types/struct_timespec64.h
 
 routines := offtime asctime clock ctime ctime_r difftime \
 	    gmtime localtime mktime time		 \
diff --git a/time/bits/types/struct_itimerspec.h b/time/bits/types/struct_itimerspec.h
index 17cc1ac86d..d36295a830 100644
--- a/time/bits/types/struct_itimerspec.h
+++ b/time/bits/types/struct_itimerspec.h
@@ -3,6 +3,7 @@
 
 #include <bits/types.h>
 #include <bits/types/struct_timespec.h>
+#include <bits/types/struct_timespec64.h>
 
 /* POSIX.1b structure for timer start values and intervals.  */
 struct itimerspec
diff --git a/time/bits/types/struct_timespec64.h b/time/bits/types/struct_timespec64.h
new file mode 100644
index 0000000000..2221bed8bc
--- /dev/null
+++ b/time/bits/types/struct_timespec64.h
@@ -0,0 +1,29 @@
+#ifndef __timespec64_defined
+#define __timespec64_defined 1
+
+#include <bits/types.h>
+#include <endian.h>
+
+/* Y2036proof structure for a time value.  This is like a `struct timeval' but
+   has nanoseconds instead of microseconds.  To keep tings Posix-ish, we keep
+   the nanoseconds field a signed long, but since Linux has a 64-bit signed int,
+   we pad it with a 32-bit int, which should always be 0.
+   Note that the public type has an anonymous bitfield as padding, so that
+   it cannot be written into (or read from). */ 
+#if BYTE_ORDER == BIG_ENDIAN
+struct __timespec64
+{
+  __time64_t tv_sec;		/* Seconds */
+  int tv_pad: 32;		/* Padding named for checking/setting */
+  __syscall_slong_t tv_nsec;	/* Nanoseconds */
+};
+#else
+struct __timespec64
+{
+  __time64_t tv_sec;		/* Seconds */
+  __syscall_slong_t tv_nsec;	/* Nanoseconds */
+  int tv_pad: 32;		/* Padding named for checking/setting */
+};
+#endif
+
+#endif
diff --git a/time/time.h b/time/time.h
index 4b55e34402..c9282e2673 100644
--- a/time/time.h
+++ b/time/time.h
@@ -40,6 +40,7 @@
 
 #if defined __USE_POSIX199309 || defined __USE_ISOC11
 # include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
 #endif
 
 #ifdef __USE_POSIX199309
-- 
2.17.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]