[Kernel] Overhaul Rtl time functions.
- Add date third party submodule. - [Kernel] Add xclock. - [Kernel] Reimplement RtlTimeToTimeFields using std::chrono/date/xclock. - [Kernel] Reimplement RtlTimeFieldsToTime using std::chrono/date/xclock. - Supersedes #1612.
This commit is contained in:
parent
63ff758049
commit
4f25a96928
|
@ -70,3 +70,6 @@
|
||||||
[submodule "third_party/premake-androidmk"]
|
[submodule "third_party/premake-androidmk"]
|
||||||
path = third_party/premake-androidmk
|
path = third_party/premake-androidmk
|
||||||
url = https://github.com/Triang3l/premake-androidmk.git
|
url = https://github.com/Triang3l/premake-androidmk.git
|
||||||
|
[submodule "third_party/date"]
|
||||||
|
path = third_party/date
|
||||||
|
url = https://github.com/HowardHinnant/date.git
|
||||||
|
|
|
@ -21,14 +21,10 @@
|
||||||
#include "xenia/kernel/util/shim_utils.h"
|
#include "xenia/kernel/util/shim_utils.h"
|
||||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
||||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h"
|
#include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h"
|
||||||
|
#include "xenia/kernel/xclock.h"
|
||||||
#include "xenia/kernel/xevent.h"
|
#include "xenia/kernel/xevent.h"
|
||||||
#include "xenia/kernel/xthread.h"
|
#include "xenia/kernel/xthread.h"
|
||||||
|
|
||||||
#if XE_PLATFORM_WIN32
|
|
||||||
#include "xenia/base/platform_win.h"
|
|
||||||
#define timegm _mkgmtime
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
namespace xboxkrnl {
|
namespace xboxkrnl {
|
||||||
|
@ -507,44 +503,51 @@ struct X_TIME_FIELDS {
|
||||||
xe::be<uint16_t> milliseconds;
|
xe::be<uint16_t> milliseconds;
|
||||||
xe::be<uint16_t> weekday;
|
xe::be<uint16_t> weekday;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(X_TIME_FIELDS) == 16, "Must be LARGEINTEGER");
|
static_assert_size(X_TIME_FIELDS, 16);
|
||||||
|
|
||||||
// https://support.microsoft.com/en-us/kb/167296
|
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtltimetotimefields
|
||||||
void RtlTimeToTimeFields(lpqword_t time_ptr,
|
void RtlTimeToTimeFields(lpqword_t time_ptr,
|
||||||
pointer_t<X_TIME_FIELDS> time_fields_ptr) {
|
pointer_t<X_TIME_FIELDS> time_fields_ptr) {
|
||||||
int64_t time_ms = time_ptr.value() / 10000 - 11644473600000LL;
|
auto tp = XClock::to_sys(XClock::from_file_time(time_ptr.value()));
|
||||||
time_t timet = time_ms / 1000;
|
auto dp = date::floor<date::days>(tp);
|
||||||
struct tm* tm = gmtime(&timet);
|
auto year_month_day = date::year_month_day{dp};
|
||||||
|
auto weekday = date::weekday{dp};
|
||||||
time_fields_ptr->year = tm->tm_year + 1900;
|
auto time = date::hh_mm_ss{date::floor<std::chrono::milliseconds>(tp - dp)};
|
||||||
time_fields_ptr->month = tm->tm_mon + 1;
|
time_fields_ptr->year = static_cast<int>(year_month_day.year());
|
||||||
time_fields_ptr->day = tm->tm_mday;
|
time_fields_ptr->month = static_cast<unsigned>(year_month_day.month());
|
||||||
time_fields_ptr->hour = tm->tm_hour;
|
time_fields_ptr->day = static_cast<unsigned>(year_month_day.day());
|
||||||
time_fields_ptr->minute = tm->tm_min;
|
time_fields_ptr->weekday = weekday.c_encoding();
|
||||||
time_fields_ptr->second = tm->tm_sec;
|
time_fields_ptr->hour = time.hours().count();
|
||||||
time_fields_ptr->milliseconds = time_ms % 1000;
|
time_fields_ptr->minute = time.minutes().count();
|
||||||
time_fields_ptr->weekday = tm->tm_wday;
|
time_fields_ptr->second = static_cast<uint16_t>(time.seconds().count());
|
||||||
|
time_fields_ptr->milliseconds =
|
||||||
|
static_cast<uint16_t>(time.subseconds().count());
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(RtlTimeToTimeFields, kNone, kImplemented);
|
DECLARE_XBOXKRNL_EXPORT1(RtlTimeToTimeFields, kNone, kImplemented);
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtltimefieldstotime
|
||||||
dword_result_t RtlTimeFieldsToTime(pointer_t<X_TIME_FIELDS> time_fields_ptr,
|
dword_result_t RtlTimeFieldsToTime(pointer_t<X_TIME_FIELDS> time_fields_ptr,
|
||||||
lpqword_t time_ptr) {
|
lpqword_t time_ptr) {
|
||||||
struct tm tm;
|
if (time_fields_ptr->year < 1601 || time_fields_ptr->month < 1 ||
|
||||||
tm.tm_year = time_fields_ptr->year - 1900;
|
time_fields_ptr->month > 11 || time_fields_ptr->day < 1 ||
|
||||||
tm.tm_mon = time_fields_ptr->month - 1;
|
time_fields_ptr->hour > 23 || time_fields_ptr->minute > 59 ||
|
||||||
tm.tm_mday = time_fields_ptr->day;
|
time_fields_ptr->second > 59 || time_fields_ptr->milliseconds > 999) {
|
||||||
tm.tm_hour = time_fields_ptr->hour;
|
|
||||||
tm.tm_min = time_fields_ptr->minute;
|
|
||||||
tm.tm_sec = time_fields_ptr->second;
|
|
||||||
tm.tm_isdst = 0;
|
|
||||||
time_t timet = timegm(&tm);
|
|
||||||
if (timet == -1) {
|
|
||||||
// set last error = ERROR_INVALID_PARAMETER
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint64_t time =
|
auto year = date::year{time_fields_ptr->year};
|
||||||
((timet + 11644473600LL) * 1000 + time_fields_ptr->milliseconds) * 10000;
|
auto month = date::month{time_fields_ptr->month};
|
||||||
*time_ptr = time;
|
auto day = date::day{time_fields_ptr->day};
|
||||||
|
auto year_month_day = date::year_month_day{year, month, day};
|
||||||
|
if (!year_month_day.ok()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto dp = static_cast<date::sys_days>(year_month_day);
|
||||||
|
std::chrono::system_clock::time_point time = dp;
|
||||||
|
time += std::chrono::hours{time_fields_ptr->hour};
|
||||||
|
time += std::chrono::minutes{time_fields_ptr->minute};
|
||||||
|
time += std::chrono::seconds{time_fields_ptr->second};
|
||||||
|
time += std::chrono::milliseconds{time_fields_ptr->milliseconds};
|
||||||
|
*time_ptr = XClock::to_file_time(XClock::from_sys(time));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(RtlTimeFieldsToTime, kNone, kImplemented);
|
DECLARE_XBOXKRNL_EXPORT1(RtlTimeFieldsToTime, kNone, kImplemented);
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_KERNEL_XCLOCK_H_
|
||||||
|
#define XENIA_KERNEL_XCLOCK_H_
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "xenia/base/clock.h"
|
||||||
|
|
||||||
|
#include "third_party/date/include/date/date.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace kernel {
|
||||||
|
|
||||||
|
struct XClock {
|
||||||
|
using rep = int64_t;
|
||||||
|
using period = std::ratio_multiply<std::ratio<100>, std::nano>;
|
||||||
|
using duration = std::chrono::duration<rep, period>;
|
||||||
|
using time_point = std::chrono::time_point<XClock>;
|
||||||
|
static constexpr bool is_steady = false;
|
||||||
|
|
||||||
|
static time_point now() noexcept {
|
||||||
|
return from_file_time(Clock::QueryGuestSystemTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t to_file_time(time_point const& tp) noexcept {
|
||||||
|
return static_cast<uint64_t>(tp.time_since_epoch().count());
|
||||||
|
}
|
||||||
|
|
||||||
|
static time_point from_file_time(uint64_t const& tp) noexcept {
|
||||||
|
return time_point{duration{tp}};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::chrono::system_clock::time_point to_sys(time_point const& tp) {
|
||||||
|
// TODO(gibbed): verify behavior under Linux
|
||||||
|
using sys_duration = std::chrono::system_clock::duration;
|
||||||
|
using sys_time = std::chrono::system_clock::time_point;
|
||||||
|
auto dp = tp;
|
||||||
|
dp += system_clock_delta();
|
||||||
|
auto cdp = std::chrono::time_point_cast<sys_duration>(dp);
|
||||||
|
return sys_time{cdp.time_since_epoch()};
|
||||||
|
}
|
||||||
|
|
||||||
|
static time_point from_sys(std::chrono::system_clock::time_point const& tp) {
|
||||||
|
// TODO(gibbed): verify behavior under Linux
|
||||||
|
auto ctp = std::chrono::time_point_cast<duration>(tp);
|
||||||
|
auto dp = time_point{ctp.time_since_epoch()};
|
||||||
|
dp -= system_clock_delta();
|
||||||
|
return dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The delta between std::chrono::system_clock (Jan 1 1970) and Xenon file
|
||||||
|
// time (Jan 1 1601), in seconds. In the spec std::chrono::system_clock's
|
||||||
|
// epoch is undefined, but C++20 cements it as Jan 1 1970.
|
||||||
|
static constexpr std::chrono::seconds system_clock_delta() {
|
||||||
|
auto filetime_epoch = date::year{1601} / date::month{1} / date::day{1};
|
||||||
|
auto system_clock_epoch = date::year{1970} / date::month{1} / date::day{1};
|
||||||
|
std::chrono::system_clock::time_point fp{
|
||||||
|
static_cast<date::sys_days>(filetime_epoch)};
|
||||||
|
std::chrono::system_clock::time_point sp{
|
||||||
|
static_cast<date::sys_days>(system_clock_epoch)};
|
||||||
|
return std::chrono::floor<std::chrono::seconds>(fp.time_since_epoch() -
|
||||||
|
sp.time_since_epoch());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
#endif // XENIA_KERNEL_XCLOCK_H_
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 97246a638a6d8f0269f4555c5e31106a86e3fd94
|
Loading…
Reference in New Issue