Page MenuHomeFreeBSD

D36857.id111328.diff
No OneTemporary

D36857.id111328.diff

diff --git a/sys/sys/time.h b/sys/sys/time.h
--- a/sys/sys/time.h
+++ b/sys/sys/time.h
@@ -158,118 +158,86 @@
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.
- *
- * These functions return the smallest sbt larger or equal to the
- * number of seconds requested so that sbttoX(Xtosbt(y)) == y. Unlike
- * top of second computations below, which require that we tick at the
- * top of second, these need to be rounded up so we do whatever for at
- * least as long as requested.
- *
- * The naive computation we'd do is this
- * ((unit * 2^64 / SIFACTOR) + 2^32-1) >> 32
- * However, that overflows. Instead, we compute
- * ((unit * 2^63 / SIFACTOR) + 2^31-1) >> 32
- * and use pre-computed constants that are the ceil of the 2^63 / SIFACTOR
- * term to ensure we are using exactly the right constant. We use the lesser
- * evil of ull rather than a uint64_t cast to ensure we have well defined
- * right shift semantics. With these changes, we get all the ns, us and ms
- * conversions back and forth right.
- * Note: This file is used for both kernel and userland includes, so we can't
- * rely on KASSERT being defined, nor can we pollute the namespace by including
- * assert.h.
- */
-static __inline int64_t
-sbttons(sbintime_t _sbt)
-{
- uint64_t ns;
+/* This macro computes the greatest common divisor as a power of two value. */
+#define BSD_TIME_GCD(a, b) \
+ ((~(a) & ((a) - 1) & ~(b) & ((b) - 1)) + 1)
-#ifdef KASSERT
- KASSERT(_sbt >= 0, ("Negative values illegal for sbttons: %jx", _sbt));
-#endif
- ns = _sbt;
- if (ns >= SBT_1S)
- ns = (ns >> 32) * 1000000000;
- else
- ns = 0;
+/* This macro computes "(v * a + b - 1) / b" as 128-bit precision */
+#define BSD_STIME_SCALE_CEIL(v, a, b) \
+ bsd_stime_scale_ceil(v, (a) / BSD_TIME_GCD(a, b), (b) / BSD_TIME_GCD(a, b))
- return (ns + (1000000000 * (_sbt & 0xffffffffu) >> 32));
-}
+/* This macro computes "(v * a) / b" as 128-bit precision */
+#define BSD_STIME_SCALE_FLOOR(v, a, b) \
+ bsd_stime_scale_floor(v, (a) / BSD_TIME_GCD(a, b), (b) / BSD_TIME_GCD(a, b))
-static __inline sbintime_t
-nstosbt(int64_t _ns)
-{
- sbintime_t sb = 0;
+/* This macro computes "(v * a + b - 1) / b" as 128-bit precision */
+#define BSD_UTIME_SCALE_CEIL(v, a, b) \
+ bsd_utime_scale_ceil(v, (a) / BSD_TIME_GCD(a, b), (b) / BSD_TIME_GCD(a, b))
-#ifdef KASSERT
- KASSERT(_ns >= 0, ("Negative values illegal for nstosbt: %jd", _ns));
-#endif
- if (_ns >= 1000000000) {
- sb = (_ns / 1000000000) * SBT_1S;
- _ns = _ns % 1000000000;
- }
- /* 9223372037 = ceil(2^63 / 1000000000) */
- sb += ((_ns * 9223372037ull) + 0x7fffffff) >> 31;
- return (sb);
-}
+/* This macro computes "(v * a) / b" as 128-bit precision */
+#define BSD_UTIME_SCALE_FLOOR(v, a, b) \
+ bsd_utime_scale_floor(v, (a) / BSD_TIME_GCD(a, b), (b) / BSD_TIME_GCD(a, b))
static __inline int64_t
-sbttous(sbintime_t _sbt)
+bsd_stime_scale_ceil(int64_t x, int32_t factor, int32_t divisor)
{
+ const int64_t rem = (x % divisor);
-#ifdef KASSERT
- KASSERT(_sbt >= 0, ("Negative values illegal for sbttous: %jx", _sbt));
-#endif
- return ((_sbt >> 32) * 1000000 +
- (1000000 * (_sbt & 0xffffffffu) >> 32));
+ return ((x / divisor) * factor + (rem * factor + divisor - 1) / divisor);
}
-static __inline sbintime_t
-ustosbt(int64_t _us)
+static __inline int64_t
+bsd_stime_scale_floor(int64_t x, int32_t factor, int32_t divisor)
{
- sbintime_t sb = 0;
+ const int64_t rem = (x % divisor);
-#ifdef KASSERT
- KASSERT(_us >= 0, ("Negative values illegal for ustosbt: %jd", _us));
-#endif
- if (_us >= 1000000) {
- sb = (_us / 1000000) * SBT_1S;
- _us = _us % 1000000;
- }
- /* 9223372036855 = ceil(2^63 / 1000000) */
- sb += ((_us * 9223372036855ull) + 0x7fffffff) >> 31;
- return (sb);
+ return ((x / divisor) * factor + (rem * factor) / divisor);
}
-static __inline int64_t
-sbttoms(sbintime_t _sbt)
+static __inline uint64_t
+bsd_utime_scale_ceil(uint64_t x, uint32_t factor, uint32_t divisor)
{
-#ifdef KASSERT
- KASSERT(_sbt >= 0, ("Negative values illegal for sbttoms: %jx", _sbt));
-#endif
- return ((_sbt >> 32) * 1000 + (1000 * (_sbt & 0xffffffffu) >> 32));
+ const uint64_t rem = (x % divisor);
+
+ return ((x / divisor) * factor + (rem * factor + divisor - 1) / divisor);
}
-static __inline sbintime_t
-mstosbt(int64_t _ms)
+static __inline uint64_t
+bsd_utime_scale_floor(uint64_t x, uint32_t factor, uint32_t divisor)
{
- sbintime_t sb = 0;
+ const uint64_t rem = (x % divisor);
-#ifdef KASSERT
- KASSERT(_ms >= 0, ("Negative values illegal for mstosbt: %jd", _ms));
-#endif
- if (_ms >= 1000) {
- sb = (_ms / 1000) * SBT_1S;
- _ms = _ms % 1000;
- }
- /* 9223372036854776 = ceil(2^63 / 1000) */
- sb += ((_ms * 9223372036854776ull) + 0x7fffffff) >> 31;
- return (sb);
+ return ((x / divisor) * factor + (rem * factor) / divisor);
+}
+
+/*
+ * 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.
+ *
+ * When converting from sbt to another unit, the result is always
+ * rounded down. When converting back to sbt the result is always
+ * rounded up. This gives the property that sbttoX(Xtosbt(y)) == y .
+ *
+ * The conversion functions can also handle negative values.
+ */
+#define SBT_DECLARE_CONVERSION_PAIR(name, units_per_second) \
+static __inline int64_t \
+sbtto##name(sbintime_t sbt) \
+{ \
+ return (BSD_STIME_SCALE_FLOOR(sbt, units_per_second, SBT_1S)); \
+} \
+static __inline sbintime_t \
+name##tosbt(int64_t name) \
+{ \
+ return (BSD_STIME_SCALE_CEIL(name, SBT_1S, units_per_second)); \
}
+SBT_DECLARE_CONVERSION_PAIR(ns, 1000000000)
+SBT_DECLARE_CONVERSION_PAIR(us, 1000000)
+SBT_DECLARE_CONVERSION_PAIR(ms, 1000)
+
/*-
* Background information:
*
@@ -289,8 +257,8 @@
{
_ts->tv_sec = _bt->sec;
- _ts->tv_nsec = ((uint64_t)1000000000 *
- (uint32_t)(_bt->frac >> 32)) >> 32;
+ _ts->tv_nsec = BSD_UTIME_SCALE_FLOOR(
+ _bt->frac, 1000000000, 1ULL << 32) >> 32;
}
static __inline uint64_t
@@ -299,8 +267,8 @@
uint64_t ret;
ret = (uint64_t)(_bt->sec) * (uint64_t)1000000000;
- ret += (((uint64_t)1000000000 *
- (uint32_t)(_bt->frac >> 32)) >> 32);
+ ret += BSD_UTIME_SCALE_FLOOR(
+ _bt->frac, 1000000000, 1ULL << 32) >> 32;
return (ret);
}
@@ -309,8 +277,8 @@
{
_bt->sec = _ts->tv_sec;
- /* 18446744073 = int(2^64 / 1000000000) */
- _bt->frac = _ts->tv_nsec * (uint64_t)18446744073LL;
+ _bt->frac = BSD_UTIME_SCALE_FLOOR(
+ (uint64_t)_ts->tv_nsec << 32, 1ULL << 32, 1000000000);
}
static __inline void
@@ -318,7 +286,8 @@
{
_tv->tv_sec = _bt->sec;
- _tv->tv_usec = ((uint64_t)1000000 * (uint32_t)(_bt->frac >> 32)) >> 32;
+ _tv->tv_usec = BSD_UTIME_SCALE_FLOOR(
+ _bt->frac, 1000000, 1ULL << 32) >> 32;
}
static __inline void
@@ -326,8 +295,8 @@
{
_bt->sec = _tv->tv_sec;
- /* 18446744073709 = int(2^64 / 1000000) */
- _bt->frac = _tv->tv_usec * (uint64_t)18446744073709LL;
+ _bt->frac = BSD_UTIME_SCALE_FLOOR(
+ (uint64_t)_tv->tv_usec << 32, 1ULL << 32, 1000000);
}
static __inline struct timespec

File Metadata

Mime Type
text/plain
Expires
Sat, Aug 8, 6:40 AM (15 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36214771
Default Alt Text
D36857.id111328.diff (7 KB)

Event Timeline