AnyPS5/core/libs/prx/libkernel/Time/Time.cpp

333 lines
9.4 KiB
C++

#include "prx/libkernel/Time/include/Time.hpp"
#include "prx/libc/include/General.hpp"
#include <cerrno>
#include <cstdint>
#include <stdexcept>
#include <string>
#ifdef _WIN32
#include <windows.h>
#else
#include <time.h>
#include <sys/time.h>
#endif
static std::uint64_t GetMonotonicNanos() {
#ifdef _WIN32
static const std::uint64_t freq = [] {
LARGE_INTEGER f{};
QueryPerformanceFrequency(&f);
return static_cast<std::uint64_t>(f.QuadPart);
}();
LARGE_INTEGER counter{};
QueryPerformanceCounter(&counter);
return static_cast<std::uint64_t>(counter.QuadPart) * 1000000000ULL / freq;
#else
struct timespec ts{};
clock_gettime(CLOCK_MONOTONIC, &ts);
return static_cast<std::uint64_t>(ts.tv_sec) * 1000000000ULL +
static_cast<std::uint64_t>(ts.tv_nsec);
#endif
}
static std::uint64_t GetStartNanos() {
static const std::uint64_t start = GetMonotonicNanos();
return start;
}
static void SleepNanos(std::uint64_t nanos) {
if (nanos == 0) {
return;
}
#ifdef _WIN32
const DWORD millis = static_cast<DWORD>(nanos / 1000000ULL);
if (millis > 0) {
Sleep(millis);
}
#else
struct timespec req{};
req.tv_sec = static_cast<time_t>(nanos / 1000000000ULL);
req.tv_nsec = static_cast<long>(nanos % 1000000000ULL);
while (nanosleep(&req, &req) == -1 && errno == EINTR) {}
#endif
}
extern "C" {
std::uint64_t APS5_VABI sceKernelGetProcessTime() {
return (GetMonotonicNanos() - GetStartNanos()) / 1000ULL;
}
std::uint64_t APS5_VABI sceKernelGetProcessTimeCounter() {
return GetMonotonicNanos() - GetStartNanos();
}
std::uint64_t APS5_VABI sceKernelGetProcessTimeCounterFrequency() {
return 1000000000ULL;
}
int APS5_VABI sceKernelUsleep_nid_postfix(KernelUseconds microseconds) {
SleepNanos(static_cast<std::uint64_t>(microseconds) * 1000ULL);
return 0;
}
int APS5_VABI sceKernelNanosleep(const KernelTimespec* rqtp, KernelTimespec* rmtp) {
if (rqtp == nullptr) {
return -1;
}
if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= 1000000000LL) {
return -1;
}
SleepNanos(static_cast<std::uint64_t>(rqtp->tv_sec) * 1000000000ULL +
static_cast<std::uint64_t>(rqtp->tv_nsec));
if (rmtp != nullptr) {
rmtp->tv_sec = 0;
rmtp->tv_nsec = 0;
}
return 0;
}
int APS5_VABI nanosleep_nid_postfix(const KernelTimespec* rqtp, KernelTimespec* rmtp) {
return sceKernelNanosleep(rqtp, rmtp);
}
int APS5_VABI _nanosleep_nid_postfix(const KernelTimespec* rqtp, KernelTimespec* rmtp) {
return sceKernelNanosleep(rqtp, rmtp);
}
int APS5_VABI clock_gettime_nid_postfix(int clockId, KernelTimespec* tp) {
if (tp == nullptr) {
APS5_INVALID_ARG_EX;
}
#ifdef _WIN32
if (clockId == 0 || clockId == 9) {
FILETIME ft{};
GetSystemTimePreciseAsFileTime(&ft);
std::uint64_t t = (static_cast<std::uint64_t>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
t -= 116444736000000000ULL;
t *= 100ULL;
tp->tv_sec = static_cast<std::int64_t>(t / 1000000000ULL);
tp->tv_nsec = static_cast<std::int64_t>(t % 1000000000ULL);
return 0;
}
if (clockId == 10 || clockId == 13) {
FILETIME ft{};
GetSystemTimeAsFileTime(&ft);
std::uint64_t t = (static_cast<std::uint64_t>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
t -= 116444736000000000ULL;
t *= 100ULL;
tp->tv_sec = static_cast<std::int64_t>(t / 1000000000ULL);
tp->tv_nsec = static_cast<std::int64_t>(t % 1000000000ULL);
return 0;
}
if (clockId == 4 || clockId == 1 || clockId == 5 || clockId == 7 || clockId == 8 || clockId == 11 || clockId == 12) {
std::uint64_t nanos = GetMonotonicNanos();
tp->tv_sec = static_cast<std::int64_t>(nanos / 1000000000ULL);
tp->tv_nsec = static_cast<std::int64_t>(nanos % 1000000000ULL);
return 0;
}
throw std::runtime_error(std::string(__func__) + ": unsupported clock_id " + std::to_string(clockId));
#else
clockid_t nativeId;
switch (clockId) {
case 0:
case 9:
nativeId = CLOCK_REALTIME;
break;
case 10:
case 13:
#ifdef CLOCK_REALTIME_COARSE
nativeId = CLOCK_REALTIME_COARSE;
#else
nativeId = CLOCK_REALTIME;
#endif
break;
case 4:
case 7:
case 11:
nativeId = CLOCK_MONOTONIC;
break;
case 5:
case 8:
case 12:
nativeId = CLOCK_MONOTONIC;
break;
case 14:
nativeId = CLOCK_THREAD_CPUTIME_ID;
break;
case 15:
nativeId = CLOCK_PROCESS_CPUTIME_ID;
break;
default:
throw std::runtime_error(std::string(__func__) + ": unsupported clock_id " + std::to_string(clockId));
}
struct timespec ts{};
if (clock_gettime(nativeId, &ts) != 0) {
return -1;
}
tp->tv_sec = static_cast<std::int64_t>(ts.tv_sec);
tp->tv_nsec = static_cast<std::int64_t>(ts.tv_nsec);
return 0;
#endif
}
int APS5_VABI gettimeofday_nid_postfix(KernelTimeval* tv, KernelTimezone* tz) {
if (tv == nullptr) {
APS5_INVALID_ARG_EX;
}
#ifdef _WIN32
FILETIME ft{};
GetSystemTimePreciseAsFileTime(&ft);
std::uint64_t t = (static_cast<std::uint64_t>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
t -= 116444736000000000ULL;
tv->tv_sec = static_cast<std::int64_t>(t / 10000000ULL);
tv->tv_usec = static_cast<std::int64_t>((t % 10000000ULL) / 10ULL);
#else
struct timeval native{};
if (gettimeofday(&native, nullptr) != 0) {
return -1;
}
tv->tv_sec = static_cast<std::int64_t>(native.tv_sec);
tv->tv_usec = static_cast<std::int64_t>(native.tv_usec);
#endif
if (tz != nullptr) {
tz->tz_minuteswest = 0;
tz->tz_dsttime = 0;
}
return 0;
}
int APS5_VABI clock_getres_nid_postfix(int clockId, KernelTimespec* res) {
if (res == nullptr) {
APS5_INVALID_ARG_EX;
}
#ifdef _WIN32
if (clockId == 0 || clockId == 9) {
res->tv_sec = 0;
res->tv_nsec = 100LL;
return 0;
}
if (clockId == 4 || clockId == 1 || clockId == 5 || clockId == 7 || clockId == 8 || clockId == 10 || clockId == 11 || clockId == 12 || clockId == 13) {
static const std::uint64_t freq = [] {
LARGE_INTEGER f{};
QueryPerformanceFrequency(&f);
return static_cast<std::uint64_t>(f.QuadPart);
}();
std::uint64_t nsPerTick = (1000000000ULL + freq - 1ULL) / freq;
res->tv_sec = 0;
res->tv_nsec = static_cast<std::int64_t>(nsPerTick);
return 0;
}
throw std::runtime_error(std::string(__func__) + ": unsupported clock_id " + std::to_string(clockId));
#else
clockid_t nativeId;
switch (clockId) {
case 0:
case 9:
nativeId = CLOCK_REALTIME;
break;
case 10:
case 13:
#ifdef CLOCK_REALTIME_COARSE
nativeId = CLOCK_REALTIME_COARSE;
#else
nativeId = CLOCK_REALTIME;
#endif
break;
case 4:
case 7:
case 11:
nativeId = CLOCK_MONOTONIC;
break;
case 5:
case 8:
case 12:
nativeId = CLOCK_MONOTONIC;
break;
case 14:
nativeId = CLOCK_THREAD_CPUTIME_ID;
break;
case 15:
nativeId = CLOCK_PROCESS_CPUTIME_ID;
break;
default:
throw std::runtime_error(std::string(__func__) + ": unsupported clock_id " + std::to_string(clockId));
}
struct timespec ts{};
if (clock_getres(nativeId, &ts) != 0) {
return -1;
}
res->tv_sec = static_cast<std::int64_t>(ts.tv_sec);
res->tv_nsec = static_cast<std::int64_t>(ts.tv_nsec);
return 0;
#endif
}
// ---------------------------------------------------------------------------
// Moved as-is (not yet implemented) from the monolithic libkernel/Export.cpp.
// ---------------------------------------------------------------------------
int APS5_VABI sceKernelClockGetres(KernelClockid clock_id, KernelTimespec* tp) {
(void)clock_id;
(void)tp;
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceKernelClockGettime(KernelClockid clock_id, KernelTimespec* tp) {
(void)clock_id;
(void)tp;
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceKernelConvertLocaltimeToUtc(int64_t local_time, int64_t reserved, int64_t* utc_time, KernelTimezone* timezone, int32_t* dst_seconds) {
(void)local_time;
(void)reserved;
(void)utc_time;
(void)timezone;
(void)dst_seconds;
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceKernelConvertUtcToLocaltime(int64_t utc_time, int64_t* local_time, KernelTimesec* st, uint64_t* dst_sec) {
(void)utc_time;
(void)local_time;
(void)st;
(void)dst_sec;
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceKernelGettimeofday(KernelTimeval* tp) {
(void)tp;
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceKernelGettimezone(KernelTimezone* tz) {
(void)tz;
NotImplemented_nid_no_patch(__func__);
return 0;
}
uint64_t APS5_VABI sceKernelReadTsc(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
uint64_t APS5_VABI sceKernelGetTscFrequency(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
unsigned int APS5_VABI sceKernelSleep(unsigned int seconds) {
(void)seconds;
NotImplemented_nid_no_patch(__func__);
return 0;
}
}