[PATCH 2/7] Add inline functions to convert between sbintime_t

Sebastian Huber <[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
From: ian <[email protected]>

and decimal time units. Use them in some existing code that is
vulnerable to roundoff errors.

The existing constant SBT_1NS is a honeypot, luring unsuspecting folks into
writing code such as long_timeout_ns*SBT_1NS to generate the argument for a
sleep call.  The actual value of 1ns in sbt units is ~4.3, leading to a
large roundoff error giving a shorter sleep than expected when multiplying
by the trucated value of 4 in SBT_1NS.  (The evil honeypot aspect becomes
clear after you waste a whole day figuring out why your sleeps return early.)
---
 newlib/libc/include/sys/time.h | 59 +++++++++++++++++++++++++++++++++++++-----
 1 file changed, 52 insertions(+), 7 deletions(-)

diff --git a/newlib/libc/include/sys/time.h b/newlib/libc/include/sys/time.h
index 2cf543d0b..f263a5352 100644
--- a/newlib/libc/include/sys/time.h
+++ b/newlib/libc/include/sys/time.h
@@ -138,7 +138,7 @@ bintime_shift(struct bintime *_bt, int _exp)
 #define	SBT_1M	(SBT_1S * 60)
 #define	SBT_1MS	(SBT_1S / 1000)
 #define	SBT_1US	(SBT_1S / 1000000)
-#define	SBT_1NS	(SBT_1S / 1000000000)
+#define	SBT_1NS	(SBT_1S / 1000000000) /* beware rounding, see nstosbt() */
 #define	SBT_MAX	0x7fffffffffffffffLL
 
 static __inline int
@@ -165,6 +165,53 @@ sbttobt(sbintime_t _sbt)
 	return (_bt);
 }
 
+/*
+ * Decimal<->sbt conversions.  Multiplying or dividing by SBT_1NS results in
+ * large roundoff errors which sbttons() and nstosbt() avoid.  Millisecond and
+ * microsecond functions are also provided for completeness.
+ */
+static __inline int64_t
+sbttons(sbintime_t _sbt)
+{
+
+	return ((1000000000 * _sbt) >> 32);
+}
+
+static __inline sbintime_t
+nstosbt(int64_t _ns)
+{
+
+	return ((_ns * (((uint64_t)1 << 63) / 500000000) >> 32));
+}
+
+static __inline int64_t
+sbttous(sbintime_t _sbt)
+{
+
+	return ((1000000 * _sbt) >> 32);
+}
+
+static __inline sbintime_t
+ustosbt(int64_t _us)
+{
+
+	return ((_us * (((uint64_t)1 << 63) / 500000) >> 32));
+}
+
+static __inline int64_t
+sbttoms(sbintime_t _sbt)
+{
+
+	return ((1000 * _sbt) >> 32);
+}
+
+static __inline sbintime_t
+mstosbt(int64_t _ms)
+{
+
+	return ((_ms * (((uint64_t)1 << 63) / 500) >> 32));
+}
+
 /*-
  * Background information:
  *
@@ -220,7 +267,7 @@ sbttots(sbintime_t _sbt)
 	struct timespec _ts;
 
 	_ts.tv_sec = _sbt >> 32;
-	_ts.tv_nsec = ((uint64_t)1000000000 * (uint32_t)_sbt) >> 32;
+	_ts.tv_nsec = sbttons((uint32_t)_sbt);
 	return (_ts);
 }
 
@@ -228,8 +275,7 @@ static __inline sbintime_t
 tstosbt(struct timespec _ts)
 {
 
-	return (((sbintime_t)_ts.tv_sec << 32) +
-	    (_ts.tv_nsec * (((uint64_t)1 << 63) / 500000000) >> 32));
+	return (((sbintime_t)_ts.tv_sec << 32) + nstosbt(_ts.tv_nsec));
 }
 
 static __inline struct timeval
@@ -238,7 +284,7 @@ sbttotv(sbintime_t _sbt)
 	struct timeval _tv;
 
 	_tv.tv_sec = _sbt >> 32;
-	_tv.tv_usec = ((uint64_t)1000000 * (uint32_t)_sbt) >> 32;
+	_tv.tv_usec = sbttous((uint32_t)_sbt);
 	return (_tv);
 }
 
@@ -246,8 +292,7 @@ static __inline sbintime_t
 tvtosbt(struct timeval _tv)
 {
 
-	return (((sbintime_t)_tv.tv_sec << 32) +
-	    (_tv.tv_usec * (((uint64_t)1 << 63) / 500000) >> 32));
+	return (((sbintime_t)_tv.tv_sec << 32) + ustosbt(_tv.tv_usec));
 }
 #endif /* __BSD_VISIBLE */
 
-- 
2.16.4
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.