At 11:31 AM 7/11/2002, Brian Pane wrote:
I don't see a way to eliminate the "/ 1000" to convert usec to
msec.  But we may be able to do all the math in 32-bit mode, by
limiting the maximum timeout to the number of milliseconds that
will fit in 32 bits, which works out to a max timeout of about
50 days.

Actually, here is my current math, with optimized forms for specific situations we encounter often (aprox. limits are given in the macro name).

They break down to;

apr_int32_t apr_time_sec_get(time)  deprecates apr_time_sec(time)
apr_int32_t apr_time_msec_get(time) deprecates apr_time_msec(time)
apr_int32_t apr_time_usec_get(time) deprecates apr_time_usec(time)
apr_int32_t apr_time_nsec_get(time) deprecates apr_time_nsec(time)

apr_int64_t apr_time_as_sec(time)
apr_int64_t apr_time_as_msec(time) or apr_time_as_272yrs_msec(time)
apr_int64_t apr_time_as_usec(time) or apr_time_as_3mos_usec(time)
apr_int64_t apr_time_as_nsec(time) or apr_time_as_2hrs_nsec(time)

apr_time_t apr_time_mmake(sec, msec)
apr_time_t apr_time_umake(sec, usec)
apr_time_t apr_time_nmake(sec, nsec)

apr_time_t apr_time_from_sec(sec)
apr_time_t apr_time_from_msec(msec) or apr_time_from_3mos_msec(msec)
apr_time_t apr_time_from_usec(usec) or apr_time_from_3mos_usec(usec)
apr_time_t apr_time_from_nsec(nsec) or apr_time_from_3mos_nsec(nsec)

The code follows, patch attached is hard to follow.  [Like my code isn't :o]

/* Number of binary microseconds per second is (2^20)
 * to keep the math fast and simple [binary arithmetic.]
 */
#define APR_BUSEC_BITS 20
#define APR_BUSEC_PER_SEC APR_TIME_C(2 ^ APR_BUSEC_BITS)

/* apr_time_sec_get returns 32 bits and is subject to the Y2038 bug
 * @see apr_time_as_sec for 64 bit resolution
 */
#define apr_time_sec_get(time) ((apr_int32_t)((time) >> APR_BUSEC_BITS))

/* These functions 'get' the xsec fractional component of the time.
 *
 * msec extraction won't overflow 32 bits so convert early,
 * while usec/nsec computations must be in all 64 bit math.
 */
#define apr_time_msec_get(time) \
    (((apr_int32_t)((time) & (APR_BUSEC_PER_SEC - 1)) * 1000) \
                                                   >> APR_BUSEC_BITS)

#define apr_time_usec_get(time) \
    ((apr_int32_t)((((time) & (APR_BUSEC_PER_SEC - 1)) \
                            * APR_TIME_C(1000000)) >> APR_BUSEC_BITS))

#define apr_time_nsec_get(time) \
    ((apr_int32_t)((((time) & (APR_BUSEC_PER_SEC - 1)) \
                            * APR_TIME_C(1000000000)) >> APR_BUSEC_BITS))


/* apr_time_as_sec returns 64 bits and escapes the Y2038 bug * @see apr_time_sec_get for 32 bit resolution */ #define apr_time_as_sec(time) ((apr_int64_t)((time) >> APR_BUSEC_BITS))

/* These functions return the given time value, complete,
 * in the given resolution (not simply the fractional component)
 *
 * They carry no resolution penalty, and due to the binary math,
 * they suffer little performance penalty either.
 */
#define apr_time_as_msec(time) \
    (((apr_int64_t)(time) >> APR_BUSEC_BITS) \
     + ((((apr_int32_t)(time) & (APR_BUSEC_PER_SEC - 1)) \
         * 1000) >> APR_BUSEC_BITS))

#define apr_time_as_usec(time) \
    (((apr_int64_t)(time) >> APR_BUSEC_BITS) \
     + ((((apr_int64_t)(time) & (APR_BUSEC_PER_SEC - 1)) \
         * APR_TIME_C(1000000)) >> APR_BUSEC_BITS))

#define apr_time_as_nsec(time) \
    (((apr_int64_t)(time) >> APR_BUSEC_BITS) \
     + ((((apr_int64_t)(time) & (APR_BUSEC_PER_SEC - 1)) \
         * APR_TIME_C(1000000000)) >> APR_BUSEC_BITS))

/* this computation is alright, but not great, we are limited to 272
 * years.  No Y2038 bug, but consider it an 'optimized form' for which
 * we have some loss of resolution.  Doing this in 32 bit signed math
 * would yield only 2 seconds, which is not worth implementing compared
 * to the existing apr_time_msec_get().
 */
#define apr_time_as_272yrs_msec(time) \
    (((apr_int64_t)(time) * APR_TIME_C(1000)) >> APR_BUSEC_BITS)

/* Another optimized form, we are limited to some 101 days.
 * Consider it a bleeding optimization with a great loss of resolution.
 */
#define apr_time_as_3mos_usec(time) \
    (((apr_int64_t)(time) * APR_TIME_C(1000000)) >> APR_BUSEC_BITS)

/* The final optimized form, we are limited to some 2.44 hours.
 * Use with extreme care.
 */
#define apr_time_as_2hrs_nsec(time) \
    (((apr_int64_t)(time) * APR_TIME_C(1000000000)) >> APR_BUSEC_BITS)


/* These have no loss of resolution if the 2nd xsec arg is < 1second */ #define apr_time_mmake(sec, msec) ((apr_time_t)(sec) << APR_BUSEC_BITS \ + ((apr_time_t)(msec) << APR_BUSEC_BITS) / APR_TIME_C(1000))

#define apr_time_umake(sec, usec) ((apr_time_t)(sec) << APR_BUSEC_BITS \
          + ((apr_time_t)(usec) << APR_BUSEC_BITS) / APR_TIME_C(1000000))

