Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F165263450
D36857.id111328.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D36857.id111328.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D36857: time(3): Increase precision of sbt and bintime conversion functions by using gcd.
Attached
Detach File
Event Timeline
Log In to Comment