From e5e36bd887471e9ba2b9e902457301f874355652 Mon Sep 17 00:00:00 2001 From: Reece Date: Mon, 24 Jan 2022 18:37:06 +0000 Subject: [PATCH] Large Commit [*] Fix deadlock in the async subsystem (NoLockShutdown vs Shutdown in exception handler) [+] Added ProccessMap NT variant [+] Added ToolHelp image profiling [*] Improved exception awareness [*] Delegated SpawnThread to isolated TU, ready for reuse for RunAs and XNU Open - now with horrible evil alloc that could fail [+] Added header for future api 'UtilRun' [*] Improve NT core detection [*] Changed small affinity bitmap to AuUInt64 instead of AuUInt32 [+] Added data structure to hold cpuids/affinity masks [+] Implemented logger sinks [+] Implemented logger glue logic [*] Began migrating older loggers to sink-based default devices [*] Minor refactors [*] Improved internal exception discarding, not yet nothrow capable [*] Minor create directory fix --- Include/Aurora/Async/WorkPairImpl.hpp | 4 +- Include/Aurora/Console/Console.hpp | 1 + Include/Aurora/Console/Logging/IBasicSink.hpp | 4 +- Include/Aurora/Console/Logging/Sinks.hpp | 3 +- Include/Aurora/Debug/Debug.hpp | 3 + Include/Aurora/Debug/EFailureCategory.hpp | 1 + Include/Aurora/Debug/StackTrace.hpp | 1 + Include/Aurora/Debug/SysErrors.hpp | 3 + Include/Aurora/HWInfo/CpuBitId.hpp | 48 +++ Include/Aurora/HWInfo/CpuBitId.inl | 193 +++++++++++ Include/Aurora/HWInfo/CpuId.hpp | 83 +++++ Include/Aurora/HWInfo/CpuInfo.hpp | 84 +---- Include/Aurora/Locale/Locale.hpp | 1 + Include/Aurora/Locale/LocaleStrings.hpp | 19 ++ Include/Aurora/Process/ProcessMap.hpp | 36 ++- Include/Aurora/Processes/Processes.hpp | 1 + Include/Aurora/Processes/UtilRun.hpp | 32 ++ Include/Aurora/Runtime.hpp | 9 +- .../Aurora/SWInfo/SWInfo.hpp | 0 .../Threading/Threads/IAuroraThread.hpp | 8 +- Include/Aurora/Time/Clock.hpp | 50 +-- Include/Aurora/Time/ETimezoneShift.hpp | 17 + Include/Aurora/Time/TM.hpp | 52 +++ Include/Aurora/Time/Time.hpp | 108 +------ Source/Async/Schedular.cpp | 6 +- Source/Async/ThreadPool.cpp | 2 +- Source/Console/Commands/Commands.cpp | 7 +- Source/Console/Console.cpp | 23 +- Source/Console/Console.hpp | 1 - Source/Console/ConsoleFIO/ConsoleFIO.cpp | 68 ++-- Source/Console/ConsoleFIO/FileSink.cpp | 88 +++++ Source/Console/ConsoleFIO/FileSink.hpp | 31 ++ Source/Console/ConsoleMessage.cpp | 49 ++- Source/Console/ConsoleStd/ConsoleStd.cpp | 129 +++++--- Source/Console/ConsoleStd/ConsoleStd.hpp | 4 + .../ConsoleWxWidgets/ConsoleWxWidgets.cpp | 2 +- Source/Console/Flusher.cpp | 29 +- Source/Console/Flusher.hpp | 2 + Source/Console/Logging/Logger.cpp | 235 ++++++++++++++ Source/Console/Logging/Logger.hpp | 31 ++ Source/Console/Logging/Sinks.cpp | 54 ++++ Source/Console/Logging/Sinks.hpp | 6 + Source/Debug/Debug.cpp | 122 +++---- Source/Debug/ExceptionWatcher.Win32.cpp | 42 ++- Source/Entrypoint.cpp | 11 +- Source/HWInfo/CpuInfo.cpp | 205 ++++++++++-- Source/IO/FS/Async.NT.cpp | 11 +- Source/IO/FS/FS.Generic.cpp | 4 +- Source/IO/FS/FS.NT.cpp | 81 ++++- Source/IO/FS/FS.hpp | 61 ++-- Source/IO/FS/FileStream.Generic.cpp | 2 +- Source/IO/FS/FileStream.NT.cpp | 74 +++-- Source/IO/FS/Resources.cpp | 2 +- Source/Locale/Encoding/EncoderIConv.cpp | 11 + Source/Locale/Encoding/Encoding.cpp | 2 +- Source/Locale/Locale.cpp | 104 +++--- Source/Locale/LocaleStrings.cpp | 183 +++++++++++ Source/Locale/LocaleStrings.hpp | 8 + Source/Loop/LSMutex.NT.cpp | 7 +- Source/Loop/LSSemaphore.NT.cpp | 7 +- Source/Loop/Loop.NT.cpp | 57 ++-- Source/Loop/WaitSingle.NT.cpp | 4 +- Source/Memory/Heap.cpp | 4 +- Source/Parse/Base32.cpp | 4 +- Source/Parse/Base64.cpp | 4 +- Source/Parse/Parser.cpp | 12 +- Source/Process/Paths.cpp | 54 +++- Source/Process/Process.cpp | 34 +- Source/Process/Process.hpp | 3 +- Source/Process/ProcessMap.NT.cpp | 306 ++++++++++++++++++ Source/Process/ProcessMap.NT.hpp | 25 ++ Source/Process/ProcessMap.Win32.cpp | 56 ++-- Source/Process/ProcessMap.Win32.hpp | 2 + Source/Process/ProcessMap.cpp | 225 +++++++++++++ Source/Process/ProcessMap.hpp | 18 ++ Source/Processes/Open.Win32.cpp | 12 +- Source/Processes/UtilRun.cpp | 14 + Source/Processes/UtilRun.hpp | 12 + Source/Registry/Registry.cpp | 7 +- Source/Threading/Threads/OSThread.cpp | 127 ++------ Source/Threading/Threads/OSThread.hpp | 10 +- Source/Threading/Threads/SpawnThread.NT.cpp | 93 ++++++ Source/Threading/Threads/SpawnThread.NT.hpp | 13 + Source/Threading/Threads/SpawnThread.Unix.cpp | 76 +++++ .../Threads/SpawnThread.Unix.hpp} | 0 Source/Threading/Threads/SpawnThread.hpp | 20 ++ Source/Time/Clock.cpp | 12 +- 87 files changed, 2890 insertions(+), 779 deletions(-) create mode 100644 Include/Aurora/HWInfo/CpuBitId.hpp create mode 100644 Include/Aurora/HWInfo/CpuBitId.inl create mode 100644 Include/Aurora/HWInfo/CpuId.hpp create mode 100644 Include/Aurora/Locale/LocaleStrings.hpp create mode 100644 Include/Aurora/Processes/UtilRun.hpp rename Source/Time/TimeLocale.cpp => Include/Aurora/SWInfo/SWInfo.hpp (100%) create mode 100644 Include/Aurora/Time/ETimezoneShift.hpp create mode 100644 Include/Aurora/Time/TM.hpp create mode 100644 Source/Console/ConsoleFIO/FileSink.cpp create mode 100644 Source/Console/ConsoleFIO/FileSink.hpp create mode 100644 Source/Locale/LocaleStrings.cpp create mode 100644 Source/Locale/LocaleStrings.hpp create mode 100644 Source/Process/ProcessMap.NT.cpp create mode 100644 Source/Process/ProcessMap.NT.hpp create mode 100644 Source/Process/ProcessMap.cpp create mode 100644 Source/Process/ProcessMap.hpp create mode 100644 Source/Processes/UtilRun.cpp create mode 100644 Source/Processes/UtilRun.hpp create mode 100644 Source/Threading/Threads/SpawnThread.NT.cpp create mode 100644 Source/Threading/Threads/SpawnThread.NT.hpp create mode 100644 Source/Threading/Threads/SpawnThread.Unix.cpp rename Source/{Time/TimeLocale.hpp => Threading/Threads/SpawnThread.Unix.hpp} (100%) create mode 100644 Source/Threading/Threads/SpawnThread.hpp diff --git a/Include/Aurora/Async/WorkPairImpl.hpp b/Include/Aurora/Async/WorkPairImpl.hpp index 9800f3dc..f47ab5c9 100644 --- a/Include/Aurora/Async/WorkPairImpl.hpp +++ b/Include/Aurora/Async/WorkPairImpl.hpp @@ -115,7 +115,7 @@ namespace Aurora::Async catch (...) { Debug::PrintError(); - Shutdown(); + ShutdownNoLock(); return; } @@ -172,7 +172,7 @@ namespace Aurora::Async catch (...) { Debug::PrintError(); - Shutdown(); + ShutdownNoLock(); } } diff --git a/Include/Aurora/Console/Console.hpp b/Include/Aurora/Console/Console.hpp index b0af165d..de4b4def 100644 --- a/Include/Aurora/Console/Console.hpp +++ b/Include/Aurora/Console/Console.hpp @@ -20,6 +20,7 @@ namespace Aurora::Console /// Writes a log message to the console subscribers and telemetry outputs AUKN_SYM void WriteLine(AuUInt8 level, const ConsoleMessage &msg); AUKN_SYM void SetGlobalLogger(const AuSPtr &defaultGlobalLogger); + AUKN_SYM AuSPtr GetDefaultLogInterface(); /// Consider using the following function for asynchronous utf-8 processed line based input - /// Hooks::SetCallbackAndDisableCmdProcessing(...) diff --git a/Include/Aurora/Console/Logging/IBasicSink.hpp b/Include/Aurora/Console/Logging/IBasicSink.hpp index 197d620e..86e59f60 100644 --- a/Include/Aurora/Console/Logging/IBasicSink.hpp +++ b/Include/Aurora/Console/Logging/IBasicSink.hpp @@ -10,8 +10,8 @@ namespace Aurora::Console::Logging { AUKN_INTERFACE(IBasicSink, - AUI_METHOD(void, OnMessageBlocking, (const ConsoleMessage &, msg)), - AUI_METHOD(void, OnMessageNonblocking, (const ConsoleMessage &, msg)), + AUI_METHOD(void, OnMessageBlocking, (AuUInt8, level, const ConsoleMessage &, msg)), + AUI_METHOD(void, OnMessageNonblocking, (AuUInt8, level, const ConsoleMessage &, msg)), AUI_METHOD(void, OnFlush, ()) ) } \ No newline at end of file diff --git a/Include/Aurora/Console/Logging/Sinks.hpp b/Include/Aurora/Console/Logging/Sinks.hpp index 1418f553..845c0510 100644 --- a/Include/Aurora/Console/Logging/Sinks.hpp +++ b/Include/Aurora/Console/Logging/Sinks.hpp @@ -14,7 +14,8 @@ namespace Aurora namespace Aurora::Console::Logging { - AUKN_SHARED_API(NewGlobalPipeSink, IBasicSink); + AUKN_SHARED_API(NewStdSink, IBasicSink); + AUKN_SHARED_API(NewOSEventDirectorySink, IBasicSink); AUKN_SHARED_API(NewFileSink, IBasicSink, const AuString &path, bool binary = false); AUKN_SHARED_API(NewIPCSink, IBasicSink, const SocketConsole &console); AUKN_SHARED_API(NewRingLogger, IBasicSinkRB, AuUInt32 approxMaxBytes); diff --git a/Include/Aurora/Debug/Debug.hpp b/Include/Aurora/Debug/Debug.hpp index 3c529506..e034b225 100644 --- a/Include/Aurora/Debug/Debug.hpp +++ b/Include/Aurora/Debug/Debug.hpp @@ -47,6 +47,9 @@ namespace Aurora::Debug */ AUKN_SYM void PrintError(); + + + AUKN_SYM void CheckErrors(); /** Immediately terminates the process. diff --git a/Include/Aurora/Debug/EFailureCategory.hpp b/Include/Aurora/Debug/EFailureCategory.hpp index 96274576..720cffd2 100644 --- a/Include/Aurora/Debug/EFailureCategory.hpp +++ b/Include/Aurora/Debug/EFailureCategory.hpp @@ -33,6 +33,7 @@ namespace Aurora::Debug kFailureSyntaxError, kFailureDisconnected, kFailureUninitialized, + kFailureUnimplemented, kFailureUserBegin = 256 }; diff --git a/Include/Aurora/Debug/StackTrace.hpp b/Include/Aurora/Debug/StackTrace.hpp index 1fb896e2..d1e3d656 100644 --- a/Include/Aurora/Debug/StackTrace.hpp +++ b/Include/Aurora/Debug/StackTrace.hpp @@ -13,6 +13,7 @@ namespace Aurora::Debug { AuOptional label; AuUInt64 address; + AuUInt64 relAddress; AuOptional module; AuOptional> file; // file, line, offset diff --git a/Include/Aurora/Debug/SysErrors.hpp b/Include/Aurora/Debug/SysErrors.hpp index a01354d5..c1475702 100644 --- a/Include/Aurora/Debug/SysErrors.hpp +++ b/Include/Aurora/Debug/SysErrors.hpp @@ -108,6 +108,7 @@ namespace Aurora::Debug #define SysPushErrorSyntaxError(...) SysPushErrorError(kFailureSyntaxError, ## __VA_ARGS__) #define SysPushErrorDisconnected(...) SysPushErrorError(kFailureDisconnected, ## __VA_ARGS__) #define SysPushErrorUninitialized(...) SysPushErrorError(kFailureUninitialized, ## __VA_ARGS__) +#define SysPushErrorUnimplemented(...) SysPushErrorError(kFailureUnimplemented, ## __VA_ARGS__) #if defined(DEBUG) || defined(STAGING) @@ -142,6 +143,7 @@ namespace Aurora::Debug #define SysPushErrorSyntaxErrorDbg SysPushErrorSyntaxError #define SysPushErrorDisconnectedDbg SysPushErrorDisconnected #define SysPushErrorUninitializedDbg SysPushErrorUninitialized + #define SysPushErrorUnimplementedDbg SysPushErrorUnimplemented #else @@ -174,5 +176,6 @@ namespace Aurora::Debug #define SysPushErrorSyntaxErrorDbg(...) #define SysPushErrorDisconnectedDbg(...) #define SysPushErrorUninitializedDbg(...) + #define SysPushErrorUnimplementedDbg(...) #endif diff --git a/Include/Aurora/HWInfo/CpuBitId.hpp b/Include/Aurora/HWInfo/CpuBitId.hpp new file mode 100644 index 00000000..79957afa --- /dev/null +++ b/Include/Aurora/HWInfo/CpuBitId.hpp @@ -0,0 +1,48 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: CpuBitId.hpp + Date: 2022-1-24 + Author: Reece +***/ +#pragma once + +namespace Aurora::HWInfo +{ + struct CpuBitId + { + AuUInt64 lower {}; + AuUInt64 upper {}; + #if defined(_AU_MASSIVE_CPUID) + AuUInt64 upper2 {}; + AuUInt64 upper3 {}; + #endif + + inline CpuBitId(); + inline ~CpuBitId(); + inline CpuBitId(AuUInt8 id); + + inline bool HasValue() const; + + inline void Add(const CpuBitId &id); + + inline CpuBitId Not() const; + inline CpuBitId And(const CpuBitId &id) const; + inline CpuBitId Xor(const CpuBitId &id) const; + + inline bool CpuBitScanForward(AuUInt8 &index, AuUInt8 offset) const; + + inline bool TestCpuIdx(AuUInt8 idx) const; + inline void Clear(); + inline void SetBit(AuUInt8 idx); + inline void ClearBit(AuUInt8 idx); + inline bool TestBit(AuUInt8 idx) const; + + inline AuString ToString() const; + + inline CpuBitId &operator=(const CpuBitId &id); + inline operator bool() const; + }; +} + +#include "CpuBitId.inl" \ No newline at end of file diff --git a/Include/Aurora/HWInfo/CpuBitId.inl b/Include/Aurora/HWInfo/CpuBitId.inl new file mode 100644 index 00000000..25a29ecd --- /dev/null +++ b/Include/Aurora/HWInfo/CpuBitId.inl @@ -0,0 +1,193 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: CpuBitId.hpp + Date: 2022-1-24 + Author: Reece +***/ +#pragma once + +namespace Aurora::HWInfo +{ + CpuBitId::CpuBitId() + { + + } + + CpuBitId::~CpuBitId() + { + + } + + CpuBitId::CpuBitId(AuUInt8 id) + { + SetBit(id); + } + + AuString CpuBitId::ToString() const + { + #if defined(_AU_MASSIVE_CPUID) + return fmt::format("{1:#0{0}b} {2:#0{0}b} {3:#0{0}b} {4:#0{0}b}", sizeof(decltype(lower)) * 8, lower, upper, upper2, upper3); + #else + return fmt::format("{1:#0{0}b} {2:#0{0}b}", sizeof(decltype(lower)) * 8, lower, upper); + #endif + } + + bool CpuBitId::CpuBitScanForward(AuUInt8 &index, AuUInt8 offset) const + { + #if defined(_AU_MASSIVE_CPUID) + if (offset >= 192) + { + if (!AuBitScanForward(index, AuUInt64(upper3) >> AuUInt64(offset - 192))) return false; + index += 192; + } + else if (offset >= 128) + { + if (!AuBitScanForward(index, AuUInt64(upper2) >> AuUInt64(offset - 128))) return false; + index += 128; + } + else + #endif + if (offset >= 64) + { + if (!AuBitScanForward(index, AuUInt64(upper) >> AuUInt64(offset - 64))) return false; + index += 64; + } + else + { + if (!AuBitScanForward(index, AuUInt64(lower) >> AuUInt64(0))) return false; + } + + return true; + } + + bool CpuBitId::HasValue() const + { + return lower || upper + #if defined(_AU_MASSIVE_CPUID) + || upper2 + || upper3 + #endif + ; + } + + void CpuBitId::Add(const CpuBitId &id) + { + lower |= id.lower; + upper |= id.upper; + #if defined(_AU_MASSIVE_CPUID) + upper2 |= id.upper2; + upper3 |= id.upper3; + #endif + } + + CpuBitId CpuBitId::Not() const + { + CpuBitId ret = *this; + ret.lower = ~ret.lower; + ret.upper = ~ret.upper; + #if defined(_AU_MASSIVE_CPUID) + ret.upper2 = ~ret.upper2; + ret.upper3 = ~ret.upper3; + #endif + return ret; + } + + CpuBitId CpuBitId::And(const CpuBitId &id) const + { + CpuBitId ret = *this; + ret.lower &= id.lower; + ret.upper &= id.upper; + #if defined(_AU_MASSIVE_CPUID) + ret.upper2 &= id.upper2; + ret.upper3 &= id.upper3; + #endif + return ret; + } + + CpuBitId CpuBitId::Xor(const CpuBitId &id) const + { + CpuBitId ret = *this; + ret.lower ^= id.lower; + ret.upper ^= id.upper; + #if defined(_AU_MASSIVE_CPUID) + ret.upper2 ^= id.upper2; + ret.upper3 ^= id.upper3; + #endif + return ret; + } + + CpuBitId &CpuBitId::operator=(const CpuBitId &id) + { + lower = id.lower; + upper = id.upper; + #if defined(_AU_MASSIVE_CPUID) + upper2 = id.upper2; + upper3 = id.upper3; + #endif + return *this; + } + + CpuBitId::operator bool() const + { + return HasValue(); + } + + bool CpuBitId::TestCpuIdx(AuUInt8 idx) const + { + return TestBit(idx); + } + + void CpuBitId::Clear() + { + lower = {}; + upper = {}; + } + + void CpuBitId::SetBit(AuUInt8 idx) + { + #if defined(_AU_MASSIVE_CPUID) + if (idx >= 192) + upper3 |= AuUInt64(1) << AuUInt64(idx - 192); + else if (idx >= 128) + upper2 |= AuUInt64(1) << AuUInt64(idx - 128); + else + #endif + if (idx >= 64) + upper |= AuUInt64(1) << AuUInt64(idx - 64); + else + lower |= AuUInt64(1) << AuUInt64(idx); + } + + void CpuBitId::ClearBit(AuUInt8 idx) + { + #if defined(_AU_MASSIVE_CPUID) + if (idx >= 192) + upper3 &= ~(AuUInt64(1) << AuUInt64(idx - 192)); + else if (idx >= 128) + upper2 &= ~(AuUInt64(1) << AuUInt64(idx - 128)); + else + #endif + if (idx >= 64) + upper &= ~(AuUInt64(1) << AuUInt64(idx - 64)); + else + lower &= ~(AuUInt64(1) << AuUInt64(idx)); + } + + bool CpuBitId::TestBit(AuUInt8 idx) const + { + bool ret {}; + #if defined(_AU_MASSIVE_CPUID) + if (idx >= 192) + ret = upper3 & (AuUInt64(1) << AuUInt64(idx - 192)); + else if (idx >= 128) + ret = upper2 & (AuUInt64(1) << AuUInt64(idx - 128)); + else + #endif + if (idx >= 64) + ret = upper & (AuUInt64(1) << AuUInt64(idx - 64)); + else + ret = lower & (AuUInt64(1) << AuUInt64(idx)); + return ret; + } +} \ No newline at end of file diff --git a/Include/Aurora/HWInfo/CpuId.hpp b/Include/Aurora/HWInfo/CpuId.hpp new file mode 100644 index 00000000..0cb88e8b --- /dev/null +++ b/Include/Aurora/HWInfo/CpuId.hpp @@ -0,0 +1,83 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: CpuId.hpp + Date: 2022-1-24 + Author: Reece +***/ +#pragma once + +namespace Aurora::HWInfo +{ + struct AUKN_SYM CpuId + { + bool SSE3(); + bool PCLMULQDQ(); + bool MONITOR(); + bool SSSE3(); + bool FMA(); + bool CMPXCHG16B(); + bool SSE41(); + bool SSE42(); + bool MOVBE(); + bool POPCNT(); + bool AES(); + bool XSAVE(); + bool OSXSAVE(); + bool AVX(); + bool F16C(); + bool RDRAND(); + + bool MSR(); + bool CX8(); + bool SEP(); + bool CMOV(); + bool CLFSH(); + bool MMX(); + bool FXSR(); + bool SSE(); + bool SSE2(); + + bool FSGSBASE(); + bool BMI1(); + bool HLE(); + bool AVX2(); + bool BMI2(); + bool ERMS(); + bool INVPCID(); + bool RTM(); + bool AVX512F(); + bool RDSEED(); + bool ADX(); + bool AVX512PF(); + bool AVX512ER(); + bool AVX512CD(); + bool SHA(); + + bool PREFETCHWT1(); + + bool LAHF(); + bool LZCNT(); + bool ABM(); + bool SSE4a(); + bool XOP(); + bool TBM(); + + bool SYSCALL(); + bool MMXEXT(); + bool RDTSCP(); + bool _3DNOWEXT(); + bool _3DNOW(); + + AuString vendor; + AuString brand; + bool isIntel; + bool isAMD; + AuUInt32 f_1_ECX; + AuUInt32 f_1_EDX; + AuUInt32 f_7_EBX; + AuUInt32 f_7_ECX; + AuUInt32 f_81_ECX; + AuUInt32 f_81_EDX; + }; +} \ No newline at end of file diff --git a/Include/Aurora/HWInfo/CpuInfo.hpp b/Include/Aurora/HWInfo/CpuInfo.hpp index 187c80ad..0b2d268b 100644 --- a/Include/Aurora/HWInfo/CpuInfo.hpp +++ b/Include/Aurora/HWInfo/CpuInfo.hpp @@ -7,80 +7,11 @@ ***/ #pragma once +#include "CpuBitId.hpp" +#include "CpuId.hpp" + namespace Aurora::HWInfo { - struct AUKN_SYM CpuId - { - bool SSE3(); - bool PCLMULQDQ(); - bool MONITOR(); - bool SSSE3(); - bool FMA(); - bool CMPXCHG16B(); - bool SSE41(); - bool SSE42(); - bool MOVBE(); - bool POPCNT(); - bool AES(); - bool XSAVE(); - bool OSXSAVE(); - bool AVX(); - bool F16C(); - bool RDRAND(); - - bool MSR(); - bool CX8(); - bool SEP(); - bool CMOV(); - bool CLFSH(); - bool MMX(); - bool FXSR(); - bool SSE(); - bool SSE2(); - - bool FSGSBASE(); - bool BMI1(); - bool HLE(); - bool AVX2(); - bool BMI2(); - bool ERMS(); - bool INVPCID(); - bool RTM(); - bool AVX512F(); - bool RDSEED(); - bool ADX(); - bool AVX512PF(); - bool AVX512ER(); - bool AVX512CD(); - bool SHA(); - - bool PREFETCHWT1(); - - bool LAHF(); - bool LZCNT(); - bool ABM(); - bool SSE4a(); - bool XOP(); - bool TBM(); - - bool SYSCALL(); - bool MMXEXT(); - bool RDTSCP(); - bool _3DNOWEXT(); - bool _3DNOW(); - - AuString vendor; - AuString brand; - bool isIntel; - bool isAMD; - AuUInt32 f_1_ECX; - AuUInt32 f_1_EDX; - AuUInt32 f_7_EBX; - AuUInt32 f_7_ECX; - AuUInt32 f_81_ECX; - AuUInt32 f_81_EDX; - }; - struct CpuInfo { Aurora::Build::EArchitecture cpuArch; @@ -88,7 +19,14 @@ namespace Aurora::HWInfo AuUInt8 socket; AuUInt8 cores; AuUInt8 threads; - + + AuList threadTopology; + AuList serverTopology; + CpuBitId maskECores; + + bool maskMTContig; + bool maskMTHalf; + CpuId cpuId; }; diff --git a/Include/Aurora/Locale/Locale.hpp b/Include/Aurora/Locale/Locale.hpp index 4b894509..a014f547 100644 --- a/Include/Aurora/Locale/Locale.hpp +++ b/Include/Aurora/Locale/Locale.hpp @@ -9,6 +9,7 @@ #include "ECodePage.hpp" #include "Encoding/Encoding.hpp" +#include "LocaleStrings.hpp" namespace Aurora::Locale { diff --git a/Include/Aurora/Locale/LocaleStrings.hpp b/Include/Aurora/Locale/LocaleStrings.hpp new file mode 100644 index 00000000..d12534ac --- /dev/null +++ b/Include/Aurora/Locale/LocaleStrings.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +namespace Aurora::Locale +{ + AUKN_SYM AuString NumbericLocaleGetDecimal(); +# + AUKN_SYM AuString TimeLocaleGetMSChar(); + AUKN_SYM AuString TimeLocaleS(); + AUKN_SYM AuString TimeLocaleGetDayChar(); + + AUKN_SYM AuString TimeDateToString(const Time::tm &time); + AUKN_SYM AuString TimeDateToISO8601(const Time::tm &time, Time::ETimezoneShift shift = Time::ETimezoneShift::eUTC); + + AUKN_SYM AuString ConvertMSToTimescale(AuUInt32 ms); + AUKN_SYM AuString ConvertNSToTimescale(AuUInt64 ns); +} \ No newline at end of file diff --git a/Include/Aurora/Process/ProcessMap.hpp b/Include/Aurora/Process/ProcessMap.hpp index 86d30256..4df5f954 100644 --- a/Include/Aurora/Process/ProcessMap.hpp +++ b/Include/Aurora/Process/ProcessMap.hpp @@ -9,16 +9,44 @@ namespace Aurora::Process { + struct PublicModule; + + struct ModuleMeta + { + AuString moduleName; + AuString modulePath; + AuUInt moduleBase; + AuUInt origVa; + }; + + struct PageTable + { + bool NX; + bool writable; + bool readable; + bool acSanity; + }; + struct Segment { - AuUInt base; + AuUInt baseVa; + AuUInt origVa; + AuUInt fsOff; AuUInt size; - char perms[6]; - AuString module; + PageTable pt; + AuString name; + AuWPtr moduleMeta; }; + using Segments = AuList; + struct PublicModule + { + AuList segments; + AuSPtr moduleMeta; + }; + AUKN_SYM AuOptional GetSegment(AuUInt pointer); - AUKN_SYM Segments DumpExecutableRoot(); + AUKN_SYM PublicModule DumpExecutableRoot(); AUKN_SYM Segments DumpExecutableAll(); } \ No newline at end of file diff --git a/Include/Aurora/Processes/Processes.hpp b/Include/Aurora/Processes/Processes.hpp index 550ced6f..d5c3fc97 100644 --- a/Include/Aurora/Processes/Processes.hpp +++ b/Include/Aurora/Processes/Processes.hpp @@ -10,5 +10,6 @@ #include "ESpawnType.hpp" #include "IProcess.hpp" #include "Spawn.hpp" +#include "UtilRun.hpp" #include "Open.hpp" \ No newline at end of file diff --git a/Include/Aurora/Processes/UtilRun.hpp b/Include/Aurora/Processes/UtilRun.hpp new file mode 100644 index 00000000..65e3ddb3 --- /dev/null +++ b/Include/Aurora/Processes/UtilRun.hpp @@ -0,0 +1,32 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: UtilRun.hpp + Date: + Author: Reece +***/ +#pragma once + +namespace Aurora::Processes +{ + AUKN_INTERFACE(ICommandFinished, + AUI_METHOD(void, OnLines, (const AuList &, buffer)), + AUI_METHOD(void, OnBuffered, (const Memory::ByteBuffer &, buffer)) + ); + + struct CommandRun_s + { + AuString cmd; + AuList args; + Memory::ByteBuffer stdIn; + bool stdOutLongerThan64k {false}; // common constraint on linux and windows, at the very least. linux -> max pipe = 16k, windows -> 16k minimum guaranteed + bool stdOutIsText {true}; + bool runCallbackOnRandomThread {true}; + bool runCallbackOnWorkerPId {}; + Async::WorkerPId_t worker; + bool syncToResult {}; // default -> async + AuSPtr callback; + }; + + AUKN_SYM void RunCommand(const CommandRun_s &in); +} \ No newline at end of file diff --git a/Include/Aurora/Runtime.hpp b/Include/Aurora/Runtime.hpp index f0aa486a..79a07d16 100644 --- a/Include/Aurora/Runtime.hpp +++ b/Include/Aurora/Runtime.hpp @@ -61,16 +61,16 @@ #include "Hashing/Hashing.hpp" #include "HWInfo/HWInfo.hpp" #include "IO/IO.hpp" +#include "Time/Time.hpp" #include "Locale/Locale.hpp" #include "Parse/Parse.hpp" #include "Process/Process.hpp" -#include "Processes/Processes.hpp" #include "Registry/Registry.hpp" #include "RNG/RNG.hpp" #include "Telemetry/Telemetery.hpp" #include "Threading/Threading.hpp" #include "Async/Async.hpp" -#include "Time/Time.hpp" +#include "Processes/Processes.hpp" #include "Loop/Loop.hpp" #include "Memory/_ByteBuffer.hpp" @@ -109,8 +109,6 @@ using AuMemoryViewWrite = AuMemory::MemoryViewWrite; using AuMemoryViewStreamRead = AuMemory::MemoryViewStreamRead; using AuMemoryViewStreamWrite = AuMemory::MemoryViewStreamWrite; - - static bool AuIsThreadRunning() { return !AuThreads::GetThread()->Exiting(); @@ -195,6 +193,9 @@ namespace Aurora /// Use WxWidgets when possible bool enableWxWidgets {true}; + + /// Delegate stdout writes to loops -> recommended for servers + bool asyncWrite {false}; #if 1 /// FIO config diff --git a/Source/Time/TimeLocale.cpp b/Include/Aurora/SWInfo/SWInfo.hpp similarity index 100% rename from Source/Time/TimeLocale.cpp rename to Include/Aurora/SWInfo/SWInfo.hpp diff --git a/Include/Aurora/Threading/Threads/IAuroraThread.hpp b/Include/Aurora/Threading/Threads/IAuroraThread.hpp index 7f80237c..bc0d7c1a 100644 --- a/Include/Aurora/Threading/Threads/IAuroraThread.hpp +++ b/Include/Aurora/Threading/Threads/IAuroraThread.hpp @@ -24,10 +24,10 @@ namespace Aurora::Threading::Threads /// A common worker thread semantic: /// EndWorker() /// m_Worker->SendExitSignal(); // sets the exiting flag - /// DestroyThread(worker); // in the dtor, a watchdog is triggered over the shutdown of the thread + /// DestroyThread(worker); // in the dtor, a watchdog guards the shutdown of the thread, and syncs to termination /// /// WorkerMain() - /// while (!this->Exiting()) {} + /// while (AuIsThreadRunning()) {} /// /// It's similar to Java /// -> think while (Thread.currentThread().isAlive()) { doWork() } @@ -42,11 +42,11 @@ namespace Aurora::Threading::Threads virtual void SendExitSignal() = 0; virtual void SetPrio(EThreadPrio prio) = 0; - virtual void SetAffinity(AuUInt32 mask) = 0; + virtual void SetAffinity(AuUInt64 mask) = 0; virtual void SetName(const AuString &name) = 0; virtual EThreadPrio GetPrio() = 0; - virtual AuUInt32 GetMask() = 0; + virtual AuUInt64 GetMask() = 0; virtual AuString GetName() = 0; /// Registers a thread feature _not_ calling on init diff --git a/Include/Aurora/Time/Clock.hpp b/Include/Aurora/Time/Clock.hpp index a3c3b7e2..3a18fab6 100644 --- a/Include/Aurora/Time/Clock.hpp +++ b/Include/Aurora/Time/Clock.hpp @@ -7,49 +7,11 @@ ***/ #pragma once +#include "ETimezoneShift.hpp" +#include "TM.hpp" + namespace Aurora::Time { - struct tm - { - int tm_sec {}; - int tm_min {}; - int tm_hour {}; - int tm_mday {1}; - int tm_mon {}; - int tm_year {70}; - int tm_wday {}; - int tm_yday {}; - int tm_isdst {-1}; - - template - void CopyTo(Dest_t &out) const - { - out.tm_sec = tm_sec; - out.tm_min = tm_min; - out.tm_hour = tm_hour; - out.tm_mday = tm_mday; - out.tm_mon = tm_mon; - out.tm_year = tm_year; - out.tm_wday = tm_wday; - out.tm_yday = tm_yday; - out.tm_isdst = tm_isdst; - } - - template - void CopyFrom(const In_t &in) - { - tm_sec = in.tm_sec; - tm_min = in.tm_min; - tm_hour = in.tm_hour; - tm_mday = in.tm_mday; - tm_mon = in.tm_mon; - tm_year = in.tm_year; - tm_wday = in.tm_wday; - tm_yday = in.tm_yday; - tm_isdst = in.tm_isdst; - } - }; - /** Converts milliseconds from the Aurora epoch to a civil timestamp structure similar to or of std::tm @@ -65,6 +27,12 @@ namespace Aurora::Time */ AUKN_SYM AuInt64 FromCivilTime(const tm &time, bool UTC = true); + + /** + Normalizes a civil data structure with respect to UTC, given the two input parameters 'in' civil and 'shiftFrom' timezone hint + */ + AUKN_SYM tm NormalizeCivilTimezone(const tm &in, ETimezoneShift shiftFrom = ETimezoneShift::eUTC); + /** Retrieves system clock in jiffies */ diff --git a/Include/Aurora/Time/ETimezoneShift.hpp b/Include/Aurora/Time/ETimezoneShift.hpp new file mode 100644 index 00000000..b272edaf --- /dev/null +++ b/Include/Aurora/Time/ETimezoneShift.hpp @@ -0,0 +1,17 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: ETimezoneShift.hpp + Date: 2022-1-24 + Author: Reece +***/ +#pragma once + +namespace Aurora::Time +{ + enum ETimezoneShift + { + eUTC, + eLocalTime + }; +} \ No newline at end of file diff --git a/Include/Aurora/Time/TM.hpp b/Include/Aurora/Time/TM.hpp new file mode 100644 index 00000000..f7305745 --- /dev/null +++ b/Include/Aurora/Time/TM.hpp @@ -0,0 +1,52 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: ETimezoneShift.hpp + Date: 2022-1-24 + Author: Reece +***/ +#pragma once + +namespace Aurora::Time +{ + struct tm + { + int tm_sec {}; + int tm_min {}; + int tm_hour {}; + int tm_mday {1}; + int tm_mon {}; + int tm_year {70}; + int tm_wday {}; + int tm_yday {}; + int tm_isdst {-1}; + + template + void CopyTo(Dest_t &out) const + { + out.tm_sec = tm_sec; + out.tm_min = tm_min; + out.tm_hour = tm_hour; + out.tm_mday = tm_mday; + out.tm_mon = tm_mon; + out.tm_year = tm_year; + out.tm_wday = tm_wday; + out.tm_yday = tm_yday; + out.tm_isdst = tm_isdst; + } + + template + void CopyFrom(const In_t &in) + { + tm_sec = in.tm_sec; + tm_min = in.tm_min; + tm_hour = in.tm_hour; + tm_mday = in.tm_mday; + tm_mon = in.tm_mon; + tm_year = in.tm_year; + tm_wday = in.tm_wday; + tm_yday = in.tm_yday; + tm_isdst = in.tm_isdst; + } + }; +} \ No newline at end of file diff --git a/Include/Aurora/Time/Time.hpp b/Include/Aurora/Time/Time.hpp index 534500c2..d365d486 100644 --- a/Include/Aurora/Time/Time.hpp +++ b/Include/Aurora/Time/Time.hpp @@ -7,114 +7,20 @@ ***/ #pragma once +#include +#include + namespace Aurora::Time { - static auline AuString TimeLocaleGetDayChar() + static AuString ConvertMSToTimescale(AuUInt32 ms) { - return "d"; //for.now + return Locale::ConvertMSToTimescale(ms); } - static auline AuString TimeLocaleS() + static AuString ConvertNSToTimescale(AuUInt64 ns) { - return "s"; + return Locale::ConvertNSToTimescale(ns); } - - static auline AuString TimeLocaleGetMSChar() - { - return "ms"; //for.now - } - - static AuString &_TextPrepadZeroIfOne(AuString &in) - { - if (in.size() == 1) in.insert(in.begin(), '0'); - return in; - } - - static AuString _TextPrepadZeroIfOne(const AuString &in) - { - AuString ret = in; - if (ret.size() == 1) ret.insert(ret.begin(), '0'); - return ret; - } - - static AuString _TextPrepadZeroMS(const AuString &in) - { - AuString ret = in; - if (ret.size() == 1) ret.insert(0, "000", 3); - if (ret.size() == 2) ret.insert(0, "000", 2); - if (ret.size() == 3) ret.insert(0, "000", 1); - while (ret.size() > 1 && ret[ret.size() - 1] == '0') - ret.pop_back(); - return ret; - } - static AuString _TextPrepadZeroNS(const AuString &in) - { - AuString ret = in; - if (ret.size() == 1) ret.insert(0, "000000", 6); - if (ret.size() == 2) ret.insert(0, "000000", 5); - if (ret.size() == 3) ret.insert(0, "000000", 4); - if (ret.size() == 4) ret.insert(0, "000000", 3); - if (ret.size() == 5) ret.insert(0, "000000", 2); - if (ret.size() == 6) ret.insert(0, "000000", 1); - while (ret.size() > 1 && ret[ret.size() - 1] == '0') - ret.pop_back(); - return ret; - } - - static auline AuString ConvertMSToTimescale(AuUInt32 ms) - { - const auto msDiv1000 = ms / 1000; // seconds - const auto msDiv1000Mod60 = msDiv1000 % 60; // remaining seconds relative to next whole minute - const auto msDiv1000Div60 = msDiv1000 / 60; // total minutes - - if (ms < 1000) - { - return AuToString(ms) + TimeLocaleGetMSChar(); - } - else if (ms < (1000 * 60)) - { - auto s = msDiv1000; - auto remMs = ms % 1000; - return _TextPrepadZeroIfOne(AuToString(s)) + "." + _TextPrepadZeroMS(AuToString(remMs)) + TimeLocaleS(); - } - else if (ms < (1000 * 60 * 60)) - { - auto m = msDiv1000Div60; - auto remS = msDiv1000Mod60; - return _TextPrepadZeroIfOne(AuToString(m)) + ":" + _TextPrepadZeroIfOne(AuToString(remS)); - } - else if (ms < (1000 * 60 * 60 * 24)) - { - auto h = msDiv1000Div60 / 60; - auto remM = msDiv1000Div60; - auto remS = msDiv1000Mod60; - - return _TextPrepadZeroIfOne(AuToString(h)) + ":" + _TextPrepadZeroIfOne(AuToString(remM)) + ":" + _TextPrepadZeroIfOne(AuToString(remS)); - } - else - { - auto d = (msDiv1000Div60 / 60 / 24); - auto h = (msDiv1000Div60 / 60) - (d * 24); - auto remM = msDiv1000Div60; - auto remS = msDiv1000Mod60; - return AuToString(d) + TimeLocaleGetDayChar() + " " + _TextPrepadZeroIfOne(AuToString(h)) + ":" + _TextPrepadZeroIfOne(AuToString(remM)) + ":" + _TextPrepadZeroIfOne(AuToString(remS)); - } - } - - static auline AuString ConvertNSToTimescale(AuUInt64 ns) - { - if (ns < AuUInt64(1000000000)) - { - const auto ms = ns / 1000000; - const auto remNs = ns % 1000000; - return _TextPrepadZeroMS(AuToString(ms)) + "." + _TextPrepadZeroNS(AuToString(remNs)) + TimeLocaleGetMSChar(); - } - else - { - return ConvertMSToTimescale(ns / AuUInt64(1000000000)); - } - } - } #include "Clock.hpp" diff --git a/Source/Async/Schedular.cpp b/Source/Async/Schedular.cpp index 43270766..1d2b6ac2 100644 --- a/Source/Async/Schedular.cpp +++ b/Source/Async/Schedular.cpp @@ -83,8 +83,8 @@ namespace Aurora::Async { if (entry.pool->ToThreadPool()->InRunnerMode()) { - LogWarn("Dropped scheduled task! Expect a leaky counter!"); - LogWarn("Would you rather `Why u no exit?!` or `WHY DID U JUST CRASH REEEE` in production?"); + AuLogWarn("Dropped scheduled task! Expect a leaky counter!"); + AuLogWarn("Would you rather `Why u no exit?!` or `WHY DID U JUST CRASH REEEE` in production?"); } Debug::PrintError(); } @@ -103,7 +103,7 @@ namespace Aurora::Async } catch (...) { - LogWarn("Dropped SysRuntimePump"); + AuLogWarn("Dropped SysRuntimePump"); Debug::PrintError(); } } diff --git a/Source/Async/ThreadPool.cpp b/Source/Async/ThreadPool.cpp index c0a06850..a3422806 100644 --- a/Source/Async/ThreadPool.cpp +++ b/Source/Async/ThreadPool.cpp @@ -1002,7 +1002,7 @@ namespace Aurora::Async } catch (...) { - LogWarn("Couldn't clean up thread feature!"); + AuLogWarn("Couldn't clean up thread feature!"); Debug::PrintError(); } } diff --git a/Source/Console/Commands/Commands.cpp b/Source/Console/Commands/Commands.cpp index 8f0e0437..d455ea57 100644 --- a/Source/Console/Commands/Commands.cpp +++ b/Source/Console/Commands/Commands.cpp @@ -72,7 +72,7 @@ namespace Aurora::Console::Commands auto cmdItr = gCommands.find(tag); if (cmdItr == gCommands.end()) { - LogWarn("Command {} does not exist", tag); + AuLogWarn("Command {} does not exist", tag); return false; } @@ -84,7 +84,7 @@ namespace Aurora::Console::Commands if (!status) { - LogWarn("Couldn't parse command {}", string); + AuLogWarn("Couldn't parse command {}", string); return false; } @@ -192,8 +192,7 @@ namespace Aurora::Console::Commands AuMakeShared([&commands]() { DispatchCommandsFromThis(commands); - }), - true)->Dispatch()->BlockUntilComplete(); + }), true)->Dispatch()->BlockUntilComplete(); } gMutex->Unlock(); diff --git a/Source/Console/Console.cpp b/Source/Console/Console.cpp index e9ac668f..4c29615d 100644 --- a/Source/Console/Console.cpp +++ b/Source/Console/Console.cpp @@ -9,6 +9,7 @@ #include "Console.hpp" #include "Commands/Commands.hpp" #include "Hooks/Hooks.hpp" +#include "Logging/Logger.hpp" #include "ConsoleStd/ConsoleStd.hpp" #include "ConsoleWxWidgets/ConsoleWxWidgets.hpp" #include "ConsoleFIO/ConsoleFIO.hpp" @@ -22,7 +23,7 @@ namespace Aurora::Console static AuSPtr CreateDefaultLogger() { - return {}; + return Logging::NewLoggerShared(gDefaultSinks); } AUKN_SYM void WriteLine(AuUInt8 level, const ConsoleMessage &msg) @@ -56,6 +57,16 @@ namespace Aurora::Console gDefaultLogger = CreateDefaultLogger(); //gDefaultSinks.clear(); } + + AUKN_SYM void SetGlobalLogger(const AuSPtr &defaultGlobalLogger) + { + gUserLogger = defaultGlobalLogger; + } + + AUKN_SYM AuSPtr GetDefaultLogInterface() + { + return gDefaultLogger; + } AUKN_SYM AuUInt32 ReadStdIn(void *buffer, AuUInt32 length) { @@ -90,6 +101,7 @@ namespace Aurora::Console ConsoleFIO::Init(); InitFlusher(); FinailizeDefaultLogger(); + Logging::InitLoggers(); } void Pump() @@ -102,10 +114,15 @@ namespace Aurora::Console void Exit() { + gDefaultSinks.clear(); + gDefaultLogger.reset(); + gUserLogger.reset(); + DeinitFlusher(); - ConsoleStd::Exit(); - ConsoleWxWidgets::Exit(); + Logging::DeinitLoggers(); ConsoleFIO::Exit(); + ConsoleWxWidgets::Exit(); + ConsoleStd::Exit(); Hooks::Deinit(); } diff --git a/Source/Console/Console.hpp b/Source/Console/Console.hpp index eda363b0..0c2b862c 100644 --- a/Source/Console/Console.hpp +++ b/Source/Console/Console.hpp @@ -9,7 +9,6 @@ namespace Aurora::Console { - void AddDefaultLogger(const AuSPtr &logger); void Init(); diff --git a/Source/Console/ConsoleFIO/ConsoleFIO.cpp b/Source/Console/ConsoleFIO/ConsoleFIO.cpp index ba2d4013..56f7fb1f 100644 --- a/Source/Console/ConsoleFIO/ConsoleFIO.cpp +++ b/Source/Console/ConsoleFIO/ConsoleFIO.cpp @@ -7,12 +7,12 @@ ***/ #include #include "ConsoleFIO.hpp" +#include "FileSink.hpp" +#include "../Console.hpp" namespace Aurora::Console::ConsoleFIO { - static AuList gLogBuffer; - static AuThreadPrimitives::RWLockUnique_t gLogMutex; - static AuIOFS::OpenWriteUnique_t gFileHandle; + static IBasicSink * gFileSink; static const auto &gLogConfig = gRuntimeConfig.console.fio; @@ -21,7 +21,7 @@ namespace Aurora::Console::ConsoleFIO AuString path; AuString procName; - if ((gLogConfig.writeLogsToUserDir) || (!IO::FS::GetProfileDomain(path))) + if ((!gLogConfig.writeLogsToUserDir) || (!AuIOFS::GetProfileDomain(path))) { path = "."; } @@ -53,7 +53,7 @@ namespace Aurora::Console::ConsoleFIO { try { - if (IO::FS::Remove(path + "/" + files[i])) + if (AuIOFS::Remove(path + "/" + files[i])) { x++; } @@ -68,17 +68,17 @@ namespace Aurora::Console::ConsoleFIO static void CleanupOldLogs() { AuList files; - AuBST fileMeta; + AuBST fileMeta; AuUInt32 size {}; auto baseLogPath = GetLogDirectory(); - IO::FS::FilesInDirectory(baseLogPath, files); + AuIOFS::FilesInDirectory(baseLogPath, files); for (const auto &file : files) { - IO::FS::Stat stat; - IO::FS::StatFile(baseLogPath + "/" + file, stat); + AuIOFS::Stat stat; + AuIOFS::StatFile(baseLogPath + "/" + file, stat); fileMeta[file] = stat; size += stat.size; } @@ -94,20 +94,8 @@ namespace Aurora::Console::ConsoleFIO void Flush() { - /// It should be expected that the TLS teardown emergency flush to dispatch after deinit - if (!gLogMutex) - { - return; - } - - AU_LOCK_GUARD(gLogMutex->AsReadable()); - - if (gFileHandle) - { - gFileHandle->Write(Aurora::Memory::MemoryViewStreamRead(gLogBuffer)); - } - - gLogBuffer.clear(); + if (!gFileSink) return; + gFileSink->OnFlush(); } static bool OpenLogFile() @@ -121,8 +109,8 @@ namespace Aurora::Console::ConsoleFIO tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); - gFileHandle = IO::FS::OpenWriteUnique(path); - return static_cast(gFileHandle); + gFileSink = NewFileSinkNew(path); + return gFileSink; } void FIOCleanup() @@ -142,27 +130,8 @@ namespace Aurora::Console::ConsoleFIO { return; } - - gLogMutex = AuThreadPrimitives::RWLockUnique(); - if (!gLogMutex) - { - return; - } - - Console::Hooks::AddFunctionalHook([&](const Console::ConsoleMessage &string) -> void - { - AU_LOCK_GUARD(gLogMutex->AsWritable()); - auto str = string.ToSimplified(); - - gLogBuffer.reserve(gLogBuffer.size() + str.size() + 2); - - gLogBuffer.insert(gLogBuffer.end(), reinterpret_cast(str.data()), reinterpret_cast(str.data()) + str.size()); - - #if defined(AURORA_IS_MODERNNT_DERIVED) - gLogBuffer.insert(gLogBuffer.end(), AuUInt8('\r')); - #endif - gLogBuffer.insert(gLogBuffer.end(), AuUInt8('\n')); - }); + + Console::AddDefaultLogger(AuUnsafeRaiiToShared(gFileSink)); } void Pump() @@ -173,7 +142,10 @@ namespace Aurora::Console::ConsoleFIO void Exit() { Flush(); - gLogMutex.reset(); - gFileHandle.reset(); + if (gFileSink) + { + NewFileSinkDestroy(gFileSink); + gFileSink = nullptr; + } } } \ No newline at end of file diff --git a/Source/Console/ConsoleFIO/FileSink.cpp b/Source/Console/ConsoleFIO/FileSink.cpp new file mode 100644 index 00000000..7f25fd5e --- /dev/null +++ b/Source/Console/ConsoleFIO/FileSink.cpp @@ -0,0 +1,88 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: FileSink.cpp + Date: 2022-1-24 + Author: Reece +***/ +#include +#include "FileSink.hpp" + +namespace Aurora::Console::ConsoleFIO +{ + FIOSink::FIOSink(const AuString &path) : path_(path) + { + + } + + bool FIOSink::Init() + { + logMutex_ = AuThreadPrimitives::RWLockUnique(); + file_ = AuIOFS::OpenWriteUnique(path_); + return static_cast(file_); + } + + void FIOSink::OnMessageBlocking(AuUInt8 level, const ConsoleMessage &msg) + { + AU_LOCK_GUARD(logMutex_->AsWritable()); + auto str = msg.ToSimplified(); + + logBuffer_.reserve(logBuffer_.size() + str.size() + 2); + + logBuffer_.insert(logBuffer_.end(), reinterpret_cast(str.data()), reinterpret_cast(str.data()) + str.size()); + + #if defined(AURORA_IS_MODERNNT_DERIVED) + logBuffer_.insert(logBuffer_.end(), AuUInt8('\r')); + #endif + logBuffer_.insert(logBuffer_.end(), AuUInt8('\n')); + } + + void FIOSink::OnMessageNonblocking(AuUInt8 level, const ConsoleMessage &msg) + { + } + + void FIOSink::OnFlush() + { + if (!logMutex_) + { + return; + } + + AU_LOCK_GUARD(logMutex_->AsReadable()); + + if (logMutex_) + { + file_->Write(Aurora::Memory::MemoryViewStreamRead(logBuffer_)); + } + + logBuffer_.clear(); + } + + IBasicSink *NewFileSinkNew(const AuString &str) + { + try + { + auto logger = _new FIOSink(str); + if (!logger) + { + return nullptr; + } + + if (!logger->Init()) + { + return nullptr; + } + + return logger; + } + catch (...) + { + return {}; + } + } + + void NewFileSinkRelease(IBasicSink *logger) + { + SafeDelete(logger); + } +} \ No newline at end of file diff --git a/Source/Console/ConsoleFIO/FileSink.hpp b/Source/Console/ConsoleFIO/FileSink.hpp new file mode 100644 index 00000000..8f038996 --- /dev/null +++ b/Source/Console/ConsoleFIO/FileSink.hpp @@ -0,0 +1,31 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: FileSink.hpp + Date: 2022-1-24 + Author: Reece +***/ +#pragma once + +namespace Aurora::Console::ConsoleFIO +{ + struct FIOSink : IBasicSink + { + FIOSink(const AuString &path); + + bool Init(); + + void OnMessageBlocking(AuUInt8 level, const ConsoleMessage &msg) override; + void OnMessageNonblocking(AuUInt8 level, const ConsoleMessage &msg) override; + void OnFlush() override; + + private: + const AuString path_; + AuIOFS::OpenWriteUnique_t file_; + AuList logBuffer_; + AuThreadPrimitives::RWLockUnique_t logMutex_; + }; + + void NewFileSinkRelease(IBasicSink *logger); + IBasicSink *NewFileSinkNew(const AuString &str); +} \ No newline at end of file diff --git a/Source/Console/ConsoleMessage.cpp b/Source/Console/ConsoleMessage.cpp index ca281e96..5fa12807 100644 --- a/Source/Console/ConsoleMessage.cpp +++ b/Source/Console/ConsoleMessage.cpp @@ -30,17 +30,24 @@ namespace Aurora::Console AuString ConsoleMessage::StringifyTime(bool simple) const { - std::tm localized; - - Aurora::Time::ToCivilTime(time, false).CopyTo(localized); - - if (simple) + try { - return fmt::format("{:%H:%M:%S}", localized); + std::tm localized; + + Aurora::Time::ToCivilTime(time, false).CopyTo(localized); + + if (simple) + { + return fmt::format("{:%H:%M:%S}", localized); + } + else + { + return fmt::format("{:%Y-%m-%d %H:%M:%S}", localized); + } } - else + catch (...) { - return fmt::format("{:%Y-%m-%d %H:%M:%S}", localized); + return {}; } } @@ -51,11 +58,33 @@ namespace Aurora::Console AuString ConsoleMessage::ToConsole() const { - return fmt::format("{}[{}] {:<7} | {}{}", kAnsiCheats[static_cast(color)], StringifyTime(), GetWrappedTag(), line, kAnsiCheats[static_cast(EAnsiColor::eReset)]); + try + { + return fmt::format("{}[{}] {:<7} | {}{}", + static_cast(color) <= EAnsiColor::eCount ? + kAnsiCheats[static_cast(color)] : + "", + StringifyTime(), + GetWrappedTag(), + line, + kAnsiCheats[static_cast(EAnsiColor::eReset)]); + } + catch (...) + { + return {}; + } + } AuString ConsoleMessage::ToSimplified() const { - return fmt::format("{:<9} {:<7} | {}", StringifyTime(true), GetWrappedTag(), line); + try + { + return fmt::format("{:<9} {:<7} | {}", StringifyTime(true), GetWrappedTag(), line); + } + catch (...) + { + return {}; + } } } \ No newline at end of file diff --git a/Source/Console/ConsoleStd/ConsoleStd.cpp b/Source/Console/ConsoleStd/ConsoleStd.cpp index e669f001..c70860a7 100644 --- a/Source/Console/ConsoleStd/ConsoleStd.cpp +++ b/Source/Console/ConsoleStd/ConsoleStd.cpp @@ -7,7 +7,8 @@ ***/ #include #include "ConsoleStd.hpp" -#include "Source/Locale/Locale.hpp" +#include +#include #if defined(AURORA_IS_MODERNNT_DERIVED) || defined(AURORA_IS_POSIX_DERIVED) @@ -77,6 +78,43 @@ namespace Aurora::Console::ConsoleStd } #endif + static void WriteStdOut(AuUInt8 level, const ConsoleMessage &msg); + + struct ConsoleStdLogger : IBasicSink + { + void OnMessageBlocking(AuUInt8 level, const ConsoleMessage &msg) override; + void OnMessageNonblocking(AuUInt8 level, const ConsoleMessage &msg) override; + void OnFlush() override; + }; + + void ConsoleStdLogger::OnMessageBlocking(AuUInt8 level, const ConsoleMessage &msg) + { + if (!gRuntimeConfig.console.asyncWrite) return; + WriteStdOut(level, msg); + } + + void ConsoleStdLogger::OnMessageNonblocking(AuUInt8 level, const ConsoleMessage &msg) + { + if (gRuntimeConfig.console.asyncWrite) return; + WriteStdOut(level, msg); + } + + void ConsoleStdLogger::OnFlush() + { + + } + + static ConsoleStdLogger gStdConsoleSink; + + IBasicSink *NewStdSinkNew() + { + return &gStdConsoleSink; + } + + void NewStdSinkRelease(IBasicSink *registry) + {} + + static void StartLogger() { if (gRuntimeConfig.console.enableStdPassthrough && gRuntimeConfig.console.enableStdOut) @@ -84,51 +122,12 @@ namespace Aurora::Console::ConsoleStd return; } - Console::Hooks::AddFunctionalHook([](const Aurora::Console::ConsoleMessage &string) -> void + if (!gRuntimeConfig.console.enableStdOut) { - #if (defined(DEBUG) || defined(STAGING)) && defined(AURORA_IS_MODERNNT_DERIVED) - auto debugLine = string.ToSimplified() + "\r\n"; - OutputDebugStringW(Locale::ConvertFromUTF8(debugLine).c_str()); - #endif + return; + } - if (!gRuntimeConfig.console.enableStdOut) - { - return; - } - - auto writeLine = string.ToConsole(); - - #if defined(AURORA_IS_MODERNNT_DERIVED) - writeLine += '\r'; - #endif - writeLine += '\n'; - - #if defined(IO_POSIX_STREAMS) - if (Locale::GetInternalCodePage() == Locale::ECodePage::eUTF8) - { - WriteStdOut(writeLine.data(), writeLine.size()); - } - else - { - AuString slow; - slow.resize(writeLine.size() * 4); - auto len = Locale::Encoding::EncodeUTF8(writeLine, Aurora::Memory::MemoryViewWrite {slow.data(), slow.size()}, Locale::ECodePage::eSysUnk); - if (len.first != 0) - { - WriteStdOut(slow.data(), len.second); - } - else - { - // better write this than nothing - WriteStdOut(writeLine.data(), writeLine.size()); - } - } - - #elif defined(AURORA_IS_MODERNNT_DERIVED) - WriteStdOut(writeLine.data(), writeLine.size()); - #endif - - }); + Console::AddDefaultLogger(AuUnsafeRaiiToShared(&gStdConsoleSink)); } void Start() @@ -287,7 +286,47 @@ namespace Aurora::Console::ConsoleStd return written; } - + + static void WriteStdOut(AuUInt8 level, const ConsoleMessage &msg) + { + #if (defined(DEBUG) || defined(STAGING)) && defined(AURORA_IS_MODERNNT_DERIVED) + auto debugLine = msg.ToSimplified() + "\r\n"; + OutputDebugStringW(Locale::ConvertFromUTF8(debugLine).c_str()); + #endif + + auto writeLine = msg.ToConsole(); + + #if defined(AURORA_IS_MODERNNT_DERIVED) + writeLine += '\r'; + #endif + writeLine += '\n'; + + #if defined(IO_POSIX_STREAMS) + if (Locale::GetInternalCodePage() == Locale::ECodePage::eUTF8) + { + WriteStdOut(writeLine.data(), writeLine.size()); + } + else + { + AuString slow; + slow.resize(writeLine.size() * 4); + auto len = Locale::Encoding::EncodeUTF8(writeLine, Aurora::Memory::MemoryViewWrite {slow.data(), slow.size()}, Locale::ECodePage::eSysUnk); + if (len.first != 0) + { + WriteStdOut(slow.data(), len.second); + } + else + { + // better write this than nothing + WriteStdOut(writeLine.data(), writeLine.size()); + } + } + + #elif defined(AURORA_IS_MODERNNT_DERIVED) + WriteStdOut(writeLine.data(), writeLine.size()); + #endif + } + static bool InputStreamAvailable() { #if defined(IO_POSIX_STREAMS) diff --git a/Source/Console/ConsoleStd/ConsoleStd.hpp b/Source/Console/ConsoleStd/ConsoleStd.hpp index 6a867258..e3beda7a 100644 --- a/Source/Console/ConsoleStd/ConsoleStd.hpp +++ b/Source/Console/ConsoleStd/ConsoleStd.hpp @@ -15,6 +15,10 @@ namespace Aurora::Console::ConsoleStd void Start(); + + IBasicSink *NewStdSinkNew(); + void NewStdSinkRelease(IBasicSink *registry); + AuUInt32 ReadStdIn(void *data, AuUInt32 length); AuUInt32 WriteStdOut(const void *data, AuUInt32 length); } \ No newline at end of file diff --git a/Source/Console/ConsoleWxWidgets/ConsoleWxWidgets.cpp b/Source/Console/ConsoleWxWidgets/ConsoleWxWidgets.cpp index 01af61e0..f6bd5d80 100644 --- a/Source/Console/ConsoleWxWidgets/ConsoleWxWidgets.cpp +++ b/Source/Console/ConsoleWxWidgets/ConsoleWxWidgets.cpp @@ -605,7 +605,7 @@ void ConsoleFrame::OnAbout(wxCommandEvent &event) void ConsoleFrame::OnHello(wxCommandEvent &event) { - LogGame("nani?!"); + AuLogGame("nani?!"); } void ConsoleFrame::OnBugWrite(wxCommandEvent &event) diff --git a/Source/Console/Flusher.cpp b/Source/Console/Flusher.cpp index 4f6961c3..3e1af19f 100644 --- a/Source/Console/Flusher.cpp +++ b/Source/Console/Flusher.cpp @@ -9,10 +9,13 @@ #include "Flusher.hpp" #include "ConsoleFIO/ConsoleFIO.hpp" +#include "Logging/Logger.hpp" namespace Aurora::Console { static AuThreads::ThreadUnique_t gWriterThread; + static AuThreadPrimitives::ConditionVariableUnique_t gCondVar; + static AuThreadPrimitives::ConditionMutexUnique_t gMutex; class ShutdownFlushHook : public AuThreads::IThreadFeature { @@ -38,13 +41,13 @@ namespace Aurora::Console static void LogThreadEP() { - auto thread = AuThreads::GetThread(); - SlowStartupTasks(); - while (!thread->Exiting()) + AU_LOCK_GUARD(gMutex); + + while (AuIsThreadRunning()) { - Threading::Sleep(500); + gCondVar->WaitForSignal(500); ForceFlush(); } } @@ -57,16 +60,17 @@ namespace Aurora::Console static void InitFlushThread() { // Startup a runner thread that will take care of all the stress inducing IO every so often on a remote thread - gWriterThread = AuThreads::ThreadUnique(AuThreads::ThreadInfo( AuMakeShared(AuThreads::IThreadVectorsFunctional::OnEntry_t(std::bind(LogThreadEP)), AuThreads::IThreadVectorsFunctional::OnExit_t{}), "CasualConsoleAsyncWritter" )); + if (!gWriterThread) { return; } + gWriterThread->Run(); } @@ -75,9 +79,23 @@ namespace Aurora::Console // Add a 'ShutdownFlushHook' object to the main threads TLS hook AuThreads::GetThread()->AddLastHopeTlsHook(AuMakeShared()); + gMutex = AuThreadPrimitives::ConditionMutexUnique(); + SysAssert(gMutex); + + gCondVar = AuThreadPrimitives::ConditionVariableUnique(AuUnsafeRaiiToShared(gMutex)); + SysAssert(gCondVar); + InitFlushThread(); } + void PingFlushers() + { + if (gCondVar) + { + gCondVar->Signal(); + } + } + void DeinitFlusher() { DestroyFlushThread(); @@ -85,6 +103,7 @@ namespace Aurora::Console void ForceFlush() { + Logging::ForceFlushLoggers(); ConsoleFIO::Flush(); } } \ No newline at end of file diff --git a/Source/Console/Flusher.hpp b/Source/Console/Flusher.hpp index 06bbd79f..5ecc133b 100644 --- a/Source/Console/Flusher.hpp +++ b/Source/Console/Flusher.hpp @@ -9,6 +9,8 @@ namespace Aurora::Console { + void PingFlushers(); + void ForceFlush(); void InitFlusher(); void DeinitFlusher(); diff --git a/Source/Console/Logging/Logger.cpp b/Source/Console/Logging/Logger.cpp index e69de29b..7d653fd9 100644 --- a/Source/Console/Logging/Logger.cpp +++ b/Source/Console/Logging/Logger.cpp @@ -0,0 +1,235 @@ +#include +#include "Logger.hpp" + +namespace Aurora::Console::Logging +{ + static AuList> gLogTasks; + static AuThreadPrimitives::SpinLock gGlobalSpin; + static AuList gFlushableLoggers; + + Logger::Logger(const AuList> &sinks) : sinks(sinks) + { + AuMemset(shouldFilter, 0, sizeof(shouldFilter)); + { + AU_LOCK_GUARD(gGlobalSpin); + AuTryInsert(gFlushableLoggers, this); + } + } + + Logger::~Logger() + { + Disable(); + } + + void Logger::WriteMessage(AuUInt8 level, const ConsoleMessage &msg) + { + { + AU_LOCK_GUARD(spin); + + if (shouldFilter[level]) + { + return; + } + } + + AddToPushQueue(level, msg); + WriteNow(level, msg); + } + + void Logger::AddToPushQueue(AuUInt8 level, const ConsoleMessage &msg) + { + AU_LOCK_GUARD(gGlobalSpin); + + while (!AuTryInsert(gLogTasks, AuMakeTuple(this, level, msg))) + { + SysPushErrorMem("Push failed - trying again"); + spin.Unlock(); + AuThreading::Sleep(100); + spin.Lock(); + } + } + + void Logger::PushFilter(AuUInt8 level, bool shouldFilter) + { + AU_LOCK_GUARD(spin); + + try + { + while (!AuTryInsert(filters, AuMakeTuple(level, shouldFilter))) + { + SysPushErrorMem("Push failed - trying again. wont be able to handle pop - wont syspanic yet"); + AuThreading::Sleep(100); + } + + AuMemset(this->shouldFilter, 0, sizeof(this->shouldFilter)); + + for (auto &tuple : filters) + { + auto level = std::get<0>(tuple); + auto shouldFilter = std::get<1>(tuple); + this->shouldFilter[level] = shouldFilter; + } + } + catch (...) + { + } + } + + void Logger::PopFilter() + { + try + { + AU_LOCK_GUARD(spin); + filters.pop_back(); + } + catch (...) + { + + } + } + + void ForceFlushLoggers() + { + AU_LOCK_GUARD(gGlobalSpin); + decltype(gLogTasks) logTasks; + + try + { + + logTasks = AuExchange(gLogTasks, {}); + } + catch (...) + { + + } + + if (logTasks.empty()) + { + return; + } + + try + { + for (const auto &logEntry : logTasks) + { + auto &logger = std::get<0>(logEntry); + auto &level = std::get<1>(logEntry); + auto &message = std::get<2>(logEntry); + + logger->WriteLater(level, message); + } + } + catch (...) + { + + } + + + for (const auto &logger : gFlushableLoggers) + { + for (const auto &sink : logger->sinks) + { + try + { + sink->OnFlush(); + } + catch (...) + { + SysPushErrorGeneric("..."); + } + } + } + } + + void Logger::Disable() + { + { + AU_LOCK_GUARD(spin); + AuMemset(shouldFilter, 1, sizeof(shouldFilter)); + } + + { + AU_LOCK_GUARD(gGlobalSpin); + AuTryDeleteList(gFlushableLoggers, this); + } + + ForceFlushLoggers(); + } + + void Logger::WriteNow(AuUInt8 level, const ConsoleMessage &msg) + { + try + { + for (const auto &sink : this->sinks) + { + try + { + sink->OnMessageNonblocking(level, msg); + } + catch (...) + { + SysPushErrorGeneric("Failed to pump a logger"); + } + } + } + catch (...) + { + + } + } + + void Logger::WriteLater(AuUInt8 level, const ConsoleMessage &msg) + { + try + { + for (const auto &sink : this->sinks) + { + try + { + sink->OnMessageBlocking(level, msg); + } + catch (...) + { + SysPushErrorGeneric("Failed to pump a logger"); + } + } + } + catch (...) + { + + } + } + + void InitLoggers() + { + + } + + void DeinitLoggers() + { + ForceFlushLoggers(); + } + + AUKN_SYM ILogger *NewLoggerNew(const AuList> &sinks) + { + try + { + auto logger = _new Logger(sinks); + if (!logger) + { + return nullptr; + } + + return logger; + } + catch (...) + { + return {}; + } + } + + AUKN_SYM void NewLoggerRelease(ILogger *logger) + { + SafeDelete(logger); + } +} \ No newline at end of file diff --git a/Source/Console/Logging/Logger.hpp b/Source/Console/Logging/Logger.hpp index e69de29b..0573caf0 100644 --- a/Source/Console/Logging/Logger.hpp +++ b/Source/Console/Logging/Logger.hpp @@ -0,0 +1,31 @@ +#pragma once + +namespace Aurora::Console::Logging +{ + struct Logger : ILogger + { + Logger(const AuList> &sinks); + ~Logger(); + + void WriteMessage(AuUInt8 level, const ConsoleMessage &msg) override; + + void PushFilter(AuUInt8 level, bool shouldFilter) override; + void PopFilter() override; + + void AddToPushQueue(AuUInt8 level, const ConsoleMessage &msg); + void WriteNow(AuUInt8 level, const ConsoleMessage &msg); + void WriteLater(AuUInt8 level, const ConsoleMessage &msg); + + void Disable(); + + AuThreadPrimitives::SpinLock spin; + AuList> sinks; + AuList> filters; // std::vector > std::stack performance. dont ask me why or for the benchmarks, just trust me bro + AuUInt8 shouldFilter[0xFF]; + }; + + void ForceFlushLoggers(); + + void DeinitLoggers(); + void InitLoggers(); +} \ No newline at end of file diff --git a/Source/Console/Logging/Sinks.cpp b/Source/Console/Logging/Sinks.cpp index e69de29b..5c462eb7 100644 --- a/Source/Console/Logging/Sinks.cpp +++ b/Source/Console/Logging/Sinks.cpp @@ -0,0 +1,54 @@ +#include +#include "Sinks.hpp" + +#include "../ConsoleStd/ConsoleStd.hpp" +#include "../ConsoleFIO/FileSink.hpp" + +namespace Aurora::Console::Logging +{ + AUKN_SYM IBasicSink *NewStdSinkNew() + { + return ConsoleStd::NewStdSinkNew(); + } + + AUKN_SYM void NewStdSinkRelease(IBasicSink *sink) + { + ConsoleStd::NewStdSinkRelease(sink); + } + + AUKN_SYM IBasicSink *NewOSEventDirectorySinkNew() + { + return {}; + } + + AUKN_SYM void NewOSEventDirectorySinkRelease(IBasicSink *registry) + {} + + AUKN_SYM IBasicSink *NewFileSinkNew(const AuString &path, bool binary) + { + return ConsoleFIO::NewFileSinkNew(path); + } + + AUKN_SYM void NewFileSinkRelease(IBasicSink *sink) + { + ConsoleFIO::NewFileSinkRelease(sink); + } + + AUKN_SYM IBasicSink *NewIPCSinkNew(const SocketConsole &console) + { + return {}; + } + + AUKN_SYM void NewIPCSinkRelease(IBasicSink *registry) + {} + + + AUKN_SYM IBasicSinkRB *NewRingLoggerNew(AuUInt32 approxMaxBytes) + { + return {}; + } + + AUKN_SYM void NewRingLoggerRelease(IBasicSinkRB *registry) + {} + +} \ No newline at end of file diff --git a/Source/Console/Logging/Sinks.hpp b/Source/Console/Logging/Sinks.hpp index e69de29b..23936150 100644 --- a/Source/Console/Logging/Sinks.hpp +++ b/Source/Console/Logging/Sinks.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace Aurora::Console::Logging +{ + +} \ No newline at end of file diff --git a/Source/Debug/Debug.cpp b/Source/Debug/Debug.cpp index 67e07c4b..9b92e33b 100644 --- a/Source/Debug/Debug.cpp +++ b/Source/Debug/Debug.cpp @@ -15,13 +15,13 @@ namespace Aurora::Debug { - static thread_local AuUInt32 tlsLastBackTrace = 0xFFFFFFFF; + static thread_local AuUInt32 tlsLastBackTrace = 0xFFFFFFFF; + static thread_local StackTrace tlsLastStackTrace; + static thread_local AuString tlsLastExceptionMessage; - static StackTrace gLastStackTrace; static AuUInt32 gStackTraceFence; static AuUInt32 gFenceId; static AuThreadPrimitives::SpinLock gLock; - static AuString gLastExceptionMessage; static AuUInt32 gFenceOSError = -1; AuUInt32 GetOSErrorFence() @@ -175,8 +175,8 @@ namespace Aurora::Debug AuUInt32 ReportStackTrace(const StackTrace& trace, const AuString& message) { AU_LOCK_GUARD(gLock); - gLastStackTrace = trace; - gLastExceptionMessage = message; + tlsLastStackTrace = trace; + tlsLastExceptionMessage = message; tlsLastBackTrace = gStackTraceFence++; gFenceId++; return tlsLastBackTrace; @@ -195,13 +195,13 @@ namespace Aurora::Debug AUKN_SYM StackTrace GetLastStackTrace() { AU_LOCK_GUARD(gLock); - return gLastStackTrace; + return tlsLastStackTrace; } AUKN_SYM AuString GetLastException() { AU_LOCK_GUARD(gLock); - return gLastExceptionMessage; + return tlsLastExceptionMessage; } AUKN_SYM OSError_t GetLastSystemMessage() @@ -223,7 +223,7 @@ namespace Aurora::Debug auto cError = TryGetOrFetchCError(); if ((cError) && (cFence != cLastFence)) { - LogWarn("Language Error: {} ({})", strerror(*cError), *cError); + AuLogWarn("Language Error: {} ({})", strerror(*cError), *cError); cLastFence = cFence; } @@ -232,7 +232,7 @@ namespace Aurora::Debug auto osError = TryGetOrFetchOSError(); if ((osError) && (osFence != osLastFence)) { - LogWarn("Operating System Error: {} (0x{:x})", osError->second, osError->first); + AuLogWarn("Operating System Error: {} (0x{:x})", osError->second, osError->first); osLastFence = osFence; } @@ -245,7 +245,7 @@ namespace Aurora::Debug Telemetry::EndBlock(); } - void CheckErrors() + AUKN_SYM void CheckErrors() { AuUInt32 rng = GetFenceId(); Telemetry::BeginBlock(); @@ -301,7 +301,7 @@ namespace Aurora::Debug #if defined(DEBUG) || defined(STAGING) PrintError(); - LogWarn("ERROR: {}", error.dbg); + AuLogWarn("ERROR: {}", error.dbg); #endif } @@ -310,64 +310,78 @@ namespace Aurora::Debug const auto frame = *this; AuString backTraceBuffer; - backTraceBuffer.reserve(512 - 32); // 512 seems like a nice length minus some overhead for a bucket allocator - - backTraceBuffer += fmt::format("\tAddress: {:x}", frame.address); - - if (frame.module) + try { - auto modName = frame.module.value(); - if (modName.size()) + backTraceBuffer.reserve(512 - 32); // 512 seems like a nice length minus some overhead for a bucket allocator + + backTraceBuffer += fmt::format("\tAddress: 0x{:x} (0x{:x})", frame.relAddress ? frame.relAddress : frame.address, frame.relAddress ? frame.address : frame.relAddress); + + if (frame.module) { - backTraceBuffer += fmt::format(" within {}", modName); + auto modName = frame.module.value(); + if (modName.size()) + { + backTraceBuffer += fmt::format(" within {}", modName); + } + else + { + backTraceBuffer += ", invalid module"; + } } else { - backTraceBuffer += ", invalid module"; + backTraceBuffer += ", unknown module"; } - } - else - { - backTraceBuffer += ", unknown module"; - } - if (frame.label) - { - backTraceBuffer += fmt::format(" ({}) \n", frame.label.value()); - } - else - { - backTraceBuffer += ", unknown function\n"; - } - - if (frame.file) - { - const auto &re = frame.file.value(); - backTraceBuffer += fmt::format("\t\t{}:{} ({}) \n", std::get<0>(re), std::get<1>(re), std::get<2>(re)); - } - else - { - backTraceBuffer += "\t\t[proprietary]\n"; - } + if (frame.label) + { + backTraceBuffer += fmt::format(" ({}) \n", frame.label.value()); + } + else + { + backTraceBuffer += ", unknown function\n"; + } - return backTraceBuffer; + if (frame.file) + { + const auto &re = frame.file.value(); + backTraceBuffer += fmt::format("\t\t{}:{} ({}) \n", std::get<0>(re), std::get<1>(re), std::get<2>(re)); + } + else + { + backTraceBuffer += "\t\t[proprietary]\n"; + } + + return backTraceBuffer; + } + catch (...) + { + return {}; + } } AUKN_SYM AuString StringifyStackTrace(const StackTrace &backtrace) { - AuString backTraceBuffer; + AuString backTraceBuffer; - backTraceBuffer.reserve(2048); - - backTraceBuffer += "Unwinding call frame:"; - - for (const auto &frame : backtrace) + try { - backTraceBuffer += "\n"; - backTraceBuffer += frame.Stringify(); - } + backTraceBuffer.reserve(2048); - return backTraceBuffer; + backTraceBuffer += "Unwinding call frame:"; + + for (const auto &frame : backtrace) + { + backTraceBuffer += "\n"; + backTraceBuffer += frame.Stringify(); + } + + return backTraceBuffer; + } + catch (...) + { + return {}; + } } void InitDebug() diff --git a/Source/Debug/ExceptionWatcher.Win32.cpp b/Source/Debug/ExceptionWatcher.Win32.cpp index 4172acf0..1beba8a4 100644 --- a/Source/Debug/ExceptionWatcher.Win32.cpp +++ b/Source/Debug/ExceptionWatcher.Win32.cpp @@ -19,10 +19,33 @@ #include #include -static thread_local int gDebugLocked = 0; +#include + +static thread_local int gDebugLocked = 0; namespace Aurora::Debug { + static AuUInt GetImageBase(HMODULE mod) + { + if (!mod) + { + return 0; + } + + if (mod == INVALID_HANDLE_VALUE) + { + return 0; + } + + auto cache = Process::GetFromModuleCache(reinterpret_cast(mod)); + if (!cache.moduleMeta) + { + return 0; + } + + return cache.moduleMeta->origVa; + } + static void ParseStack(CONTEXT *ctx, StackTrace &backTrace) { char buffer[sizeof(SYMBOL_INFO) + (MAX_SYM_NAME + 1) * sizeof(char)] = { 0 }; @@ -80,26 +103,17 @@ namespace Aurora::Debug pSymbol->MaxNameLen = MAX_SYM_NAME; frameCurrent.address = stack.AddrPC.Offset; + frameCurrent.relAddress = frameCurrent.address; if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)(stack.AddrPC.Offset), &hModule)) { if (hModule != NULL) { frameCurrent.module = Process::ModuleToPath(hModule); + frameCurrent.relAddress = frameCurrent.relAddress - reinterpret_cast(hModule) + GetImageBase(hModule); } } - try - { - //if (SymFromAddr(process, (ULONG64)stack.AddrPC.Offset, &displacement, pSymbol)) - { - //frameCurrent.label = pSymbol->Name; - } - } - catch (...) - { - } - #if defined(DEBUG) || defined(STAGING) IMAGEHLP_LINE64 line; DWORD disp; @@ -336,8 +350,8 @@ namespace Aurora::Debug if ((isCritical || isInternal) && (minimal == 0)) { - LogWarn("NT Exception: 0x{:x}, {}", ExceptionInfo->ExceptionRecord->ExceptionCode, entry.wincxx.str); - LogWarn("{}", StringifyStackTrace(entry.wincxx.stack.backtrace)); + AuLogWarn("NT Exception: 0x{:x}, {}", ExceptionInfo->ExceptionRecord->ExceptionCode, entry.wincxx.str); + AuLogWarn("{}", StringifyStackTrace(entry.wincxx.stack.backtrace)); } try diff --git a/Source/Entrypoint.cpp b/Source/Entrypoint.cpp index c238e8dd..c6e89af0 100644 --- a/Source/Entrypoint.cpp +++ b/Source/Entrypoint.cpp @@ -24,6 +24,7 @@ #if defined(AURORA_PLATFORM_WIN32) #include "Extensions/Win32/DarkTheme.hpp" #endif +#include "Process/ProcessMap.hpp" static void Init() { @@ -44,6 +45,7 @@ static void Init() Aurora::Async::InitAsync(); Aurora::HWInfo::Init(); Aurora::Telemetry::Init(); + Aurora::Process::InitProcessMap(); } static void Pump() @@ -66,7 +68,14 @@ namespace Aurora AUKN_SYM void RuntimeStart(const RuntimeStartInfo &info) { gRuntimeConfig = info; - Init(); + try + { + Init(); + } + catch (...) + { + SysPanic("A fatal error occurred during the initialization of Aurora Runtime"); + } gRuntimeHasStarted = true; } diff --git a/Source/HWInfo/CpuInfo.cpp b/Source/HWInfo/CpuInfo.cpp index 526c0b4a..bb3ed816 100644 --- a/Source/HWInfo/CpuInfo.cpp +++ b/Source/HWInfo/CpuInfo.cpp @@ -23,6 +23,10 @@ #include #endif +#if defined(AURORA_IS_MODERNNT_DERIVED) + #include +#endif + namespace Aurora::HWInfo { static CpuInfo gCpuInfo; @@ -348,10 +352,10 @@ namespace Aurora::HWInfo } char vendor[0x20]; - memset(vendor, 0, sizeof(vendor)); - *reinterpret_cast(vendor) = cpuInfo.ebx; - *reinterpret_cast(vendor + 4) = cpuInfo.edx; - *reinterpret_cast(vendor + 8) = cpuInfo.ecx; + AuMemset(vendor, 0, sizeof(vendor)); + *reinterpret_cast(vendor) = cpuInfo.ebx; + *reinterpret_cast(vendor + 4) = cpuInfo.edx; + *reinterpret_cast(vendor + 8) = cpuInfo.ecx; gCpuInfo.cpuId.vendor = vendor; @@ -383,7 +387,7 @@ namespace Aurora::HWInfo auto nExIds = cpui.eax; char brand[0x40]; - memset(brand, 0, sizeof(brand)); + AuMemset(brand, 0, sizeof(brand)); for (int i = 0x80000000; i <= nExIds; ++i) { @@ -400,56 +404,159 @@ namespace Aurora::HWInfo // Interpret CPU brand string if reported if (nExIds >= 0x80000004) { - memcpy(brand, &extdata[2], sizeof(cpui)); - memcpy(brand + 16, &extdata[3], sizeof(cpui)); - memcpy(brand + 32, &extdata[4], sizeof(cpui)); + AuMemcpy(brand, &extdata[2], sizeof(cpui)); + AuMemcpy(brand + 16, &extdata[3], sizeof(cpui)); + AuMemcpy(brand + 32, &extdata[4], sizeof(cpui)); gCpuInfo.cpuId.brand = brand; } #endif } - static void SetCpuTopology() +#if defined(AURORA_IS_MODERNNT_DERIVED) + static bool IsWindowsLTSC() + { + OSVERSIONINFOEXW osvi = {sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0, VER_SUITE_ENTERPRISE, 0}; + DWORDLONG const dwlConditionMask = VerSetConditionMask(0, VER_SUITENAME, VER_EQUAL); + + return !VerifyVersionInfoW(&osvi, VER_SUITENAME, dwlConditionMask); + } + + static bool TrySetNtCpuSetInfoSlowExtended() + { + SYSTEM_CPU_SET_INFORMATION cpuSetInfo[128]; + SYSTEM_LOGICAL_PROCESSOR_INFORMATION sysinfo[128]; + DWORD length = {}; + + if (!GetSystemCpuSetInformation(cpuSetInfo, sizeof(cpuSetInfo), &length, 0, 0)) + { + return false; + } + + struct CpuInfo + { + AuList low; + AuList server; + CpuBitId mask; + }; + AuBST cpuThreads; + AuUInt8 cpuCount; + + cpuCount = length / sizeof(decltype(*cpuSetInfo)); + + for (int i = 0; i < cpuCount; i++) + { + auto &idx = cpuThreads[cpuSetInfo[i].CpuSet.CoreIndex]; + AuUInt8 id = AuUInt8(cpuSetInfo[i].CpuSet.LogicalProcessorIndex + cpuSetInfo[i].CpuSet.Group); + auto cpuId = CpuBitId(id); + idx.server.push_back(cpuId); + idx.low.push_back(id); + idx.mask.Add(cpuId); + } + + for (const auto &[cpuId, coreIds] : cpuThreads) + { + AuUInt64 shortMask {}; + for (const auto &id : coreIds.server) + { + // TODO (scar): + if (false) + { + gCpuInfo.maskECores.Add(id); + } + } + + for (const auto &id : coreIds.low) + { + shortMask |= AuUInt64(1) << AuUInt64(id); + } + + gCpuInfo.serverTopology.push_back(coreIds.mask); + gCpuInfo.threadTopology.push_back(shortMask); + } + + gCpuInfo.socket = 1; + gCpuInfo.threads = cpuCount; + gCpuInfo.cores = cpuThreads.size(); + + if (!GetLogicalProcessorInformation(sysinfo, &length)) + { + return true; + } + + gCpuInfo.socket = 0; + length /= sizeof(*sysinfo); + + for (auto i = 0; i < length; i++) + { + if (sysinfo[i].Relationship == RelationProcessorPackage) + { + gCpuInfo.socket++; + } + } + + return true; + } + + static void SetCpuTopologyNT() { - #if defined(AURORA_IS_MODERNNT_DERIVED) SYSTEM_LOGICAL_PROCESSOR_INFORMATION sysinfo[128]; DWORD length = AuArraySize(sysinfo) * sizeof(*sysinfo); - + + if (IsWindows10OrGreater() || IsWindowsServer() || IsWindowsLTSC()) + { + if (TrySetNtCpuSetInfoSlowExtended()) + { + return; + } + } + if (!GetLogicalProcessorInformation(sysinfo, &length)) { SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); - gCpuInfo.socket = 1; - gCpuInfo.cores = 1; + gCpuInfo.socket = 1; + gCpuInfo.cores = 1; gCpuInfo.threads = sysinfo.dwNumberOfProcessors; return; } length /= sizeof(*sysinfo); - - gCpuInfo.socket = 0; - gCpuInfo.cores = 0; + + gCpuInfo.socket = 0; + gCpuInfo.cores = 0; gCpuInfo.threads = 0; + + bool sparse = false; for (auto i = 0; i < length; i++) { if (sysinfo[i].Relationship == RelationProcessorCore) { - //TODO: fuck it, if some macro fuckery, use popcnt on x86 - //we just need to count the bits. first it was just two BitScanForwards. discontiguous cores fucked things up so now we have a loop just to count a few bits. - gCpuInfo.cores++; - auto mask = sysinfo[i].ProcessorMask; + + gCpuInfo.cores++; + gCpuInfo.threadTopology.push_back(mask); + + CpuBitId serverId; + serverId.lower = mask; + gCpuInfo.serverTopology.push_back(mask); + + // TODO: fuck it, if some macro fuckery, use popcnt on x86 + // we just need to count the bits. first it was just two BitScanForwards. discontiguous cores fucked things up so now we have a loop just to count a few bits. + int counter {}; unsigned long offset {}, tmp; - while (offset != (sizeof(offset) * 8)) + while (offset != (sizeof(offset) * 8)) { // Count the index to a 1 if (BitScanForward(&tmp, mask >> offset) == 0) break; // mask was zero, end of scan offset += tmp; - + // Count the 1's by inverting the bitmap and counting to 1 BitScanForward(&tmp, ~(mask >> offset)); offset += tmp; - + + if (counter++) sparse = true; + // Increment threads by the bits set in gCpuInfo.threads += tmp; } @@ -460,6 +567,15 @@ namespace Aurora::HWInfo } } + gCpuInfo.maskMTContig = !sparse; + gCpuInfo.maskMTHalf = sparse; + } +#endif + + static void SetCpuTopology() + { + #if defined(AURORA_IS_MODERNNT_DERIVED) + SetCpuTopologyNT(); #elif defined(AURORA_IS_BSD_DERIVED) auto opt = QueryBsdHwStat(HW_AVAILCPU); @@ -472,12 +588,18 @@ namespace Aurora::HWInfo gCpuInfo.cores = 1; gCpuInfo.threads = opt.value_or(1); + // TODO: parse sysctl kern.sched.topology_spec + gCpuInfo.maskMTHalf = true; + #elif defined(AURORA_IS_LINUX_DERIVED) gCpuInfo.socket = 1; gCpuInfo.cores = 1; gCpuInfo.threads = get_nprocs(); + // TODO: parse /proc/cpuinfo + gCpuInfo.maskMTHalf = true; + #elif defined(AURORA_IS_POSIX_DERIVED) gCpuInfo.socket = 1; @@ -487,10 +609,47 @@ namespace Aurora::HWInfo #endif } + static void SetFakeTopologyIfMissing() + { + if (gCpuInfo.threadTopology.size() || gCpuInfo.serverTopology.size()) + { + return; + } + + bool fakeMtHalf = (gCpuInfo.threads & 1) == 0; + gCpuInfo.maskMTHalf = true; + + if (fakeMtHalf) + { + for (int i = 0; i < gCpuInfo.threads / 2; i++) + { + AuUInt64 shortMask {AuUInt64(1) << AuUInt64(i)}, shortMask2 {AuUInt64(1) << AuUInt64(i + gCpuInfo.threads / 2)}; + CpuBitId mask; + mask.lower = shortMask | shortMask2; + gCpuInfo.serverTopology.push_back(mask); + gCpuInfo.threadTopology.push_back(shortMask); + } + } + else + { + for (int i = 0; i < gCpuInfo.threads; i++) + { + AuUInt64 shortMask {AuUInt64(1) << AuUInt64(i)}; + CpuBitId mask; + mask.lower = shortMask; + gCpuInfo.serverTopology.push_back(mask); + gCpuInfo.threadTopology.push_back(shortMask); + } + } + } + void InitCpuInfo() { + gCpuInfo.maskMTContig = false; + gCpuInfo.maskMTHalf = false; gCpuInfo.cpuArch = Aurora::Build::kCurrentArchitecture; SetCpuId(); SetCpuTopology(); + SetFakeTopologyIfMissing(); } } diff --git a/Source/IO/FS/Async.NT.cpp b/Source/IO/FS/Async.NT.cpp index 666f912a..84a6147d 100644 --- a/Source/IO/FS/Async.NT.cpp +++ b/Source/IO/FS/Async.NT.cpp @@ -88,7 +88,16 @@ namespace Aurora::IO::FS HANDLE fileHandle; auto pathex = NormalizePathRet(path); + if (!pathex.empty()) + { + return false; + } + auto win32Path = Locale::ConvertFromUTF8(pathex); + if (!win32Path.empty()) + { + return false; + } auto flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED; @@ -109,7 +118,7 @@ namespace Aurora::IO::FS if (fileHandle == INVALID_HANDLE_VALUE) { - LogWarn("Missing file: {}", path); + AuLogWarn("Missing file: {}", path); SysPushErrorIO("Missing file: {}", path); return {}; } diff --git a/Source/IO/FS/FS.Generic.cpp b/Source/IO/FS/FS.Generic.cpp index 61557f38..6ca8cc2b 100644 --- a/Source/IO/FS/FS.Generic.cpp +++ b/Source/IO/FS/FS.Generic.cpp @@ -181,7 +181,7 @@ namespace Aurora::IO::FS { if (ENOENT == errno) { - LogWarn("Critical IO error, errno = {}", path); + AuLogWarn("Critical IO error, errno = {}", path); } return false; } @@ -193,7 +193,7 @@ namespace Aurora::IO::FS if (!stat.exists) { - LogWarn("Missing attribute type of path {}, stat mode {}", path, s.st_mode); + AuLogWarn("Missing attribute type of path {}, stat mode {}", path, s.st_mode); return false; } diff --git a/Source/IO/FS/FS.NT.cpp b/Source/IO/FS/FS.NT.cpp index 25bfe677..23cc8d6e 100644 --- a/Source/IO/FS/FS.NT.cpp +++ b/Source/IO/FS/FS.NT.cpp @@ -56,8 +56,18 @@ namespace Aurora::IO::FS pathNormalized = NormalizePathRet(path); win32Path = Locale::ConvertFromUTF8(pathNormalized); - CreateDirectories(pathNormalized, true); + if (!pathNormalized.empty()) + { + return false; + } + if (!win32Path.empty()) + { + return false; + } + + CreateDirectories(pathNormalized, true); + fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (fileHandle == INVALID_HANDLE_VALUE) { @@ -106,6 +116,11 @@ namespace Aurora::IO::FS offset = 0; win32Path = Locale::ConvertFromUTF8(NormalizePathRet(path)); + if (!win32Path.empty()) + { + return false; + } + auto fileHandle = CreateFileW(win32Path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fileHandle == INVALID_HANDLE_VALUE) { @@ -133,7 +148,7 @@ namespace Aurora::IO::FS if (!::ReadFile(fileHandle, &buffer[offset], blockSize, &read, NULL)) { - LogWarn("ReadFile IO Error: 0x{:x} {}", GetLastError(), path); + AuLogWarn("ReadFile IO Error: 0x{:x} {}", GetLastError(), path); SysPushErrorIO(); goto out; } @@ -151,36 +166,78 @@ namespace Aurora::IO::FS AUKN_SYM bool FileExists(const AuString &path) { - DWORD dwAttrib = GetFileAttributesW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str()); - return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && - !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); + try + { + DWORD dwAttrib = GetFileAttributesW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str()); + return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && + !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); + } + catch (...) + { + return false; + } } AUKN_SYM bool DirExists(const AuString &path) { - DWORD dwAttrib = GetFileAttributesW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str()); - return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && - (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); + try + { + DWORD dwAttrib = GetFileAttributesW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str()); + return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && + (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); + } + catch (...) + { + return false; + } } AUKN_SYM bool DirMk(const AuString &path) { - return CreateDirectories(NormalizePathRet(path), false); + try + { + return CreateDirectories(NormalizePathRet(path), false); + } + catch (...) + { + return false; + } } AUKN_SYM bool Remove(const AuString &path) { - return DeleteFileW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str()); + try + { + return DeleteFileW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str()); + } + catch (...) + { + return false; + } } AUKN_SYM bool Relink(const AuString &src, const AuString &dest) { - return MoveFileW(Locale::ConvertFromUTF8(NormalizePathRet(src)).c_str(), Locale::ConvertFromUTF8(NormalizePathRet(dest)).c_str()); + try + { + return MoveFileW(Locale::ConvertFromUTF8(NormalizePathRet(src)).c_str(), Locale::ConvertFromUTF8(NormalizePathRet(dest)).c_str()); + } + catch (...) + { + return false; + } } AUKN_SYM bool Copy(const AuString &src, const AuString &dest) { - return CopyFileW(Locale::ConvertFromUTF8(NormalizePathRet(src)).c_str(), Locale::ConvertFromUTF8(NormalizePathRet(dest)).c_str(), true); + try + { + return CopyFileW(Locale::ConvertFromUTF8(NormalizePathRet(src)).c_str(), Locale::ConvertFromUTF8(NormalizePathRet(dest)).c_str(), true); + } + catch (...) + { + return false; + } } AUKN_SYM bool StatFile(const AuString &path, Stat &stat) diff --git a/Source/IO/FS/FS.hpp b/Source/IO/FS/FS.hpp index c37c167d..89d08095 100644 --- a/Source/IO/FS/FS.hpp +++ b/Source/IO/FS/FS.hpp @@ -43,44 +43,65 @@ namespace Aurora::IO::FS static void NormalizePath(AuString &str) { - _NormalizePath(str); + try + { + _NormalizePath(str); + } + catch (...) + { + str = {}; + } } - static inline AuString NormalizePathRet(const AuString &str) + static auline AuString NormalizePathRet(const AuString &str) { - AuString ret = str; - _NormalizePath(ret); - return ret; + try + { + AuString ret = str; + _NormalizePath(ret); + return ret; + } + catch (...) + { + return {}; + } } bool _MkDir(const AuString &str); static bool CreateDirectories(const AuString &cpath, bool isFile) { - for (int i = 0; i < cpath.size(); i++) + try { - bool end = i == cpath.size() - 1; - if ((cpath[i] == kPathSplitter) || - ((!isFile) && (end))) + for (int i = 0; i < cpath.size(); i++) { - auto subpath = end ? cpath : AuString(cpath.begin(), cpath.begin() + i); - - if (DirExists(subpath)) + bool end = i == cpath.size() - 1; + if ((cpath[i] == kPathSplitter) || + ((!isFile) && (end))) { - continue; - } + auto subpath = end ? cpath : AuString(cpath.begin(), cpath.begin() + i); - if (!_MkDir(subpath)) - { - if (!DirExists(subpath)) // copium. im worried :( + if (DirExists(subpath)) { - return false; // ...aw shit + continue; + } + + if (!_MkDir(subpath)) + { + if (!DirExists(subpath)) // copium. im worried :( + { + return false; // ...aw shit + } } } } - } - return true; + return true; + } + catch (...) + { + return false; + } } static bool IterateDirEntriesSTL(const AuString &path, bool filesOnly, AuList &patches) diff --git a/Source/IO/FS/FileStream.Generic.cpp b/Source/IO/FS/FileStream.Generic.cpp index ece361d8..01c55d47 100644 --- a/Source/IO/FS/FileStream.Generic.cpp +++ b/Source/IO/FS/FileStream.Generic.cpp @@ -189,7 +189,7 @@ namespace Aurora::IO::FS } catch (...) { - LogWarn("Couldn't flush file stream"); + AuLogWarn("Couldn't flush file stream"); } } }; diff --git a/Source/IO/FS/FileStream.NT.cpp b/Source/IO/FS/FileStream.NT.cpp index b7e03213..c1827cbd 100644 --- a/Source/IO/FS/FileStream.NT.cpp +++ b/Source/IO/FS/FileStream.NT.cpp @@ -39,7 +39,7 @@ namespace Aurora::IO::FS if (SetFilePointerEx(handle_, distance, &pos, FILE_CURRENT) == INVALID_SET_FILE_POINTER) { - LogWarn("SetFilePointerEx IO Error: 0x{:x}, {}", GetLastError(), path_); + AuLogWarn("SetFilePointerEx IO Error: 0x{:x}, {}", GetLastError(), path_); SysPushErrorIO(); return 0; } @@ -62,7 +62,7 @@ namespace Aurora::IO::FS if (SetFilePointerEx(handle_, distance, &pos, FILE_CURRENT) == INVALID_SET_FILE_POINTER) { - LogWarn("SetFilePointerEx IO Error: 0x{:x}, {}", GetLastError(), path_); + AuLogWarn("SetFilePointerEx IO Error: 0x{:x}, {}", GetLastError(), path_); SysPushErrorIO(); return false; } @@ -107,7 +107,7 @@ namespace Aurora::IO::FS if (!::ReadFile(handle_, reinterpret_cast(parameters.ptr) + offset, blockSize, &read, NULL)) { - LogWarn("ReadFile IO Error: 0x{:x}, {}", GetLastError(), path_); + AuLogWarn("ReadFile IO Error: 0x{:x}, {}", GetLastError(), path_); SysPushErrorIO(); return false; } @@ -148,7 +148,7 @@ namespace Aurora::IO::FS if (!::WriteFile(handle_, reinterpret_cast(parameters.ptr) + offset, blockSize, &written, NULL)) { - LogWarn("WriteFileEx IO Error: 0x{:x}, {}", GetLastError(), path_); + AuLogWarn("WriteFileEx IO Error: 0x{:x}, {}", GetLastError(), path_); SysPushErrorIO(); return false; } @@ -196,36 +196,52 @@ namespace Aurora::IO::FS static IFileStream *OpenNew(const AuString &path, bool read) { - auto pathex = NormalizePathRet(path); - auto win32Path = Locale::ConvertFromUTF8(pathex); + try + { + auto pathex = NormalizePathRet(path); + if (pathex.empty()) + { + return nullptr; + } - HANDLE fileHandle; - if (read) - { - fileHandle = CreateFileW(win32Path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - } - else - { - CreateDirectories(pathex, true); - fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - } + auto win32Path = Locale::ConvertFromUTF8(pathex); + if (win32Path.empty()) + { + return nullptr; + } - if (fileHandle == INVALID_HANDLE_VALUE) + HANDLE fileHandle; + if (read) + { + fileHandle = CreateFileW(win32Path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } + else + { + CreateDirectories(pathex, true); + fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + } + + if (fileHandle == INVALID_HANDLE_VALUE) + { + AuLogWarn("Missing file: {}", path); + SysPushErrorIO("Missing file: {}", path); + return nullptr; + } + + auto stream = _new WinFileStream(); + if (!stream) + { + CloseHandle(fileHandle); + return nullptr; + } + + stream->Init(fileHandle, pathex); + return stream; + } + catch (...) { - LogWarn("Missing file: {}", path); - SysPushErrorIO("Missing file: {}", path); return nullptr; } - - auto stream = _new WinFileStream(); - if (!stream) - { - CloseHandle(fileHandle); - return nullptr; - } - - stream->Init(fileHandle, pathex); - return stream; } AUKN_SYM IFileStream *OpenReadNew(const AuString &path) diff --git a/Source/IO/FS/Resources.cpp b/Source/IO/FS/Resources.cpp index 5cab7009..c975c15d 100644 --- a/Source/IO/FS/Resources.cpp +++ b/Source/IO/FS/Resources.cpp @@ -61,7 +61,7 @@ namespace Aurora::IO::FS if (fileName.find("..") != AuString::npos) { - LogWarn("Exploit Attempt? A system resource path may not contain relative directory move tokens: {}", fileName); + AuLogWarn("Exploit Attempt? A system resource path may not contain relative directory move tokens: {}", fileName); return false; } diff --git a/Source/Locale/Encoding/EncoderIConv.cpp b/Source/Locale/Encoding/EncoderIConv.cpp index 6cf7c8c4..dd739f2b 100644 --- a/Source/Locale/Encoding/EncoderIConv.cpp +++ b/Source/Locale/Encoding/EncoderIConv.cpp @@ -10,3 +10,14 @@ #include "Encoding.hpp" #include "EncoderIConv.hpp" +namespace Aurora::Locale::Encoding +{ + static void SanitizeIConvCharset(AuString &str) + { + if (AuStartsWith(str, "MS-")) + str = "WINDOWS-" + str.substr(3); + else if (AuToUpper(str) == AuToUpper("Latin-1")) + str = "LATIN1"; + else str = AuToUpper(str); + } +} \ No newline at end of file diff --git a/Source/Locale/Encoding/Encoding.cpp b/Source/Locale/Encoding/Encoding.cpp index 37bd4864..9f579e7e 100644 --- a/Source/Locale/Encoding/Encoding.cpp +++ b/Source/Locale/Encoding/Encoding.cpp @@ -11,7 +11,7 @@ namespace Aurora::Locale::Encoding { - AUKN_SYM BOM DecodeBOM(const AuMemoryViewRead & binary) + AUKN_SYM BOM DecodeBOM(const AuMemoryViewRead &binary) { #define ADD_PATTERN(str, code) {str, {ECodePage::code, AuArraySize(str) - 1}} AuList> bows = diff --git a/Source/Locale/Locale.cpp b/Source/Locale/Locale.cpp index 1fd576d8..d9b97b2a 100644 --- a/Source/Locale/Locale.cpp +++ b/Source/Locale/Locale.cpp @@ -32,49 +32,77 @@ namespace Aurora::Locale AUKN_SYM AuString ConvertFromWChar(const wchar_t *in) { - return ConvertFromWChar(in, wcslen(in)); + try + { + return ConvertFromWChar(in, wcslen(in)); + } + catch (...) + { + SysPushErrorMem("ConvertFromWChar failed"); + return {}; + } } AUKN_SYM AuString ConvertFromWChar(const wchar_t *in, AuMach length) { - #if defined(AU_HAS_MSFT_NATIONALLANGSUPPORT) - AuString ret; - auto chars = WideCharToMultiByte(CP_UTF8, 0, in, length, NULL, 0, NULL, NULL); - - if (!chars) + try { - return {}; - } + #if defined(AU_HAS_MSFT_NATIONALLANGSUPPORT) + AuString ret; + auto chars = WideCharToMultiByte(CP_UTF8, 0, in, length, NULL, 0, NULL, NULL); - ret.resize(chars); - WideCharToMultiByte(CP_UTF8, 0, in, length, ret.data(), ret.size(), NULL, NULL); - return ret; - #elif !defined(AU_NO_CPPLOCALE) - return gUtf8Conv.to_bytes(std::wstring(in, wcslen(in))); - #else - return false; - #endif + if (!chars) + { + return {}; + } + + ret.resize(chars); + WideCharToMultiByte(CP_UTF8, 0, in, length, ret.data(), ret.size(), NULL, NULL); + return ret; + #elif !defined(AU_NO_CPPLOCALE) + return gUtf8Conv.to_bytes(std::wstring(in, wcslen(in))); + #else + SysPushErrorUnimplemented("ConvertFromWChar"); + return {}; + #endif + } + catch (...) + { + SysPushErrorMem("ConvertFromWChar failed"); + Debug::CheckErrors(); + } + return {}; } AUKN_SYM std::wstring ConvertFromUTF8(const AuString &in) { - #if defined(AU_HAS_MSFT_NATIONALLANGSUPPORT) - std::wstring ret; - auto chars = MultiByteToWideChar(CP_UTF8, 0, in.c_str(), in.length(), NULL, 0); - - if (!chars) + try { - return {}; - } + #if defined(AU_HAS_MSFT_NATIONALLANGSUPPORT) + std::wstring ret; + auto chars = MultiByteToWideChar(CP_UTF8, 0, in.c_str(), in.length(), NULL, 0); - ret.resize(chars); - MultiByteToWideChar(CP_UTF8, 0, in.c_str(), in.length(), ret.data(), ret.size()); - return ret; - #elif !defined(AU_NO_CPPLOCALE) - return gUtf8Conv.from_bytes(in); - #else - return false; - #endif + if (!chars) + { + return {}; + } + + ret.resize(chars); + MultiByteToWideChar(CP_UTF8, 0, in.c_str(), in.length(), ret.data(), ret.size()); + return ret; + #elif !defined(AU_NO_CPPLOCALE) + return gUtf8Conv.from_bytes(in); + #else + SysPushErrorUnimplemented("ConvertFromUTF8"); + return {}; + #endif + } + catch (...) + { + SysPushErrorMem("ConvertFromUTF8 failed"); + Debug::CheckErrors(); + } + return {}; } ECodePage GetInternalCodePage() @@ -214,9 +242,9 @@ namespace Aurora::Locale if (locale == "C") { - LogWarn("Improperly configured UNIX environment."); - LogWarn("This localization detection code was written in 2020, please follow the `language[_territory][.codeset][@modifier]` convention for user/sys locales."); - LogWarn("'C' is not a language, country, or anything with which we can discern anything meaningful from. Fix your scuffed unix operating system and try again later..."); + AuLogWarn("Improperly configured UNIX environment."); + AuLogWarn("This localization detection code was written in 2020, please follow the `language[_territory][.codeset][@modifier]` convention for user/sys locales."); + AuLogWarn("'C' is not a language, country, or anything with which we can discern anything meaningful from. Fix your scuffed unix operating system and try again later..."); SysPanic("You fools"); } @@ -229,8 +257,8 @@ namespace Aurora::Locale } else { - LogWarn("Improperly configured UNIX environment."); - LogWarn("Couldn't discern language from localization string: {}", locale); + AuLogWarn("Improperly configured UNIX environment."); + AuLogWarn("Couldn't discern language from localization string: {}", locale); SysPanic("You fools"); } @@ -343,9 +371,9 @@ namespace Aurora::Locale gLanguageCode = AuToLower(gLanguageCode); gCountryCode = AuToUpper(gCountryCode); - gCodeset = AuToUpper(gCodeset); + gCodeset = gCodeset; - LogDbg("Initialized default localization information (language: {}, country: {}, codeset: {})", gLanguageCode, gCountryCode, gCodeset); + AuLogDbg("Initialized default localization information (language: {}, country: {}, codeset: {})", gLanguageCode, gCountryCode, gCodeset); } static bool gLockLocale = false; diff --git a/Source/Locale/LocaleStrings.cpp b/Source/Locale/LocaleStrings.cpp new file mode 100644 index 00000000..d29af3a0 --- /dev/null +++ b/Source/Locale/LocaleStrings.cpp @@ -0,0 +1,183 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: LocaleStrings.cpp + Date: 2022-1-23 + Author: Reece +***/ +#include +#include "LocaleStrings.hpp" + +namespace Aurora::Locale +{ + AUKN_SYM AuString NumbericLocaleGetDecimal() + { + return "."; //for.now + } + + AUKN_SYM AuString TimeLocaleGetDayChar() + { + return "d"; //for.now + } + + AUKN_SYM AuString TimeLocaleS() + { + return "s"; + } + + AUKN_SYM AuString TimeLocaleGetMSChar() + { + return "ms"; //for.now + } + + static AuString &_TextPrepadZeroIfOne(AuString &in) + { + if (in.size() == 1) in.insert(in.begin(), '0'); + return in; + } + + static AuString _TextPrepadZeroIfOne(const AuString &in) + { + AuString ret = in; + if (ret.size() == 1) ret.insert(ret.begin(), '0'); + return ret; + } + + static AuString _TextPrepadZeroMS(const AuString &in) + { + AuString ret = in; + if (ret.size() == 1) ret.insert(0, "000", 3); + else if (ret.size() == 2) ret.insert(0, "000", 2); + else if (ret.size() == 3) ret.insert(0, "000", 1); + while (ret.size() > 1 && ret[ret.size() - 1] == '0') + ret.pop_back(); + return ret; + } + + static AuString _TextPrepadZeroNS(const AuString &in) + { + AuString ret = in; + switch (ret.size()) + { + case 1: ret.insert(0, "000000", 6); break; + case 2: ret.insert(0, "000000", 5); break; + case 3: ret.insert(0, "000000", 4); break; + case 4: ret.insert(0, "000000", 3); break; + case 5: ret.insert(0, "000000", 2); break; + case 6: ret.insert(0, "000000", 1); break; + } + while (ret.size() > 1 && ret[ret.size() - 1] == '0') + ret.pop_back(); + return ret; + } + + AUKN_SYM AuString ConvertMSToTimescale(AuUInt32 ms) + { + const auto msDiv1000 = ms / 1000; // seconds + const auto msDiv1000Mod60 = msDiv1000 % 60; // remaining seconds relative to next whole minute + const auto msDiv1000Div60 = msDiv1000 / 60; // total minutes + + try + { + if (ms < 1000) + { + return AuToString(ms) + TimeLocaleGetMSChar(); + } + else if (ms < (1000 * 60)) + { + auto s = msDiv1000; + auto remMs = ms % 1000; + return _TextPrepadZeroIfOne(AuToString(s)) + NumbericLocaleGetDecimal() + _TextPrepadZeroMS(AuToString(remMs)) + TimeLocaleS(); + } + else if (ms < (1000 * 60 * 60)) + { + auto m = msDiv1000Div60; + auto remS = msDiv1000Mod60; + return _TextPrepadZeroIfOne(AuToString(m)) + ":" + _TextPrepadZeroIfOne(AuToString(remS)); + } + else if (ms < (1000 * 60 * 60 * 24)) + { + auto h = msDiv1000Div60 / 60; + auto remM = msDiv1000Div60; + auto remS = msDiv1000Mod60; + + return _TextPrepadZeroIfOne(AuToString(h)) + ":" + _TextPrepadZeroIfOne(AuToString(remM)) + ":" + _TextPrepadZeroIfOne(AuToString(remS)); + } + else + { + auto d = (msDiv1000Div60 / 60 / 24); + auto h = (msDiv1000Div60 / 60) - (d * 24); + auto remM = msDiv1000Div60; + auto remS = msDiv1000Mod60; + return AuToString(d) + TimeLocaleGetDayChar() + " " + _TextPrepadZeroIfOne(AuToString(h)) + ":" + _TextPrepadZeroIfOne(AuToString(remM)) + ":" + _TextPrepadZeroIfOne(AuToString(remS)); + } + } + catch (...) + { + SysPushErrorGeneric("ConvertNSToTimescale failed -> returning empty string"); + return {}; + } + } + + AUKN_SYM AuString ConvertNSToTimescale(AuUInt64 ns) + { + try + { + if (ns < AuUInt64(1000000000)) + { + const auto ms = ns / 1000000; + const auto remNs = ns % 1000000; + return _TextPrepadZeroMS(AuToString(ms)) + NumbericLocaleGetDecimal() + _TextPrepadZeroNS(AuToString(remNs)) + TimeLocaleGetMSChar(); + } + else + { + return ConvertMSToTimescale(ns / AuUInt64(1000000000)); + } + } + catch (...) + { + SysPushErrorGeneric("ConvertNSToTimescale failed -> returning empty string"); + return {}; + } + } + + AUKN_SYM AuString TimeDateToString(const Time::tm &time) + { + try + { + bool simple = time.tm_mday == 0 && time.tm_mon == 0 && time.tm_year == 0; + if (simple) + { + return fmt::format("{:02}-{:02}-{:02}", time.tm_hour, time.tm_min, time.tm_sec); + } + else + { + // Hard-code ISO-8601 locale because, the larders locale doesn't make any sense whatsoever, and east asia has the right idea + // EU users and burgers seethe... we normalize one standard to disambiguate this shit + return fmt::format("{:{:04}-{:02}-{:02} {:02}-{:02}-{:02}}", time.tm_year + 1900, time.tm_mon + 1, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec); + } + } + catch (...) + { + SysPushErrorGeneric("TimeDateToString failed -> returning empty string"); + return {}; + } + } + + AUKN_SYM AuString TimeDateToISO8601(const Time::tm &time, AuTime::ETimezoneShift shift) + { + try + { + AuString tz {}; + auto tnorm = AuTime::NormalizeCivilTimezone(time, shift); + return fmt::format("{:04}-{:02}-{:02}T{:02}-{:02}-{:02}Z", + tnorm.tm_year + 1900, tnorm.tm_mon + 1, tnorm.tm_mday, + tnorm.tm_hour, tnorm.tm_min, tnorm.tm_sec); + } + catch (...) + { + SysPushErrorGeneric("TimeDateToISO8601 failed -> returning empty string"); + return {}; + } + } +} \ No newline at end of file diff --git a/Source/Locale/LocaleStrings.hpp b/Source/Locale/LocaleStrings.hpp new file mode 100644 index 00000000..53467034 --- /dev/null +++ b/Source/Locale/LocaleStrings.hpp @@ -0,0 +1,8 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: LocaleStrings.hpp + Date: 2022-1-23 + Author: Reece +***/ +#pragma once \ No newline at end of file diff --git a/Source/Loop/LSMutex.NT.cpp b/Source/Loop/LSMutex.NT.cpp index 64c1c035..1d77f488 100644 --- a/Source/Loop/LSMutex.NT.cpp +++ b/Source/Loop/LSMutex.NT.cpp @@ -36,11 +36,6 @@ namespace Aurora::Loop return {}; } - if (!(ret = AuMakeShared(mutex))) - { - return {}; - } - - return ret; + return AuMakeShared(mutex); } } \ No newline at end of file diff --git a/Source/Loop/LSSemaphore.NT.cpp b/Source/Loop/LSSemaphore.NT.cpp index 394d85d5..43d4aff0 100644 --- a/Source/Loop/LSSemaphore.NT.cpp +++ b/Source/Loop/LSSemaphore.NT.cpp @@ -37,11 +37,6 @@ namespace Aurora::Loop return {}; } - if (!(ret = AuMakeShared(mutex))) - { - return {}; - } - - return ret; + return AuMakeShared(mutex); } } \ No newline at end of file diff --git a/Source/Loop/Loop.NT.cpp b/Source/Loop/Loop.NT.cpp index 2fc938ba..70f453b9 100644 --- a/Source/Loop/Loop.NT.cpp +++ b/Source/Loop/Loop.NT.cpp @@ -19,36 +19,43 @@ namespace Aurora::Loop AuList handleArray; AuSPtr msgSource; - isWinLoop = false; - loopSourceExs.reserve(objects.size()); - handleArray.reserve(objects.size()); - triggered.reserve(triggered.size()); - - for (const auto &source : objects) + try { - if (!source) - { - continue; - } - - if (source->GetType() == ELoopSource::eSourceWin32) - { - isWinLoop = true; - msgSource = source; - continue; - } + isWinLoop = false; + loopSourceExs.reserve(objects.size()); + handleArray.reserve(objects.size()); + triggered.reserve(triggered.size()); - if (auto extended = std::dynamic_pointer_cast(source)) + for (const auto &source : objects) { - loopSourceExs.push_back(extended); - for (const auto &handle : extended->GetHandles()) + if (!source) { - auto nthandle = reinterpret_cast(handle); - handleArray.push_back(nthandle); + continue; + } + + if (source->GetType() == ELoopSource::eSourceWin32) + { + isWinLoop = true; + msgSource = source; + continue; + } + + if (auto extended = std::dynamic_pointer_cast(source)) + { + loopSourceExs.push_back(extended); + for (const auto &handle : extended->GetHandles()) + { + auto nthandle = reinterpret_cast(handle); + handleArray.push_back(nthandle); + } } } } - + catch (...) + { + return {}; + } + for (const auto &source : loopSourceExs) { source->OnPresleep(); @@ -100,7 +107,7 @@ namespace Aurora::Loop if (source->OnTrigger(lastHandle, wasTriggered)) { - triggered.push_back(source); + AuTryInsert(triggered, source); } } @@ -109,7 +116,7 @@ namespace Aurora::Loop if (isPump) { - triggered.push_back(msgSource); + AuTryInsert(triggered, msgSource); } return triggered; diff --git a/Source/Loop/WaitSingle.NT.cpp b/Source/Loop/WaitSingle.NT.cpp index efed9018..8f706dcf 100644 --- a/Source/Loop/WaitSingle.NT.cpp +++ b/Source/Loop/WaitSingle.NT.cpp @@ -20,7 +20,7 @@ namespace Aurora::Loop if (handles.size() == 1) { - return WaitForSingleObject(reinterpret_cast(handles.at(0)), 0) == WAIT_OBJECT_0; + return WaitForSingleObjectEx(reinterpret_cast(handles.at(0)), 0, true) == WAIT_OBJECT_0; } else { @@ -30,7 +30,7 @@ namespace Aurora::Loop { ntHandles.push_back(reinterpret_cast(handle)); } - return WaitForMultipleObjects(ntHandles.size(), ntHandles.data(), false, 0) >= WAIT_OBJECT_0; + return WaitForMultipleObjectsEx(ntHandles.size(), ntHandles.data(), false, 0, true) >= WAIT_OBJECT_0; } } diff --git a/Source/Memory/Heap.cpp b/Source/Memory/Heap.cpp index bdc186d7..3deef2f0 100644 --- a/Source/Memory/Heap.cpp +++ b/Source/Memory/Heap.cpp @@ -244,8 +244,8 @@ namespace Aurora::Memory if (count_) { - LogWarn("Heap life was less than its allocations, waiting for final free"); - LogWarn("Reporting using mayday!"); + AuLogWarn("Heap life was less than its allocations, waiting for final free"); + AuLogWarn("Reporting using mayday!"); Telemetry::Mayday(); isDangling_ = true; diff --git a/Source/Parse/Base32.cpp b/Source/Parse/Base32.cpp index 7123d08c..70509822 100644 --- a/Source/Parse/Base32.cpp +++ b/Source/Parse/Base32.cpp @@ -23,7 +23,7 @@ namespace Aurora::Parse } catch (...) { - Console::Logging::LogWarn("Decoding error: {}", in); + AuLogWarn("Decoding error: {}", in); Debug::PrintError(); return false; } @@ -41,7 +41,7 @@ namespace Aurora::Parse } catch (...) { - Console::Logging::LogWarn("Encoding error"); + AuLogWarn("Encoding error"); Debug::PrintError(); return false; } diff --git a/Source/Parse/Base64.cpp b/Source/Parse/Base64.cpp index 88303ed0..14d36710 100644 --- a/Source/Parse/Base64.cpp +++ b/Source/Parse/Base64.cpp @@ -33,7 +33,7 @@ namespace Aurora::Parse } catch (...) { - Console::Logging::LogWarn("Decoding error: {}", in); + AuLogWarn("Decoding error: {}", in); Debug::PrintError(); return false; } @@ -61,7 +61,7 @@ namespace Aurora::Parse } catch (...) { - Console::Logging::LogWarn("Encoding error"); + AuLogWarn("Encoding error"); Debug::PrintError(); return false; } diff --git a/Source/Parse/Parser.cpp b/Source/Parse/Parser.cpp index 708275e9..a33a04a2 100644 --- a/Source/Parse/Parser.cpp +++ b/Source/Parse/Parser.cpp @@ -196,11 +196,11 @@ namespace Aurora::Parse //SysAssert(!stringLevel, "Parsed tag of string type must end with \", got {}", out); if (stringLevel) { - LogWarn("Parsed tag of string type must end with \", got {}", out); + AuLogWarn("Parsed tag of string type must end with \", got {}", out); return false; } - //Aurora::Console::Logging::LogDbg("returned {} {}", out, count != 0); + //AuLogDbg("returned {} {}", out, count != 0); return out.size() != 0; } @@ -369,7 +369,7 @@ namespace Aurora::Parse uuid = uuids::uuid::from_string(str); if (!uuid.has_value()) { - LogWarn("Parse Error: invalid UUID {}", str); + AuLogWarn("Parse Error: invalid UUID {}", str); return false; } out.UUID = uuid.value(); @@ -387,7 +387,7 @@ namespace Aurora::Parse } else { - Aurora::Console::Logging::LogWarn("Parsed tag of boolean type wasn't parsable given the English string {}", str); + AuLogWarn("Parsed tag of boolean type wasn't parsable given the English string {}", str); return false; } break; @@ -457,7 +457,7 @@ namespace Aurora::Parse if (!ConsumeToken(state, context, ParsableTag::kParseUInt, arrayLengthBit)) { - Aurora::Console::Logging::LogWarn("Couldn't consume array length, label: {}, tag {}", parseBit.label, parseBit.tag); + AuLogWarn("Couldn't consume array length, label: {}, tag {}", parseBit.label, parseBit.tag); return false; } @@ -505,7 +505,7 @@ namespace Aurora::Parse break; } - Aurora::Console::Logging::LogWarn("Syntax error around: label: {}, tag {}", parseBit.label, parseBit.tag); + AuLogWarn("Syntax error around: label: {}, tag {}", parseBit.label, parseBit.tag); return false; } diff --git a/Source/Process/Paths.cpp b/Source/Process/Paths.cpp index 872794f5..b4543cff 100644 --- a/Source/Process/Paths.cpp +++ b/Source/Process/Paths.cpp @@ -122,7 +122,7 @@ namespace Aurora::Process for (const auto &name : procFsPaths) { - if (Aurora::IO::FS::ReadString(name, path)) + if (AuIOFS::ReadString(name, path)) { splitter = '/'; return true; @@ -138,8 +138,11 @@ namespace Aurora::Process { static AuString cachedModule, cachedPartialPath, cachedFullPath; static bool init = false; + static AuThreadPrimitives::SpinLock spinlock; char spitter; + AU_TRY_LOCK_GUARD_RET_DEF(spinlock); + if (AuExchange(init, true)) { if (!cachedModule.size()) @@ -178,13 +181,20 @@ namespace Aurora::Process { AuString module, partial, full; - if (!GetModulePath(module, partial, full)) + try + { + if (!GetModulePath(module, partial, full)) + { + return false; + } + + executable = module; + } + catch (...) { return false; } - executable = module; - return true; } @@ -192,18 +202,25 @@ namespace Aurora::Process { AuString module, partial, full; - if (!GetModulePath(module, partial, full)) + try + { + if (!GetModulePath(module, partial, full)) + { + return false; + } + + path = partial; + + if (path.empty()) + { + return GetWorkingDirectory(path); + } + } + catch (...) { return false; } - path = partial; - - if (path.empty()) - { - return GetWorkingDirectory(path); - } - return true; } @@ -211,13 +228,20 @@ namespace Aurora::Process { AuString module, partial, full; - if (!GetModulePath(module, partial, full)) + try + { + if (!GetModulePath(module, partial, full)) + { + return false; + } + + path = full; + } + catch (...) { return false; } - path = full; - return true; } } \ No newline at end of file diff --git a/Source/Process/Process.cpp b/Source/Process/Process.cpp index 875fee73..944e12bf 100644 --- a/Source/Process/Process.cpp +++ b/Source/Process/Process.cpp @@ -23,6 +23,8 @@ #include #include +#include "ProcessMap.hpp" + namespace Aurora::Process { static AuThreadPrimitives::SpinLock gSpinLock; @@ -265,7 +267,7 @@ namespace Aurora::Process { fail = false; - auto pathNrml = IO::FS::NormalizePathRet(path); + auto pathNrml = AuIOFS::NormalizePathRet(path); #if defined(AURORA_IS_MODERNNT_DERIVED) auto widePath = Locale::ConvertFromUTF8(pathNrml); @@ -278,7 +280,7 @@ namespace Aurora::Process return false; } - auto absPath = IO::FS::NormalizePathRet(abs); + auto absPath = AuIOFS::NormalizePathRet(abs); #endif if (request.verify || (kIsMainSigned || request.enableMitigations)) @@ -292,7 +294,7 @@ namespace Aurora::Process return false; } #else - LogWarn("Can't verify {} on this platform", path); + AuLogWarn("Can't verify {} on this platform", path); #endif } @@ -342,7 +344,7 @@ namespace Aurora::Process AuString bAbs = path + "/" + genericDll + "."; #endif - if (Aurora::IO::FS::FileExists(a)) + if (AuIOFS::FileExists(a)) { return TryLoadModule(a, #if defined(AURORA_IS_MODERNNT_DERIVED) @@ -353,7 +355,7 @@ namespace Aurora::Process ); } - if (Aurora::IO::FS::FileExists(b)) + if (AuIOFS::FileExists(b)) { return TryLoadModule(b, #if defined(AURORA_IS_MODERNNT_DERIVED) @@ -382,15 +384,15 @@ namespace Aurora::Process break; case EModulePath::eModulePathSystemDir: - pathA = IO::FS::GetSystemLibPath().value_or(AuString {}); - pathB = IO::FS::GetSystemLibPath2().value_or(AuString {}); + pathA = AuIOFS::GetSystemLibPath().value_or(AuString {}); + pathB = AuIOFS::GetSystemLibPath2().value_or(AuString {}); if (pathA.empty()) return false; break; case EModulePath::eModulePathUserDir: - pathA = IO::FS::GetUserLibPath().value_or(AuString {}); - pathB = IO::FS::GetUserLibPath2().value_or(AuString {}); + pathA = AuIOFS::GetUserLibPath().value_or(AuString {}); + pathB = AuIOFS::GetUserLibPath2().value_or(AuString {}); if (pathA.empty()) return false; @@ -532,6 +534,16 @@ namespace Aurora::Process #endif } - // TODO (reece): init, deinit - // TODO (reece): test if self is signed + + void InitProcess() + { + // TODO (reece): test if self is signed -> xref kIsMainSigned + + InitProcessMap(); + } + + void DeinitProcess() + { + DeinitProcessMap(); + } } \ No newline at end of file diff --git a/Source/Process/Process.hpp b/Source/Process/Process.hpp index db780384..08e175c0 100644 --- a/Source/Process/Process.hpp +++ b/Source/Process/Process.hpp @@ -9,5 +9,6 @@ namespace Aurora::Process { - + void InitProcess(); + void DeinitProcess(); } \ No newline at end of file diff --git a/Source/Process/ProcessMap.NT.cpp b/Source/Process/ProcessMap.NT.cpp new file mode 100644 index 00000000..28045c29 --- /dev/null +++ b/Source/Process/ProcessMap.NT.cpp @@ -0,0 +1,306 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: UtilProcessMap.NT.cpp + Date: 2022-1-24 + Author: Reece +***/ +#include +#include "ProcessMap.NT.hpp" +#include "ProcessMap.hpp" + +namespace Aurora::Process +{ + static AuThreadPrimitives::MutexUnique_t gMutex; + static AuBST gPathCache; + static AuBST gModNameCache; + + AuString ModuleToSomething(HMODULE handle, bool path) + { + try + { + std::wstring file; + + if (!handle) + { + return {}; + } + + if (gMutex) + { + AU_LOCK_GUARD(gMutex); + if (path) + { + auto itr = gPathCache.find(reinterpret_cast(handle)); + if (itr != gPathCache.end()) return itr->second; + } + else + { + auto itr = gModNameCache.find(reinterpret_cast(handle)); + if (itr != gModNameCache.end()) return itr->second; + } + } + + if (!AuTryResize(file, 16 * 1024)) + { + return {}; + } + + auto length = GetModuleFileNameW(handle, &file[0], file.size()); + if (!length) + { + return {}; + } + + file.resize(length); + + if (!path) + { + auto idx = file.find_last_of('\\'); + if (idx != std::wstring::npos) + { + file = file.substr(idx + 1); + } + } + + auto ret = Locale::ConvertFromWChar(file.c_str(), file.length()); + + if (gMutex) + { + AU_LOCK_GUARD(gMutex); + if (path) + { + AuTryInsert(gPathCache, AuMakePair(reinterpret_cast(handle), ret)); + } + else + { + AuTryInsert(gModNameCache, AuMakePair(reinterpret_cast(handle), ret)); + } + } + + return ret; + } + catch (...) + { + return ""; + } + } + + AuString ModuleToName(HMODULE handle) + { + return ModuleToSomething(handle, false); + } + + AuString ModuleToPath(HMODULE handle) + { + return ModuleToSomething(handle, true); + } + + static AuUInt GetModuleBaseAddressFromPathGrossYesThisIsCached(HMODULE mod, const AuString &path) + { + if (path.empty()) + { + return 0; + } + + auto dosHeader = reinterpret_cast(mod); + auto nt = &(reinterpret_cast(reinterpret_cast(mod) + dosHeader->e_lfanew)->OptionalHeader.ImageBase); + + auto offset = static_cast(reinterpret_cast(nt) - reinterpret_cast(mod)); + using Value_t = AuRemovePointer_t; + Value_t value {}; + + auto handle = CreateFileW(Locale::ConvertFromUTF8(path).c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); + if (handle == INVALID_HANDLE_VALUE) return 0; + + DWORD bytesRead {}; + + if (!SetFilePointer(handle, offset, NULL, 0)) + { + return {}; + } + + if (!ReadFile(handle, &value, sizeof(Value_t), &bytesRead, NULL)) + { + return {}; + } + + if (bytesRead != sizeof(Value_t)) + { + return {}; + } + + CloseHandle(handle); + return value; + } + + static void FetchModuleSegments(Segments &segments, AuUInt offset, HMODULE mod) + { + auto dosHeader = reinterpret_cast(mod); + auto nt = reinterpret_cast(reinterpret_cast(mod) + dosHeader->e_lfanew); + + auto pSection = IMAGE_FIRST_SECTION(nt); + auto pSectionCur = pSection; + + for (auto i = 0; i < nt->FileHeader.NumberOfSections; i++) + { + auto cur = pSectionCur++; + Segment seg; + + seg.origVa = cur->VirtualAddress - reinterpret_cast(mod) + offset; + seg.baseVa = cur->VirtualAddress; + seg.size = cur->SizeOfRawData; + seg.fsOff = cur->PointerToRawData; + + seg.pt.readable = cur->Characteristics & (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE); + seg.pt.NX = !(cur->Characteristics & IMAGE_SCN_MEM_EXECUTE); + seg.pt.writable = cur->Characteristics & IMAGE_SCN_MEM_WRITE; + + seg.name = AuString(cur->Name, cur->Name + strnlen(reinterpret_cast(cur->Name), sizeof(cur->Name))); + + AuTryInsert(segments, seg); + } + } + + static AuSPtr HandleToPublicModule(HMODULE h) + { + auto pub = AuMakeShared(); + if (!pub) return {}; + pub->moduleMeta = AuMakeShared(); + if (!pub->moduleMeta) return {}; + + pub->moduleMeta->moduleBase = AuUInt(h); + pub->moduleMeta->moduleName = ModuleToName(h); + pub->moduleMeta->modulePath = ModuleToPath(h); + pub->moduleMeta->origVa = GetModuleBaseAddressFromPathGrossYesThisIsCached(h, pub->moduleMeta->modulePath); + FetchModuleSegments(pub->segments, pub->moduleMeta->origVa, h); + return pub; + } + + void InvaildateModule(HMODULE hmod) + { + if (!gMutex) + { + return; + } + + try + { + // acquire gmutex + { + AU_LOCK_GUARD(gMutex); + auto itr1 = gPathCache.find(reinterpret_cast(hmod)); + if (itr1 != gPathCache.end()) gPathCache.erase(itr1); + + auto itr2 = gModNameCache.find(reinterpret_cast(hmod)); + if (itr2 != gModNameCache.end()) gModNameCache.erase(itr2); + } + + // release lock + { + RemoveModuleCache({"", reinterpret_cast(hmod)}); + } + } + catch (...) + { + + } + } + + bool MakeAwarePtr(AuUInt pointer) + { + HMODULE handle; + if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast(pointer), &handle)) + { + return false; + } + + MakeAware(handle); + return true; + } + + AuOptional LookupArbitrarySegment(AuUInt address) + { + MEMORY_BASIC_INFORMATION info; + Segment segment; + + if (!VirtualQuery((LPCVOID)address, &info, sizeof(info))) + { + return {}; + } + + segment.baseVa = reinterpret_cast(info.BaseAddress); + segment.size = info.RegionSize; + segment.pt.NX = (info.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ)) == 0; + segment.pt.writable = (info.Protect & (PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY)) != 0; + segment.pt.readable = (!segment.pt.NX) && ((info.Protect & (PAGE_NOACCESS)) != 0); + segment.pt.acSanity = info.Protect == PAGE_EXECUTE_WRITECOPY; + return segment; + } + + void MakeAware(HMODULE hmod) + { + ModuleBasePair handle {"", reinterpret_cast(hmod)}; + + if (!gMutex) + { + return; + } + + if (hmod == INVALID_HANDLE_VALUE) + { + SysPushErrorArg(); + return; + } + + if (!hmod) + { + SysPushErrorArg(); + return; + } + + try + { + if (IsInModuleCache(handle)) + { + return; + } + + auto ptr = HandleToPublicModule(hmod); + if (!ptr) + { + return; + } + + InsertModuleCache(handle, ptr); + } + catch (...) + { + + } + } + + PublicModule GetExecutableRoot() + { + try + { + auto handle = GetModuleHandleW(NULL); + MakeAware(handle); + return GetFromModuleCache(reinterpret_cast(handle)); + } + catch (...) + { + return {}; + } + } + + void InitProcessMapNt() + { + gMutex = AuThreadPrimitives::MutexUnique(); + } + + void DeinitProcessMapNt() + { + gMutex.reset(); + } +} \ No newline at end of file diff --git a/Source/Process/ProcessMap.NT.hpp b/Source/Process/ProcessMap.NT.hpp new file mode 100644 index 00000000..9a5de126 --- /dev/null +++ b/Source/Process/ProcessMap.NT.hpp @@ -0,0 +1,25 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: UtilProcessMap.NT.hpp + Date: 2022-1-24 + Author: Reece +***/ +#pragma once + +namespace Aurora::Process +{ + void DeinitProcessMapNt(); + void InitProcessMapNt(); + + AuOptional LookupArbitrarySegment(AuUInt address); + + void InvaildateModule(HMODULE hmod); + void MakeAware(HMODULE hmod); + bool MakeAwarePtr(AuUInt pointer); + + PublicModule GetExecutableRoot(); + + AuString ModuleToName(HMODULE handle); + AuString ModuleToPath(HMODULE handle); +} \ No newline at end of file diff --git a/Source/Process/ProcessMap.Win32.cpp b/Source/Process/ProcessMap.Win32.cpp index 33cc2cd4..09365c70 100644 --- a/Source/Process/ProcessMap.Win32.cpp +++ b/Source/Process/ProcessMap.Win32.cpp @@ -7,47 +7,39 @@ ***/ #include #include "ProcessMap.Win32.hpp" +#include "ProcessMap.NT.hpp" +#include namespace Aurora::Process { - static AuString ModuleToSomething(HMODULE handle, bool path) + void MakeToolHelp32Snapshot() { - std::wstring file; - file.resize(16 * 1024); - - // HMODULE arent handles, they're COFF pointers - if (!handle) + MODULEENTRY32 me32; + HANDLE hModuleSnap = INVALID_HANDLE_VALUE; + + hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); + if (hModuleSnap == INVALID_HANDLE_VALUE) { - return {}; + SysPushErrorGen("CreateToolhelp32Snapshot"); + return; + } + me32.dwSize = sizeof(MODULEENTRY32); + + if (!Module32First(hModuleSnap, &me32)) + { + SysPushErrorGen("Module32First failed"); + CloseHandle(hModuleSnap); + return; } - auto length = GetModuleFileNameW(handle, &file[0], file.size()); - if (!length) + do { - return {}; + auto h = reinterpret_cast(me32.modBaseAddr); + InvaildateModule(h); + MakeAware(h); } + while (Module32Next(hModuleSnap, &me32)); - file.resize(length); - - if (!path) - { - auto idx = file.find_last_of('\\'); - if (idx != std::wstring::npos) - { - file = file.substr(idx + 1); - } - } - - return Locale::ConvertFromWChar(file.c_str(), file.length()); - } - - AuString ModuleToName(HMODULE handle) - { - return ModuleToSomething(handle, false); - } - - AuString ModuleToPath(HMODULE handle) - { - return ModuleToSomething(handle, true); + CloseHandle(hModuleSnap); } } \ No newline at end of file diff --git a/Source/Process/ProcessMap.Win32.hpp b/Source/Process/ProcessMap.Win32.hpp index c2dd0a81..5a8f8ffd 100644 --- a/Source/Process/ProcessMap.Win32.hpp +++ b/Source/Process/ProcessMap.Win32.hpp @@ -9,6 +9,8 @@ namespace Aurora::Process { + void MakeToolHelp32Snapshot(); + AuString ModuleToName(HMODULE handle); AuString ModuleToPath(HMODULE handle); } \ No newline at end of file diff --git a/Source/Process/ProcessMap.cpp b/Source/Process/ProcessMap.cpp new file mode 100644 index 00000000..a233c997 --- /dev/null +++ b/Source/Process/ProcessMap.cpp @@ -0,0 +1,225 @@ +#include +#include "ProcessMap.hpp" + +#if defined(AURORA_PLATFORM_WIN32) + #include "ProcessMap.Win32.hpp" +#endif + +#if defined(AURORA_IS_MODERNNT_DERIVED) + #include "ProcessMap.NT.hpp" +#endif + +namespace Aurora::Process +{ + struct ModuleBasePairUtil + { + AuUInt operator()(const ModuleBasePair &in) const + { + return in.modBase; + } + + constexpr bool operator()(const ModuleBasePair &lhs, const AuString &rhs) const + { + return lhs.module == rhs; + } + + constexpr bool operator()(const ModuleBasePair &lhs, const AuUInt &rhs) const + { + return lhs.modBase == rhs; + } + + constexpr bool operator()(const ModuleBasePair &lhs, const ModuleBasePair &rhs) const + { + return rhs.modBase ? lhs.modBase == rhs.modBase : (rhs.module.size() ? rhs.module == rhs.module : false); + } + }; + + struct ModuleLookup : Segment + { + ModuleLookup() + {} + + ModuleLookup(const Segment &s) : Segment(s) + {} + }; + + static AuBST gModulePtrMap; + + static const auto kMinPageAlignment = 4096; + static const auto kPageBufferPad = 20; + + static AuThreadPrimitives::MutexUnique_t gMutexUnique; + static AuHashMapEx, ModuleBasePairUtil> gModuleMap; + + static AuUInt ToLowestPageAlignment(AuUInt in) + { + return in & ~(kMinPageAlignment - 1); + } + + static AuSPtr GetModuleFromSegmentCache(AuUInt pointer) + { + AU_LOCK_GUARD(gMutexUnique); + auto itr = gModulePtrMap.find(pointer); + if (itr == gModulePtrMap.end()) return {}; + return itr->second.moduleMeta.lock(); + } + + static AuOptional GetSegmentCache(AuUInt pointer) + { + AU_LOCK_GUARD(gMutexUnique); + auto itr = gModulePtrMap.find(pointer); + if (itr == gModulePtrMap.end()) return {}; + return itr->second; + } + + bool IsInModuleCache(const ModuleBasePair &pair) + { + AU_LOCK_GUARD(gMutexUnique); + return gModuleMap.find(pair) != gModuleMap.end(); + } + + void InsertModuleCache(const ModuleBasePair &pair, const AuSPtr &mod) + { + for (auto &segment : mod->segments) + { + AU_LOCK_GUARD(gMutexUnique); + segment.moduleMeta = mod; + + for (AuUInt i = segment.baseVa; i < segment.baseVa + segment.size; i += (kMinPageAlignment * kPageBufferPad)) + { + ModuleLookup a(segment); + gModulePtrMap[i] = a; + } + } + + { + AU_LOCK_GUARD(gMutexUnique); + gModuleMap[pair] = mod; + } + } + + void RemoveModuleCache(const ModuleBasePair &eitherOr) + { + AU_LOCK_GUARD(gMutexUnique); + auto itr = gModuleMap.find(eitherOr); + if (itr == gModuleMap.end()) return; + auto mod = itr->second; + + for (const auto &segment : mod->segments) + { + for (AuUInt i = segment.baseVa; i < segment.baseVa + segment.size; i += (kMinPageAlignment * kPageBufferPad)) + { + auto itr = gModulePtrMap.find(i); + if (itr != gModulePtrMap.end()) + { + gModulePtrMap.erase(itr); + } + } + } + + gModuleMap.erase(itr); + } + + PublicModule GetFromModuleCache(AuUInt handle) + { + AU_LOCK_GUARD(gMutexUnique); + auto itr = gModuleMap.find({"", handle}); + if (itr == gModuleMap.end()) return {}; + return *itr->second; + } + + static AuOptional FindInCache(AuUInt pointer) + { + AU_LOCK_GUARD(gMutexUnique); + + auto curPtr = ToLowestPageAlignment(pointer); + auto temp = GetSegmentCache(curPtr); + if (temp.has_value()) return temp; + + for (int i = 0; i < kPageBufferPad; i++) + { + curPtr -= kMinPageAlignment; + temp = GetSegmentCache(curPtr); // TODO: i dont want to start from the top of the tree, thats stupid + if (temp.has_value()) return temp; + } + + return AuOptional{}; + } + + void InitProcessMap() + { + gMutexUnique = AuThreadPrimitives::MutexUnique(); + + #if defined(AURORA_IS_MODERNNT_DERIVED) + InitProcessMapNt(); + #endif + + #if defined(AURORA_PLATFORM_WIN32) + MakeToolHelp32Snapshot(); + #endif + } + + void DeinitProcessMap() + { + gMutexUnique.reset(); + DeinitProcessMapNt(); + } + + AUKN_SYM AuOptional GetSegment(AuUInt pointer) + { + try + { + auto ceg = FindInCache(pointer); + if (ceg.has_value()) + { + return ceg; + } + + #if defined(AURORA_IS_MODERNNT_DERIVED) + if (MakeAwarePtr(pointer)) + { + return FindInCache(pointer); + } + else + { + return LookupArbitrarySegment(pointer); + } + #endif + + return {}; + } + catch (...) + { + + } + } + + AUKN_SYM PublicModule DumpExecutableRoot() + { + try + { + return GetExecutableRoot(); + } + catch (...) + { + + } + } + + AUKN_SYM Segments DumpExecutableAll() + { + try + { + Segments ret; + for (const auto &[meta, ptr] : gModuleMap) + { + ret.insert(ret.end(), ptr->segments.begin(), ptr->segments.end()); + } + return ret; + } + catch (...) + { + + } + } +} \ No newline at end of file diff --git a/Source/Process/ProcessMap.hpp b/Source/Process/ProcessMap.hpp new file mode 100644 index 00000000..3c9f54e5 --- /dev/null +++ b/Source/Process/ProcessMap.hpp @@ -0,0 +1,18 @@ +#pragma once + +namespace Aurora::Process +{ + struct ModuleBasePair + { + AuString module; + AuUInt modBase; + }; + + PublicModule GetFromModuleCache(AuUInt handle); + void InsertModuleCache(const ModuleBasePair &pair, const AuSPtr &mod); + void RemoveModuleCache(const ModuleBasePair &eitherOr); + bool IsInModuleCache(const ModuleBasePair &pair); + + void InitProcessMap(); + void DeinitProcessMap(); +} \ No newline at end of file diff --git a/Source/Processes/Open.Win32.cpp b/Source/Processes/Open.Win32.cpp index ade770b1..1f08b92a 100644 --- a/Source/Processes/Open.Win32.cpp +++ b/Source/Processes/Open.Win32.cpp @@ -33,7 +33,7 @@ namespace Aurora::Processes { for (const auto &open : gOpenItems) { - ShellExecuteW(NULL, IO::FS::DirExists(open) ? L"explore" : NULL, Locale::ConvertFromUTF8(open).c_str(), NULL, NULL, SW_SHOWNORMAL); + ShellExecuteW(NULL, AuIOFS::DirExists(open) ? L"explore" : NULL, Locale::ConvertFromUTF8(open).c_str(), NULL, NULL, SW_SHOWNORMAL); } gOpenItems.clear(); gCondVariable->WaitForSignal(); @@ -41,7 +41,7 @@ namespace Aurora::Processes catch (...) { Debug::PrintError(); - LogWarn("An error occurred while dispatching a ShellExecute runner frame"); + AuLogWarn("An error occurred while dispatching a ShellExecute runner frame"); } } } @@ -56,12 +56,18 @@ namespace Aurora::Processes void InitWin32Opener() { gCondMutex = AuThreadPrimitives::ConditionMutexUnique(); + SysAssert(gCondMutex); + gCondVariable = AuThreadPrimitives::ConditionVariableUnique(AuUnsafeRaiiToShared(gCondMutex)); + SysAssert(gCondVariable); + gOpenerThread = AuThreads::ThreadUnique(AuThreads::ThreadInfo( AuMakeShared(AuThreads::IThreadVectorsFunctional::OnEntry_t(std::bind(OpenerThread)), AuThreads::IThreadVectorsFunctional::OnExit_t{}), "COM ShellExecute Runner" )); + SysAssert(gOpenerThread); + gOpenerThread->Run(); } @@ -83,6 +89,6 @@ namespace Aurora::Processes AUKN_SYM void OpenFile(const AuString &file) { - OpenUri(IO::FS::NormalizePathRet(file)); + OpenUri(AuIOFS::NormalizePathRet(file)); } } \ No newline at end of file diff --git a/Source/Processes/UtilRun.cpp b/Source/Processes/UtilRun.cpp new file mode 100644 index 00000000..82f87285 --- /dev/null +++ b/Source/Processes/UtilRun.cpp @@ -0,0 +1,14 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: UtilRun.cpp + Date: + Author: Reece +***/ +#include +#include "UtilRun.hpp" + +namespace Aurora::Processes +{ + +} \ No newline at end of file diff --git a/Source/Processes/UtilRun.hpp b/Source/Processes/UtilRun.hpp new file mode 100644 index 00000000..475dfd2f --- /dev/null +++ b/Source/Processes/UtilRun.hpp @@ -0,0 +1,12 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: UtilRun.hpp + Date: + Author: Reece +***/ +#pragma once + +namespace Aurora::Processes +{ +} \ No newline at end of file diff --git a/Source/Registry/Registry.cpp b/Source/Registry/Registry.cpp index 93655b59..e5dfa800 100644 --- a/Source/Registry/Registry.cpp +++ b/Source/Registry/Registry.cpp @@ -104,9 +104,9 @@ namespace Aurora::Registry cacheDocument_ = {}; } - if (!IO::FS::ReadString(path, file)) + if (!AuIOFS::ReadString(path, file)) { - return IO::FS::WriteString(path, "{}"); + return AuIOFS::WriteString(path, "{}"); } currentStreamDocument_ = json::parse(file); @@ -293,7 +293,6 @@ namespace Aurora::Registry SaveBuffered(); CloseSave(); } - void FSRegistry::OpenRead(const AuString &path) { @@ -349,7 +348,7 @@ namespace Aurora::Registry return false; } - if (!IO::FS::WriteString(lastPath_.value(), currentStreamDocument_.dump(4))) + if (!AuIOFS::WriteString(lastPath_.value(), currentStreamDocument_.dump(4))) { SysPushErrorIO("Couldn't write registry to {}", lastPath_.value()); return false; diff --git a/Source/Threading/Threads/OSThread.cpp b/Source/Threading/Threads/OSThread.cpp index 7b52f330..df554c94 100644 --- a/Source/Threading/Threads/OSThread.cpp +++ b/Source/Threading/Threads/OSThread.cpp @@ -13,18 +13,18 @@ #include "TLSView.hpp" #if defined(AURORA_IS_LINUX_DERIVED) -#include + #include #endif #if defined(AURORA_HAS_PTHREADS) -#include + #include #endif #if defined(AURORA_PLATFORM_WIN32) -#include -#include + #include #endif +#include "SpawnThread.hpp" namespace Aurora::Threading::Threads { @@ -231,11 +231,11 @@ namespace Aurora::Threading::Threads // The thread must've requested suicide and got stuck in a lengthy clean up effort if (!exitOnlyOnce_->TryLock()) { - LogWarn("Watchdog error - OS thread context didn't finish in 15 seconds, but he should exiting now."); + AuLogWarn("Watchdog error - OS thread context didn't finish in 15 seconds, but he should exiting now."); return false; } - LogWarn("Watchdog error - OS thread context didn't finish in 15 seconds, forcefully terminating without a watchdog overlooking onExit"); + AuLogWarn("Watchdog error - OS thread context didn't finish in 15 seconds, forcefully terminating without a watchdog overlooking onExit"); // Kill the current OS thread instance TeminateOSContext(false); @@ -266,7 +266,7 @@ namespace Aurora::Threading::Threads return prio_; } - AuUInt32 OSThread::GetMask() + AuUInt64 OSThread::GetMask() { return affinityProcessMask_; } @@ -276,9 +276,9 @@ namespace Aurora::Threading::Threads return name_; } - void OSThread::SetAffinity(AuUInt32 mask) + void OSThread::SetAffinity(AuUInt64 mask) { - if (mask == 0) mask = 0xFFFFFFFF; + if (mask == 0) mask = 0xFFFFFFFFFFFFFFFF; affinityProcessMask_ = mask; UpdateAffinity(mask); } @@ -303,102 +303,17 @@ namespace Aurora::Threading::Threads { task_ = task; - // https://github.com/webrtc-uwp/chromium-base/blob/master/threading/platform_thread_win.cc#L129-L136 - // Do we care yet? - // When targeting older CRTs, _beginthreadex - // When targeting at least UWP, CreateThread but _beginthreadex is fine - // https://web.archive.org/web/20110928122401/http://www.microsoft.com/msj/1099/win32/win321099.aspx - // Even in 1999 it sounded like _tiddata was setup for all modules that may come across our thread - // It wasn't until 2005, 6 years later, it became less of a requirement. - // Does the modern CRT need it for anything estoeric or evil? - // I think so long as we're targeting modern windows its fine to call _beginthreadex for all CRT users - // Userland icds, plugins, software not in our build chain, it makes sense for them to have a _fully_ initialized crt - // I think I switched it from CreateThread to _beginthreadex at somepoint and i don't remember why - #if defined(AURORA_IS_MODERNNT_DERIVED) - - unsigned(WINAPI * OSEP_f)(void *) = [](void *that) -> unsigned + auto ret = SpawnThread([this]() { - auto thiz = reinterpret_cast(that); - thiz->_ThreadEP(); - return 0; - }; - - DWORD(WINAPI * OSCreateThreadEP_f)(void *) = [](void *that) -> DWORD + this->_ThreadEP(); + }, GetName(), info_.stackSize); + + if (ret.first) { - auto thiz = reinterpret_cast(that); - thiz->_ThreadEP(); - return 0; - }; - - #if defined(AURORA_PLATFORM_WIN32) - BOOL a {}; - if (AuxUlibIsDLLSynchronizationHeld(&a)) - { - if (a) - { - handle_ = CreateThread(NULL, info_.stackSize, OSCreateThreadEP_f, reinterpret_cast(this), NULL, NULL); - if (!handle_) - { - handle_ = INVALID_HANDLE_VALUE; - SysPushErrorGen("Couldn't create locked thread: {}", GetName()); - return false; - } - - return true; - } - } - #endif - - auto ok = _beginthreadex(nullptr, info_.stackSize, OSEP_f, this, 0, 0); - if (ok == -1L) - { - SysPushErrorGen("Couldn't initialize thread: {}", GetName()); - return false; + handle_ = (decltype(handle_))ret.second; } - handle_ = reinterpret_cast(ok); - - #elif defined(AURORA_HAS_PTHREADS) - pthread_attr_t tattr; - - void *(*OSEP_f)(void *) = [](void *that) -> void * - { - auto thiz = reinterpret_cast(that); - thiz->_ThreadEP(); - return nullptr; - }; - - auto ret = pthread_attr_init(&tattr); - if (ret != 0) - { - SysPushErrorGen("Couldn't create thread: {}", GetName()); - return false; - } - - if (info_.stackSize) - { - ret = pthread_attr_setstacksize(&tattr, AuMin(AuUInt32(PTHREAD_STACK_MIN), info_.stackSize)); - if (ret != 0) - { - SysPushErrorGen("Couldn't create thread: {}", GetName()); - return false; - } - } - - ret = pthread_create(&handle_, &tattr, OSEP_f, this); - if (ret != 0) - { - SysPushErrorGen("Couldn't create thread: {}", GetName()); - return false; - } - - #else - - SysPanic("Not implemented"); - - #endif - - return true; + return ret.first; } void OSThread::_ThreadEP() @@ -627,7 +542,7 @@ namespace Aurora::Threading::Threads prio_ = prio; } - void OSThread::UpdateAffinity(AuUInt32 mask) + void OSThread::UpdateAffinity(AuUInt64 mask) { #if defined(AURORA_IS_MODERNNT_DERIVED) if (handle_ == INVALID_HANDLE_VALUE) @@ -669,10 +584,10 @@ namespace Aurora::Threading::Threads catch (...) { Debug::PrintError(); - LogWarn("Couldn't deinitialize thread"); - LogWarn("The smart thing to do at this point would be to panic"); - LogWarn("...but we could continue"); - LogWarn("Carrying on despite the potential for data integrity loss and memory leaks"); + AuLogWarn("Couldn't deinitialize thread"); + AuLogWarn("The smart thing to do at this point would be to panic"); + AuLogWarn("...but we could continue"); + AuLogWarn("Carrying on despite the potential for data integrity loss and memory leaks"); Telemetry::Mayday(); } diff --git a/Source/Threading/Threads/OSThread.hpp b/Source/Threading/Threads/OSThread.hpp index 6bb5afd5..540b5870 100644 --- a/Source/Threading/Threads/OSThread.hpp +++ b/Source/Threading/Threads/OSThread.hpp @@ -23,11 +23,11 @@ namespace Aurora::Threading::Threads void SendExitSignal() override; void SetPrio(EThreadPrio prio) override; - void SetAffinity(AuUInt32 mask) override; + void SetAffinity(AuUInt64 mask) override; void SetName(const AuString &name) override; EThreadPrio GetPrio() override; - AuUInt32 GetMask() override; + AuUInt64 GetMask() override; AuString GetName() override; AuSPtr GetTlsView() override; @@ -48,7 +48,7 @@ namespace Aurora::Threading::Threads bool Exit(bool willReturnToOS); bool ExecuteNewOSContext(AuFunction task); void UpdatePrio(EThreadPrio prio); - void UpdateAffinity(AuUInt32 mask); + void UpdateAffinity(AuUInt64 mask); void UpdateName(); void OSAttach(); void OSDeatach(); @@ -65,7 +65,7 @@ namespace Aurora::Threading::Threads OSThread * tlsReferenceThread_ {}; AuString name_; ThreadInfo info_; - AuUInt32 affinityProcessMask_ = 0xFFFFFFFF; + AuUInt64 affinityProcessMask_ = 0xFFFFFFFFFFFFFFFF; EThreadPrio prio_ = EThreadPrio::ePrioNormal; bool exiting_{}; @@ -84,7 +84,7 @@ namespace Aurora::Threading::Threads #if defined(AURORA_IS_MODERNNT_DERIVED) HANDLE handle_ = INVALID_HANDLE_VALUE; #elif defined(AURORA_HAS_PTHREADS) - pthread_t handle_; + pthread_t handle_ {}; #endif AuUInt64 unixThreadId_ = 0; diff --git a/Source/Threading/Threads/SpawnThread.NT.cpp b/Source/Threading/Threads/SpawnThread.NT.cpp new file mode 100644 index 00000000..6a6a8e91 --- /dev/null +++ b/Source/Threading/Threads/SpawnThread.NT.cpp @@ -0,0 +1,93 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: SpawnThread.NT.cpp + Date: + Author: Reece +***/ +#include +#include "Threads.hpp" +#include "SpawnThread.hpp" + +#if defined(AURORA_PLATFORM_WIN32) + #include + #include +#endif + +namespace Aurora::Threading::Threads +{ + AuPair /*success, oshandle*/ SpawnThread(const AuFunction &entrypoint, const AuString &debugString, AuUInt32 staskSize) + { + // https://github.com/webrtc-uwp/chromium-base/blob/master/threading/platform_thread_win.cc#L129-L136 + // Do we care yet? + // When targeting older CRTs, _beginthreadex + // When targeting at least UWP, CreateThread but _beginthreadex is fine + // https://web.archive.org/web/20110928122401/http://www.microsoft.com/msj/1099/win32/win321099.aspx + // Even in 1999 it sounded like _tiddata was setup for all modules that may come across our thread + // It wasn't until 2005, 6 years later, it became less of a requirement. + // Does the modern CRT need it for anything estoeric or evil? + // I think so long as we're targeting modern windows its fine to call _beginthreadex for all CRT users + // Userland icds, plugins, software not in our build chain, it makes sense for them to have a _fully_ initialized crt + // I think I switched it from CreateThread to _beginthreadex at somepoint and i don't remember why + + if (!entrypoint) + { + return {false, 0}; + } + + // i dont like this allocate + auto callbackClone = _new AuFunction(entrypoint); + if (!callbackClone) + { + return {false, 0}; + } + + static auto callVoidPtr_f = [](void *that) -> void + { + auto handle = reinterpret_cast *>(that); + auto callMe = *handle; + delete handle; + callMe(); + }; + + unsigned(WINAPI * OSEP_f)(void *) = [](void *that) -> unsigned + { + callVoidPtr_f(that); + return 0; + }; + + DWORD(WINAPI * OSCreateThreadEP_f)(void *) = [](void *that) -> DWORD + { + callVoidPtr_f(that); + return 0; + }; + + #if defined(AURORA_PLATFORM_WIN32) + BOOL a {}; + if (AuxUlibIsDLLSynchronizationHeld(&a)) + { + if (a) + { + auto handle = CreateThread(NULL, staskSize, OSCreateThreadEP_f, reinterpret_cast(callbackClone), NULL, NULL); + if (!handle) + { + handle = INVALID_HANDLE_VALUE; + SysPushErrorGen("Couldn't create locked thread: {}", debugString); + return {false, 0}; + } + + return {true, reinterpret_cast(handle)}; + } + } + #endif + + auto ok = _beginthreadex(nullptr, staskSize, OSEP_f, callbackClone, 0, 0); + if (ok == -1L) + { + SysPushErrorGen("Couldn't initialize thread: {}", debugString); + return {false, 0}; + } + + return {true, ok}; + } +} \ No newline at end of file diff --git a/Source/Threading/Threads/SpawnThread.NT.hpp b/Source/Threading/Threads/SpawnThread.NT.hpp new file mode 100644 index 00000000..8cc91ddf --- /dev/null +++ b/Source/Threading/Threads/SpawnThread.NT.hpp @@ -0,0 +1,13 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: SpawnThread.NT.hpp + Date: + Author: Reece +***/ +#pragma once + +namespace Aurora::Threading::Threads +{ + // ... +} \ No newline at end of file diff --git a/Source/Threading/Threads/SpawnThread.Unix.cpp b/Source/Threading/Threads/SpawnThread.Unix.cpp new file mode 100644 index 00000000..aef5d219 --- /dev/null +++ b/Source/Threading/Threads/SpawnThread.Unix.cpp @@ -0,0 +1,76 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: SpawnThread.Unix.cpp + Date: + Author: Reece +***/ +#include +#include "Threads.hpp" +#include "SpawnThread.hpp" + +#if defined(AURORA_HAS_PTHREADS) + #include +#endif + +namespace Aurora::Threading::Threads +{ + AuPair /*success, oshandle*/ SpawnThread(const AuFunction &entrypoint, const AuString &debugString, AuUInt32 staskSize) + { + pthread_attr_t tattr; + pthread_t handle; + + if (!entrypoint) + { + return {false, 0}; + } + + // i dont like this allocate + auto callbackClone = _new AuFunction(entrypoint); + if (!callbackClone) + { + return {false, 0}; + } + + static auto callVoidPtr_f = [](void *that) -> void + { + auto handle = reinterpret_cast *>(that); + auto callMe = *handle; + delete handle; + callMe(); + }; + + void *(*OSEP_f)(void *) = [](void *that) -> void * + { + auto thiz = reinterpret_cast(that); + thiz->_ThreadEP(); + return nullptr; + }; + + auto ret = pthread_attr_init(&tattr); + if (ret != 0) + { + SysPushErrorGen("Couldn't create thread: {}", debugString); + return {false, 0}; + } + + if (info_.stackSize) + { + ret = pthread_attr_setstacksize(&tattr, AuMin(AuUInt32(PTHREAD_STACK_MIN), info_.stackSize)); + if (ret != 0) + { + SysPushErrorGen("Couldn't create thread: {}", debugString); + return {false, 0}; + } + } + + ret = pthread_create(&handle, &tattr, OSEP_f, callbackClone); + if (ret != 0) + { + SysPushErrorGen("Couldn't create thread: {}", debugString); + return {false, 0}; + } + + return {true, handle}; + } +} \ No newline at end of file diff --git a/Source/Time/TimeLocale.hpp b/Source/Threading/Threads/SpawnThread.Unix.hpp similarity index 100% rename from Source/Time/TimeLocale.hpp rename to Source/Threading/Threads/SpawnThread.Unix.hpp diff --git a/Source/Threading/Threads/SpawnThread.hpp b/Source/Threading/Threads/SpawnThread.hpp new file mode 100644 index 00000000..627b3ba8 --- /dev/null +++ b/Source/Threading/Threads/SpawnThread.hpp @@ -0,0 +1,20 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: SpawnThread.hpp + Date: + Author: Reece +***/ +#pragma once + + +namespace Aurora::Threading::Threads +{ + AuPair /*success, oshandle*/ SpawnThread(const AuFunction &entrypoint, const AuString &debugString, AuUInt32 staskSize = 0); +} + +#if defined(AURORA_IS_MODERNNT_DERIVED) +#include "SpawnThread.NT.hpp" +#elif defined(AURORA_IS_UNIX_DERIVED) +#include "SpawnThread.Unix.hpp" +#endif \ No newline at end of file diff --git a/Source/Time/Clock.cpp b/Source/Time/Clock.cpp index 92848179..3820a4c3 100644 --- a/Source/Time/Clock.cpp +++ b/Source/Time/Clock.cpp @@ -219,7 +219,7 @@ namespace Aurora::Time if (!localtime_r(&timet, &ret)) #endif { - LogWarn("Couldn't convert local civil time"); + AuLogWarn("Couldn't convert local civil time"); return ToCivilTime(time, true); } } @@ -253,4 +253,14 @@ namespace Aurora::Time return std::chrono::duration_cast(NormalizeEpoch(std::chrono::system_clock::from_time_t(timet).time_since_epoch())).count(); } + + AUKN_SYM tm NormalizeCivilTimezone(const Time::tm &time, ETimezoneShift shift) + { + if ((time.tm_isdst == 0) && (shift == ETimezoneShift::eUTC)) + { + return time; + } + + return ToCivilTime(FromCivilTime(time, shift == ETimezoneShift::eUTC)); + } }