#define apr_time_nmake(sec, nsec) ((apr_time_t)(sec) << APR_BUSEC_BITS \
          + ((apr_time_t)(nsec) << APR_BUSEC_BITS) / APR_TIME_C(1000000000))


#define apr_time_from_sec(sec) ((apr_time_t)(sec) << APR_BUSEC_BITS)

/* These carry no resolution penalty, just a nasty performance penalty.
 */
#define apr_time_from_msec(msec) \
    ((((apr_time_t)(msec) / APR_TIME_C(1000)) << APR_BUSEC_BITS) \
     + ((((apr_time_t)(msec) % APR_TIME_C(1000)) << APR_BUSEC_BITS) \
        / APR_TIME_C(1000)))

#define apr_time_from_usec(usec) \
    ((((apr_time_t)(usec) / APR_TIME_C(1000000)) << APR_BUSEC_BITS) \
     + ((((apr_time_t)(usec) % APR_TIME_C(1000000)) << APR_BUSEC_BITS) \
        / APR_TIME_C(1000000)))

#define apr_time_from_nsec(nsec) \
    ((((apr_time_t)(nsec) / APR_TIME_C(1000000000)) << APR_BUSEC_BITS) \
     + ((((apr_time_t)(nsec) % APR_TIME_C(1000000000)) << APR_BUSEC_BITS) \
        / APR_TIME_C(1000000000)))

/* 97 day macros; you would expect these to be correct, until you
 * consider that the initial SHL reduces precision to 43 bits (signed)
 * of which 20 bits is the busecs.  23 remaining bits ~= 97 days.
 * The apr_time_xmake macros above doesn't suffer the problem, since
 * we presume that the xsec component is < 1 second... and the 'proper'
 * apr_time_from_xsec macros will split into integral and fractional
 * seconds while converting, so there is no unexpected loss of range.
 */
#define apr_time_from_3mos_msec(msec) \
    (((apr_time_t)(msec) << APR_BUSEC_BITS) / APR_TIME_C(1000))

#define apr_time_from_3mos_usec(usec) \
    (((apr_time_t)(usec) << APR_BUSEC_BITS) / APR_TIME_C(1000000))

#define apr_time_from_3mos_nsec(nsec) \
    (((apr_time_t)(usec) << APR_BUSEC_BITS) / APR_TIME_C(1000000000))

/* XXX These are ambiguous and dangerous.  The symbol names must be
 * deprecated to assure folks don't misuse them (_xsec_get vs _as_xsec)
 */
#define apr_time_sec apr_time_sec_get
#define apr_time_msec apr_time_msec_get
#define apr_time_usec apr_time_usec_get
#define apr_time_nsec apr_time_nsec_get

/* XXX Also dangerous, since folks might assume the literal meaning.
 * we have no need to define this constant anymore for library users
 */
