summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlbert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>2017-03-29 11:57:53 +0200
committerAlbert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>2018-06-20 12:16:27 +0200
commitba0f7a55f4e714b9b6dabe02b4c6d7e85ac466e7 (patch)
tree8756a4f2f10951927a7ae970d4588be85d583bb4
parent96d2ec74227e715ea30c62d6e725e36852635438 (diff)
downloadglibc-aaribaud/y2038-rfc-3-wip.tar.gz
Y2038: add function __difftime64aaribaud/y2038-rfc-3-wip
Note: 1. The implementation expects __time64_t arguments, and could, in theory, require 64 bits to express the difference accurately; but it returns a double, which only provides about 55 significant bits. We could make it return a long double, which would be more than enough for 64 bits accuracy. But then, existing source code which uses difftime, and therefore stores difftime results in doubles, would need to change to long doubles. However, we want 64-bit time support to work without any application source code change. Besides, 55 bits allow for counting seconds accurately over 417 billion years, which is arguably enough for most actual uses of difftime. 2. The 64-bit time implementation was obtained by duplicating the original 32-bit code then simplifying the source code based on the knowledge that __time64_t is a 64-bit signed integer for all architectures. This led to the following removals: - in the subtract64 function, removal of code which handled unsigned time handling (as __time64_t is signed); - in the difftime64 function, removal of code which handled time bitsize smaller than or equal to that of a double matissa (as __time64_t has more bits than a double mantissa can hold) 3. The 32-bit implementation is now a wrapper around the 64-bit one.
-rw-r--r--include/time.h2
-rw-r--r--time/difftime.c112
2 files changed, 56 insertions, 58 deletions
diff --git a/include/time.h b/include/time.h
index 5afb12305e..36c6848792 100644
--- a/include/time.h
+++ b/include/time.h
@@ -127,6 +127,8 @@ extern char * __strptime_internal (const char *rp, const char *fmt,
extern double __difftime (time_t time1, time_t time0);
+extern double __difftime64 (__time64_t time1, __time64_t time0);
+
/* Use in the clock_* functions. Size of the field representing the
actual clock ID. */
#define CLOCK_IDFIELD_SIZE 3
diff --git a/time/difftime.c b/time/difftime.c
index 7c5dd9898b..1642c6d6b2 100644
--- a/time/difftime.c
+++ b/time/difftime.c
@@ -30,87 +30,75 @@
/* Return the difference between TIME1 and TIME0, where TIME0 <= TIME1.
time_t is known to be an integer type. */
-static double
-subtract (time_t time1, time_t time0)
+static double subtract (__time64_t time1, __time64_t time0)
{
- if (! TYPE_SIGNED (time_t))
- return time1 - time0;
- else
- {
- /* Optimize the common special cases where time_t
- can be converted to uintmax_t without losing information. */
- uintmax_t dt = (uintmax_t) time1 - (uintmax_t) time0;
- double delta = dt;
-
- if (UINTMAX_MAX / 2 < INTMAX_MAX)
- {
- /* This is a rare host where uintmax_t has padding bits, and possibly
- information was lost when converting time_t to uintmax_t.
- Check for overflow by comparing dt/2 to (time1/2 - time0/2).
- Overflow occurred if they differ by more than a small slop.
- Thanks to Clive D.W. Feather for detailed technical advice about
- hosts with padding bits.
+ /* Optimize the common special cases where __time64_t
+ can be converted to uintmax_t without losing information. */
+ uintmax_t dt = (uintmax_t) time1 - (uintmax_t) time0;
+ double delta = dt;
+
+ if (UINTMAX_MAX / 2 < INTMAX_MAX)
+{
+ /* This is a rare host where uintmax_t has padding bits, and possibly
+ information was lost when converting time_t to uintmax_t.
+ Check for overflow by comparing dt/2 to (time1/2 - time0/2).
+ Overflow occurred if they differ by more than a small slop.
+ Thanks to Clive D.W. Feather for detailed technical advice about
+ hosts with padding bits.
- In the following code the "h" prefix means half. By range
- analysis, we have:
+ In the following code the "h" prefix means half. By range
+ analysis, we have:
- -0.5 <= ht1 - 0.5*time1 <= 0.5
- -0.5 <= ht0 - 0.5*time0 <= 0.5
- -1.0 <= dht - 0.5*(time1 - time0) <= 1.0
+ -0.5 <= ht1 - 0.5*time1 <= 0.5
+ -0.5 <= ht0 - 0.5*time0 <= 0.5
+ -1.0 <= dht - 0.5*(time1 - time0) <= 1.0
- If overflow has not occurred, we also have:
+ If overflow has not occurred, we also have:
- -0.5 <= hdt - 0.5*(time1 - time0) <= 0
- -1.0 <= dht - hdt <= 1.5
+ -0.5 <= hdt - 0.5*(time1 - time0) <= 0
+ -1.0 <= dht - hdt <= 1.5
- and since dht - hdt is an integer, we also have:
+ and since dht - hdt is an integer, we also have:
- -1 <= dht - hdt <= 1
+ -1 <= dht - hdt <= 1
- or equivalently:
+ or equivalently:
- 0 <= dht - hdt + 1 <= 2
+ 0 <= dht - hdt + 1 <= 2
- In the above analysis, all the operators have their exact
- mathematical semantics, not C semantics. However, dht - hdt +
- 1 is unsigned in C, so it need not be compared to zero. */
+ In the above analysis, all the operators have their exact
+ mathematical semantics, not C semantics. However, dht - hdt +
+ 1 is unsigned in C, so it need not be compared to zero. */
- uintmax_t hdt = dt / 2;
- time_t ht1 = time1 / 2;
- time_t ht0 = time0 / 2;
- time_t dht = ht1 - ht0;
+ uintmax_t hdt = dt / 2;
+ __time64_t ht1 = time1 / 2;
+ __time64_t ht0 = time0 / 2;
+ __time64_t dht = ht1 - ht0;
- if (2 < dht - hdt + 1)
- {
- /* Repair delta overflow.
+ if (2 < dht - hdt + 1)
+ {
+ /* Repair delta overflow.
- The following expression contains a second rounding,
- so the result may not be the closest to the true answer.
- This problem occurs only with very large differences.
- It's too painful to fix this portably. */
+ The following expression contains a second rounding,
+ so the result may not be the closest to the true answer.
+ This problem occurs only with very large differences.
+ It's too painful to fix this portably. */
- delta = dt + 2.0L * (UINTMAX_MAX - UINTMAX_MAX / 2);
- }
+ delta = dt + 2.0L * (UINTMAX_MAX - UINTMAX_MAX / 2);
}
+}
- return delta;
- }
+ return delta;
}
/* Return the difference between TIME1 and TIME0. */
double
-__difftime (time_t time1, time_t time0)
+__difftime64 (__time64_t time1, __time64_t time0)
{
- /* Convert to double and then subtract if no double-rounding error could
+ /* Convert to long double and then subtract if no double-rounding error could
result. */
- if (TYPE_BITS (time_t) <= DBL_MANT_DIG
- || (TYPE_FLOATING (time_t) && sizeof (time_t) < sizeof (long double)))
- return (double) time1 - (double) time0;
-
- /* Likewise for long double. */
-
- if (TYPE_BITS (time_t) <= LDBL_MANT_DIG || TYPE_FLOATING (time_t))
+ if (TYPE_BITS (__time64_t) <= LDBL_MANT_DIG)
return (long double) time1 - (long double) time0;
/* Subtract the smaller integer from the larger, convert the difference to
@@ -118,4 +106,12 @@ __difftime (time_t time1, time_t time0)
return time1 < time0 ? - subtract (time0, time1) : subtract (time1, time0);
}
+
+/* Return the difference between TIME1 and TIME0. */
+double
+__difftime (time_t time1, time_t time0)
+{
+ return __difftime64 (time1, time0);
+}
strong_alias (__difftime, difftime)
+