/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuSleep.cpp Date: 2021-6-12 Author: Reece ***/ #include #include "AuSleep.hpp" #include "AuWaitFor.hpp" #if defined(AURORA_IS_POSIX_DERIVED) #include #endif #if defined(AURORA_IS_MODERNNT_DERIVED) #include #include #endif namespace Aurora::Threading { AUKN_SYM void Sleep(AuUInt64 qwTimeout) { #if defined(AURORA_IS_MODERNNT_DERIVED) ::Sleep(qwTimeout); #else SleepNs(AuMSToNS(qwTimeout)); #endif } AUKN_SYM void SleepNs(AuUInt64 qwTimeout) { #if defined(AURORA_IS_LINUX_DERIVED) || defined(AURORA_IS_BSD_DERIVED) auto qwEndTime = AuTime::SteadyClockNS() + qwTimeout; if (auto uSleepMnSec = qwTimeout / 1000) { if ((usleep(uSleepMnSec) == -1) && (errno == EINTR)) { AuUInt64 qwNow; while ((qwNow = AuTime::SteadyClockNS()) < qwEndTime) { if (auto uSleepMnSec = (qwEndTime - qwNow) / 1000) { usleep(uSleepMnSec); } else { break; } } } } #else #if defined(AURORA_IS_MODERNNT_DERIVED) if (pNtDelayExecution) { auto uEndTimeSteadyNS = AuTime::SteadyClockNS() + qwTimeout; auto uEndTimeSteadyNS2 = uEndTimeSteadyNS; #if defined(_AURORA_WANT_STRICT_NT_WAKEUP_TIME_NO_WALL_CLOCK_SHIFT_ALLOWED) auto uEndTimeWall = AuTime::CurrentClockNS() + qwTimeout; auto uTargetTimeNt = AuTime::ConvertTimestampNs(uEndTimeWall); Win32DropSchedulerResolution(); #else if (!AuSwInfo::IsWindows8Point1OrGreater()) { if (qwTimeout < 500000) { uEndTimeSteadyNS -= 10'000ull; (void)YieldPollNs(true, uEndTimeSteadyNS, [=]() { return false; }); return; } if (qwTimeout > AuMSToNS(60)) { uEndTimeSteadyNS -= 20'000'000ull; } else if (qwTimeout > AuMSToNS(40)) { uEndTimeSteadyNS -= 10'000'000ull; } else if (qwTimeout > AuMSToNS(10)) { uEndTimeSteadyNS -= 4'000'000ull; } else if (qwTimeout < AuMSToNS(1'300)) { uEndTimeSteadyNS -= 500'000ull; } Win32DropSchedulerResolution(); } else { if (qwTimeout < AuMSToNS(1)) { uEndTimeSteadyNS -= 250'000ull; } } #endif AuUInt64 uNowNS {}; while ((uNowNS = AuTime::SteadyClockNS()) < uEndTimeSteadyNS2) { LARGE_INTEGER word; #if defined(_AURORA_WANT_STRICT_NT_WAKEUP_TIME_NO_WALL_CLOCK_SHIFT_ALLOWED) word.QuadPart = uTargetTimeNt; #else if (AuThreadPrimitives::ThrdCfg::gPlatformIsSMPProcessorOptimized) { if (uEndTimeSteadyNS2 - uNowNS <= 230000ull) { auto uNow = AuAtomicAdd(&AuThreadPrimitives::gSpinAdaptiveCurrentCount, 1u); if (!AuThreadPrimitives::gSpinAdaptiveThreshold || uNow <= AuThreadPrimitives::gSpinAdaptiveThreshold) { #if (defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86)) if (AuThreadPrimitives::ThrdCfg::gIsIntelAlderLakeOrGreater) { _tpause(0, __rdtsc() + 10000); } else #endif { #if 0 for (AU_ITERATE_N(i, 32)) { AuThreadPrimitives::SMPPause(); } #else // shit compiler wont unwrap AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); // 32 or 16? AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); #endif } AuAtomicSub(&AuThreadPrimitives::gSpinAdaptiveCurrentCount, 1u); continue; } else { AuAtomicSub(&AuThreadPrimitives::gSpinAdaptiveCurrentCount, 1u); } } } AuSInt sDelta1 = uEndTimeSteadyNS - uNowNS; word.QuadPart = 0; if (sDelta1 > 0) { word.QuadPart = -(sDelta1 / 100ull); } if (!word.QuadPart) { if (AuThreadPrimitives::ThrdCfg::gPlatformIsSMPProcessorOptimized) { auto uNow = AuAtomicAdd(&AuThreadPrimitives::gSpinAdaptiveCurrentCount, 1u); if (!AuThreadPrimitives::gSpinAdaptiveThreshold || uNow <= AuThreadPrimitives::gSpinAdaptiveThreshold) { #if (defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86)) if (AuThreadPrimitives::ThrdCfg::gIsIntelAlderLakeOrGreater) { _tpause(0, __rdtsc() + 1000); } else #endif { #if 0 for (AU_ITERATE_N(i, 32)) { AuThreadPrimitives::SMPPause(); } #else // shit compiler wont unwrap AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); // 32 or 16? AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); AuThreadPrimitives::SMPPause(); #endif } AuAtomicSub(&AuThreadPrimitives::gSpinAdaptiveCurrentCount, 1u); continue; } else { AuAtomicSub(&AuThreadPrimitives::gSpinAdaptiveCurrentCount, 1u); break; } } else { if (!uEndTimeSteadyNS) { ContextYield(); } else { break; } } } #endif pNtDelayExecution(FALSE, &word); } return; } #endif auto status = YieldPollNs(true, qwTimeout + Time::SteadyClockNS(), [=]() { return false; }); #endif } void InitSleep() { // ... } }