#define APR_USEC_PER_SEC APR_BUSEC_PER_SEC
Index: include/apr_time.h
===================================================================
RCS file: /home/cvs/apr/include/apr_time.h,v
retrieving revision 1.54
diff -u -r1.54 apr_time.h
--- include/apr_time.h  2 Jul 2002 15:47:12 -0000       1.54
+++ include/apr_time.h  11 Jul 2002 18:53:13 -0000
@@ -92,19 +92,144 @@
 /** short interval for I/O timeouts, in microseconds */
 typedef apr_int32_t apr_short_interval_time_t;
 
-/** number of microseconds per second */
-#define APR_USEC_PER_SEC APR_TIME_C(1000000)
+/* Number of binary microseconds per second is (2^20) 
+ * to keep the math fast and simple [binary arithmetic.]
+ */
+#define APR_BUSEC_BITS 20
+#define APR_BUSEC_PER_SEC APR_TIME_C(2 ^ APR_BUSEC_BITS)
 
-#define apr_time_usec(time) ((apr_int32_t)((time) % APR_USEC_PER_SEC))
+/* apr_time_sec_get returns 32 bits and is subject to the Y2038 bug
+ * @see apr_time_as_sec for 64 bit resolution
+ */
+#define apr_time_sec_get(time) ((apr_int32_t)((time) >> APR_BUSEC_BITS))
 
-#define apr_time_nsec(time) ((apr_int32_t)((time) % APR_USEC_PER_SEC) * 
(apr_int32_t)1000)
+/* These functions 'get' the xsec fractional component of the time.
+ *
+ * msec extraction won't overflow 32 bits so convert early, 
+ * while usec/nsec computations must be in all 64 bit math.
+ */
+#define apr_time_msec_get(time) \
+    (((apr_int32_t)((time) & (APR_BUSEC_PER_SEC - 1)) * 1000) \
+                                                   >> APR_BUSEC_BITS)
 
-#define apr_time_sec(time) ((apr_int64_t)((time) / APR_USEC_PER_SEC))
+#define apr_time_usec_get(time) \
+    ((apr_int32_t)((((time) & (APR_BUSEC_PER_SEC - 1)) \
+                            * APR_TIME_C(1000000)) >> APR_BUSEC_BITS))
 
