1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2013 Pluribus Networks Inc.
14 * Copyright 2020 Oxide Computer Company
15 */
16
17 #ifndef _COMPAT_FREEBSD_SYS_TIME_H_
18 #define _COMPAT_FREEBSD_SYS_TIME_H_
19
20 #include_next <sys/time.h>
21
22 #define tc_precexp 0
23
24 struct bintime {
25 ulong_t sec; /* seconds */
26 uint64_t frac; /* 64 bit fraction of a second */
27 };
28
29 #define BT2FREQ(bt) \
30 (((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) / \
31 ((bt)->frac >> 1))
32
33 #define FREQ2BT(freq, bt) \
34 { \
35 (bt)->sec = 0; \
36 (bt)->frac = ((uint64_t)0x8000000000000000 / (freq)) << 1; \
37 }
38
39 static __inline void
binuptime(struct bintime * bt)40 binuptime(struct bintime *bt)
41 {
42 hrtime_t now = gethrtime();
43
44 bt->sec = now / 1000000000;
45 /* 18446744073 = int(2^64 / 1000000000) = 1ns in 64-bit fractions */
46 bt->frac = (now % 1000000000) * (uint64_t)18446744073LL;
47 }
48
49 #define bintime_cmp(a, b, cmp) \
50 (((a)->sec == (b)->sec) ? \
51 ((a)->frac cmp (b)->frac) : \
52 ((a)->sec cmp (b)->sec))
53
54 /*
55 * The bintime_cmp() macro is problematic for a couple reasons:
56 * 1. Bearing a lowercase name suggests it is a function rather than a macro.
57 * 2. Placing the comparison operator as the last argument runs afoul of our
58 * cstyle rules, unlike cases such as VERIFY3*().
59 *
60 * To remedy these issues in illumos bhyve, we provide a slightly modified
61 * version which addresses both problems.
62 */
63 #define BINTIME_CMP(a, cmp, b) bintime_cmp((a), (b), cmp)
64
65 #define SBT_1S ((sbintime_t)1 << 32)
66 #define SBT_1M (SBT_1S * 60)
67 #define SBT_1MS (SBT_1S / 1000)
68 #define SBT_1US (SBT_1S / 1000000)
69 #define SBT_1NS (SBT_1S / 1000000000)
70 #define SBT_MAX 0x7fffffffffffffffLL
71
72
73 static __inline void
bintime_add(struct bintime * bt,const struct bintime * bt2)74 bintime_add(struct bintime *bt, const struct bintime *bt2)
75 {
76 uint64_t u;
77
78 u = bt->frac;
79 bt->frac += bt2->frac;
80 if (u > bt->frac)
81 bt->sec++;
82 bt->sec += bt2->sec;
83 }
84
85 static __inline void
bintime_sub(struct bintime * bt,const struct bintime * bt2)86 bintime_sub(struct bintime *bt, const struct bintime *bt2)
87 {
88 uint64_t u;
89
90 u = bt->frac;
91 bt->frac -= bt2->frac;
92 if (u < bt->frac)
93 bt->sec--;
94 bt->sec -= bt2->sec;
95 }
96
97 static __inline void
bintime_mul(struct bintime * bt,u_int x)98 bintime_mul(struct bintime *bt, u_int x)
99 {
100 uint64_t p1, p2;
101
102 p1 = (bt->frac & 0xffffffffull) * x;
103 p2 = (bt->frac >> 32) * x + (p1 >> 32);
104 bt->sec *= x;
105 bt->sec += (p2 >> 32);
106 bt->frac = (p2 << 32) | (p1 & 0xffffffffull);
107 }
108
109 static __inline sbintime_t
bttosbt(const struct bintime bt)110 bttosbt(const struct bintime bt)
111 {
112 return (((sbintime_t)bt.sec << 32) + (bt.frac >> 32));
113 }
114
115 static __inline struct bintime
sbttobt(sbintime_t _sbt)116 sbttobt(sbintime_t _sbt)
117 {
118 struct bintime _bt;
119
120 _bt.sec = _sbt >> 32;
121 _bt.frac = _sbt << 32;
122 return (_bt);
123 }
124
125 static __inline sbintime_t
sbinuptime(void)126 sbinuptime(void)
127 {
128 hrtime_t hrt = gethrtime();
129 uint64_t sec = hrt / NANOSEC;
130 uint64_t nsec = hrt % NANOSEC;
131
132 return (((sbintime_t)sec << 32) +
133 (nsec * (((uint64_t)1 << 63) / 500000000) >> 32));
134 }
135
136 #endif /* _COMPAT_FREEBSD_SYS_TIME_H_ */
137