ReXGlue SDK
Loading...
Searching...
No Matches
chrono.h
Go to the documentation of this file.
1
16
17#pragma once
18
19#include <atomic>
20#include <chrono>
21#include <utility>
22
23#include <rex/platform.h>
24#include <rex/types.h>
25
26namespace rex {
27
32 public:
38 static bool IsNoScaling();
39
40 static u64 GetHostTickFrequency() noexcept;
41
42 static u64 GetHostTickCount() noexcept;
43
47 static u64 QueryHostSystemTime() noexcept;
48
51
53 static f64 GetGuestTimeScalar();
54
59 static void SetGuestTimeScalar(f64 scalar);
60
65 static std::pair<u64, u64> GetGuestTickRatio();
66
67 static u64 GetGuestTickFrequency();
68
74 static void SetGuestTickFrequency(u64 frequency);
75
81
87 static void SetGuestSystemTimeBase(u64 time_base);
88
90 static u64 QueryGuestTickCount();
91
97
100
106 static void SetGuestSystemTime(u64 system_time);
107
113 static u32 ScaleGuestDurationMillis(u32 guest_ms);
114
123 static i64 ScaleGuestDurationFileTime(i64 guest_file_time);
124
131 static void ScaleGuestDurationTimeval(i32* tv_sec, i32* tv_usec);
132};
133
135using HundredNano = std::ratio<1, 10000000>;
136
138using HundredNanoseconds = std::chrono::duration<i64, HundredNano>;
139
140namespace detail {
141
142enum class Domain : u8 {
143 kHost,
144 kGuest
145};
146
148template <Domain Domain>
149struct NtSystemClock {
150 using rep = i64;
151 using period = HundredNano;
152 using duration = HundredNanoseconds;
153 using time_point = std::chrono::time_point<NtSystemClock<Domain>>;
154
155 public:
160 static constexpr std::chrono::seconds GetUnixEpochDelta() {
161 using std::chrono::steady_clock;
162 auto filetime_epoch = std::chrono::year{1601} / std::chrono::month{1} / std::chrono::day{1};
163 auto system_clock_epoch = std::chrono::year{1970} / std::chrono::month{1} / std::chrono::day{1};
164 auto fp =
165 static_cast<std::chrono::sys_seconds>(static_cast<std::chrono::sys_days>(filetime_epoch));
166 auto sp = static_cast<std::chrono::sys_seconds>(
167 static_cast<std::chrono::sys_days>(system_clock_epoch));
168 return fp.time_since_epoch() - sp.time_since_epoch();
169 }
170
171 static constexpr u64 ToFileTime(time_point const& tp) noexcept {
172 return static_cast<u64>(tp.time_since_epoch().count());
173 }
174
175 static constexpr time_point FromFileTime(u64 const& tp) noexcept {
176 return time_point{duration{tp}};
177 }
178
183 static constexpr std::chrono::sys_time<duration> to_sys(const time_point& tp)
184 requires(Domain == Domain::kHost)
185 {
186 return std::chrono::sys_time<duration>{tp.time_since_epoch() + GetUnixEpochDelta()};
187 }
188
194 template <typename SysDuration>
195 static constexpr time_point from_sys(const std::chrono::sys_time<SysDuration>& tp)
196 requires(Domain == Domain::kHost)
197 {
198 auto ctp = std::chrono::time_point_cast<duration>(tp);
199 return time_point{ctp.time_since_epoch() - GetUnixEpochDelta()};
200 }
201
202 [[nodiscard]] static time_point now() noexcept {
203 if constexpr (Domain == Domain::kHost) {
204 return FromFileTime(Clock::QueryHostSystemTime());
205 } else if constexpr (Domain == Domain::kGuest) {
206 return FromFileTime(Clock::QueryGuestSystemTime());
207 }
208 }
209};
210
211} // namespace detail
212
214using WinSystemClock = detail::NtSystemClock<detail::Domain::kHost>;
215
217using XSystemClock = detail::NtSystemClock<detail::Domain::kGuest>;
218
227inline u64 DecodeFATTimestamp(u32 date, u32 time) {
228 using namespace std::chrono;
229 const year_month first = year{1980 + static_cast<i32>((date >> 9) & 0x7F)} / January;
230 const year_month month = first + months{static_cast<i32>((date >> 5) & 0x0F) - 1};
231 const sys_days day = sys_days{month / 1} + days{static_cast<i32>(date & 0x1F) - 1};
232 const sys_seconds stamp = day + hours{static_cast<i32>((time >> 11) & 0x1F)} +
233 minutes{static_cast<i32>((time >> 5) & 0x3F)} +
234 seconds{static_cast<i32>((time & 0x1F) * 2)};
235 const i64 file_time_seconds =
236 stamp.time_since_epoch().count() -
237 detail::NtSystemClock<detail::Domain::kHost>::GetUnixEpochDelta().count();
238 return static_cast<u64>(file_time_seconds * HundredNano::den);
239}
240
241} // namespace rex
242
243// NOLINTNEXTLINE(bugprone-std-namespace-modification): permitted program defined clock
244namespace std::chrono {
245
246#ifdef _LIBCPP_VERSION
250template <class, class>
251struct clock_time_conversion {};
252
254template <class DestClock, class SourceClock, class Duration>
255auto clock_cast(const std::chrono::time_point<SourceClock, Duration>& t) {
256 return clock_time_conversion<DestClock, SourceClock>{}(t);
257}
258#endif
259
264template <>
265struct clock_time_conversion<::rex::WinSystemClock, ::rex::XSystemClock> {
270
272 template <typename Duration>
273 WClock::time_point operator()(const std::chrono::time_point<XClock, Duration>& t) const {
274 std::atomic_thread_fence(std::memory_order_acq_rel);
275 auto w_now = WClock::now();
276 auto x_now = XClock::now();
277 std::atomic_thread_fence(std::memory_order_acq_rel);
278
279 auto delta = (t - x_now);
281 delta = std::chrono::floor<WClock::duration>(delta * rex::Clock::GetGuestTimeScalar());
282 }
283 return w_now + delta;
284 }
285};
286
291template <>
292struct clock_time_conversion<::rex::XSystemClock, ::rex::WinSystemClock> {
297
299 template <typename Duration>
300 XClock::time_point operator()(const std::chrono::time_point<WClock, Duration>& t) const {
301 std::atomic_thread_fence(std::memory_order_acq_rel);
302 auto w_now = WClock::now();
303 auto x_now = XClock::now();
304 std::atomic_thread_fence(std::memory_order_acq_rel);
305
306 rex::HundredNanoseconds delta = (t - w_now);
308 delta = std::chrono::floor<WClock::duration>(delta / rex::Clock::GetGuestTimeScalar());
309 }
310 return x_now + delta;
311 }
312};
313
314} // namespace std::chrono
315
316// NOLINTNEXTLINE(bugprone-std-namespace-modification): permitted program defined clock
317namespace std::chrono {
318
323template <>
324struct clock_time_conversion<::rex::WinSystemClock, std::chrono::steady_clock> {
328 using SteadyClock = std::chrono::steady_clock;
329
331 template <typename Duration>
332 WinSystemClock::time_point operator()(
333 const std::chrono::time_point<SteadyClock, Duration>& t) const {
334 std::atomic_thread_fence(std::memory_order_acq_rel);
335 auto steady_now = SteadyClock::now();
336 auto nt_now = WinSystemClock::now();
337 std::atomic_thread_fence(std::memory_order_acq_rel);
338
339 auto delta = std::chrono::floor<WinSystemClock::duration>(t - steady_now);
340 return nt_now + delta;
341 }
342};
343
345template <>
346struct clock_time_conversion<std::chrono::steady_clock, ::rex::WinSystemClock> {
350 using SteadyClock = std::chrono::steady_clock;
351
353 template <typename Duration>
354 SteadyClock::time_point operator()(
355 const std::chrono::time_point<WinSystemClock, Duration>& t) const {
356 std::atomic_thread_fence(std::memory_order_acq_rel);
357 auto steady_now = SteadyClock::now();
358 auto nt_now = WinSystemClock::now();
359 std::atomic_thread_fence(std::memory_order_acq_rel);
360
361 auto delta = t - nt_now;
362 return steady_now + delta;
363 }
364};
365
366} // namespace std::chrono
Definition chrono.h:31
static u32 ScaleGuestDurationMillis(u32 guest_ms)
static void SetGuestTimeScalar(f64 scalar)
static u64 QueryGuestTickCount()
static u64 GetGuestSystemTimeBase()
static bool IsNoScaling()
static void ScaleGuestDurationTimeval(i32 *tv_sec, i32 *tv_usec)
static std::pair< u64, u64 > GetGuestTickRatio()
static i64 ScaleGuestDurationFileTime(i64 guest_file_time)
static f64 GetGuestTimeScalar()
static u64 QueryHostUptimeMillis()
static u32 GetGuestUptimeMillis()
static u64 QueryGuestSystemTime()
static void SetGuestSystemTime(u64 system_time)
static u64 QueryHostSystemTime() noexcept
static void SetGuestSystemTimeBase(u64 time_base)
static void SetGuestTickFrequency(u64 frequency)
Definition app.h:36
u64 DecodeFATTimestamp(u32 date, u32 time)
Definition chrono.h:227
std::ratio< 1, 10000000 > HundredNano
Definition chrono.h:135
detail::NtSystemClock< detail::Domain::kGuest > XSystemClock
Definition chrono.h:217
detail::NtSystemClock< detail::Domain::kHost > WinSystemClock
Definition chrono.h:214
std::chrono::duration< i64, HundredNano > HundredNanoseconds
Definition chrono.h:138
Platform flags, packing macros and export markers.
#define REX_API
Definition platform.h:177
SteadyClock::time_point operator()(const std::chrono::time_point< WinSystemClock, Duration > &t) const
Definition chrono.h:354
WClock::time_point operator()(const std::chrono::time_point< XClock, Duration > &t) const
Definition chrono.h:273
WinSystemClock::time_point operator()(const std::chrono::time_point< SteadyClock, Duration > &t) const
Definition chrono.h:332
XClock::time_point operator()(const std::chrono::time_point< WClock, Duration > &t) const
Definition chrono.h:300
Integer types, byte order wrappers and size literals.