-#define apr_time_from_sec(sec) ((apr_time_t)(sec) * APR_USEC_PER_SEC)
+#define apr_time_nsec_get(time) \
+    ((apr_int32_t)((((time) & (APR_BUSEC_PER_SEC - 1)) \
+                            * APR_TIME_C(1000000000)) >> APR_BUSEC_BITS))
+
+
+/* apr_time_as_sec returns 64 bits and escapes the Y2038 bug
+ * @see apr_time_sec_get for 32 bit resolution
+ */
+#define apr_time_as_sec(time) ((apr_int64_t)((time) >> APR_BUSEC_BITS))
+
+/* These functions return the given time value, complete,
+ * in the given resolution (not simply the fractional component)
+ *
+ * They carry no resolution penalty, and due to the binary math,
+ * they suffer little performance penalty either.
+ */
+#define apr_time_as_msec(time) \
+    (((apr_int64_t)(time) >> APR_BUSEC_BITS) \
+     + ((((apr_int32_t)(time) & (APR_BUSEC_PER_SEC - 1)) \
+         * 1000) >> APR_BUSEC_BITS))
+
+#define apr_time_as_usec(time) \
+    (((apr_int64_t)(time) >> APR_BUSEC_BITS) \
+     + ((((apr_int64_t)(time) & (APR_BUSEC_PER_SEC - 1)) \
+         * APR_TIME_C(1000000)) >> APR_BUSEC_BITS))
+
+#define apr_time_as_nsec(time) \
+    (((apr_int64_t)(time) >> APR_BUSEC_BITS) \
+     + ((((apr_int64_t)(time) & (APR_BUSEC_PER_SEC - 1)) \
+         * APR_TIME_C(1000000000)) >> APR_BUSEC_BITS))
+
+/* this computation is alright, but not great, we are limited to 272
+ * years.  No Y2038 bug, but consider it an 'optimized form' for which
+ * we have some loss of resolution.  Doing this in 32 bit signed math
+ * would yield only 2 seconds, which is not worth implementing compared 
+ * to the existing apr_time_msec_get().
+ */
+#define apr_time_as_272yrs_msec(time) \
+    (((apr_int64_t)(time) * APR_TIME_C(1000)) >> APR_BUSEC_BITS)
+
+/* Another optimized form, we are limited to some 101 days.
+ * Consider it a bleeding optimization with a great loss of resolution.
+ */
+#define apr_time_as_3mos_usec(time) \
+    (((apr_int64_t)(time) * APR_TIME_C(1000000)) >> APR_BUSEC_BITS)
+
+/* The final optimized form, we are limited to some 2.44 hours.
+ * Use with extreme care.
+ */
+#define apr_time_as_2hrs_nsec(time) \
+    (((apr_int64_t)(time) * APR_TIME_C(1000000000)) >> APR_BUSEC_BITS)
+
+
+/* These have no loss of resolution if the 2nd xsec arg is < 1second
+ */
+#define apr_time_mmake(sec, msec) ((apr_time_t)(sec) << APR_BUSEC_BITS \
+          + ((apr_time_t)(msec) << APR_BUSEC_BITS) / APR_TIME_C(1000))
+
+#define apr_time_umake(sec, usec) ((apr_time_t)(sec) << APR_BUSEC_BITS \
+          + ((apr_time_t)(usec) << APR_BUSEC_BITS) / APR_TIME_C(1000000)) 
+
+#define apr_time_nmake(sec, nsec) ((apr_time_t)(sec) << APR_BUSEC_BITS \
+          + ((apr_time_t)(nsec) << APR_BUSEC_BITS) / APR_TIME_C(1000000000)) 
+
+
+#define apr_time_from_sec(sec)  ((apr_time_t)(sec) << APR_BUSEC_BITS)
+
+/* These carry no resolution penalty, just a nasty performance penalty.
+ */
+#define apr_time_from_msec(msec) \
+    ((((apr_time_t)(msec) / APR_TIME_C(1000)) << APR_BUSEC_BITS) \
+     + ((((apr_time_t)(msec) % APR_TIME_C(1000)) << APR_BUSEC_BITS) \
+        / APR_TIME_C(1000)))
+
+#define apr_time_from_usec(usec) \
+    ((((apr_time_t)(usec) / APR_TIME_C(1000000)) << APR_BUSEC_BITS) \
+     + ((((apr_time_t)(usec) % APR_TIME_C(1000000)) << APR_BUSEC_BITS) \
+        / APR_TIME_C(1000000)))
+
+#define apr_time_from_nsec(nsec) \
+    ((((apr_time_t)(nsec) / APR_TIME_C(1000000000)) << APR_BUSEC_BITS) \
+     + ((((apr_time_t)(nsec) % APR_TIME_C(1000000000)) << APR_BUSEC_BITS) \
+        / APR_TIME_C(1000000000)))
+
+/* 97 day macros; you would expect these to be correct, until you
+ * consider that the initial SHL reduces precision to 43 bits (signed)
+ * of which 20 bits is the busecs.  23 remaining bits ~= 97 days.
+ * The apr_time_xmake macros above doesn't suffer the problem, since
+ * we presume that the xsec component is < 1 second... and the 'proper'
+ * apr_time_from_xsec macros will split into integral and fractional
+ * seconds while converting, so there is no unexpected loss of range.
+ */
+#define apr_time_from_3mos_msec(msec) \
+    (((apr_time_t)(msec) << APR_BUSEC_BITS) / APR_TIME_C(1000))
+
+#define apr_time_from_3mos_usec(usec) \
+    (((apr_time_t)(usec) << APR_BUSEC_BITS) / APR_TIME_C(1000000))
+
+#define apr_time_from_3mos_nsec(nsec) \
+    (((apr_time_t)(usec) << APR_BUSEC_BITS) / APR_TIME_C(1000000000))
+
+/* XXX These are ambiguous and dangerous.  The symbol names must be
+ * deprecated to assure folks don't misuse them (_xsec_get vs _as_xsec)
+ */
+#define apr_time_sec apr_time_sec_get
+#define apr_time_msec apr_time_msec_get
+#define apr_time_usec apr_time_usec_get
+#define apr_time_nsec apr_time_nsec_get
+
+/* XXX Also dangerous, since folks might assume the literal meaning.
+ * we have no need to define this constant anymore for library users
+ */
+#define APR_USEC_PER_SEC APR_BUSEC_PER_SEC
 
-#define apr_time_make(sec, usec) ((apr_time_t)(sec) * APR_USEC_PER_SEC \
-                                + (apr_time_t)(usec))
 
 /**
  * return the current time

Reply via email to