#include "prx/libkernel/Time/include/Time.hpp" #include "prx/libc/include/General.hpp" #include #include #include #include #ifdef _WIN32 #include #else #include #include #endif static std::uint64_t GetMonotonicNanos() { #ifdef _WIN32 static const std::uint64_t freq = [] { LARGE_INTEGER f{}; QueryPerformanceFrequency(&f); return static_cast(f.QuadPart); }(); LARGE_INTEGER counter{}; QueryPerformanceCounter(&counter); return static_cast(counter.QuadPart) * 1000000000ULL / freq; #else struct timespec ts{}; clock_gettime(CLOCK_MONOTONIC, &ts); return static_cast(ts.tv_sec) * 1000000000ULL + static_cast(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(nanos / 1000000ULL); if (millis > 0) { Sleep(millis); } #else struct timespec req{}; req.tv_sec = static_cast(nanos / 1000000000ULL); req.tv_nsec = static_cast(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(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(rqtp->tv_sec) * 1000000000ULL + static_cast(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(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; t -= 116444736000000000ULL; t *= 100ULL; tp->tv_sec = static_cast(t / 1000000000ULL); tp->tv_nsec = static_cast(t % 1000000000ULL); return 0; } if (clockId == 10 || clockId == 13) { FILETIME ft{}; GetSystemTimeAsFileTime(&ft); std::uint64_t t = (static_cast(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; t -= 116444736000000000ULL; t *= 100ULL; tp->tv_sec = static_cast(t / 1000000000ULL); tp->tv_nsec = static_cast(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(nanos / 1000000000ULL); tp->tv_nsec = static_cast(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(ts.tv_sec); tp->tv_nsec = static_cast(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(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; t -= 116444736000000000ULL; tv->tv_sec = static_cast(t / 10000000ULL); tv->tv_usec = static_cast((t % 10000000ULL) / 10ULL); #else struct timeval native{}; if (gettimeofday(&native, nullptr) != 0) { return -1; } tv->tv_sec = static_cast(native.tv_sec); tv->tv_usec = static_cast(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(f.QuadPart); }(); std::uint64_t nsPerTick = (1000000000ULL + freq - 1ULL) / freq; res->tv_sec = 0; res->tv_nsec = static_cast(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(ts.tv_sec); res->tv_nsec = static_cast(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; } }