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
This commit is contained in:
Reece Wilson 2022-01-24 18:37:06 +00:00
parent 8db441ff33
commit e5e36bd887
87 changed files with 2890 additions and 779 deletions

View File

@ -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();
}
}

View File

@ -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<Logging::ILogger> &defaultGlobalLogger);
AUKN_SYM AuSPtr<Logging::ILogger> GetDefaultLogInterface();
/// Consider using the following function for asynchronous utf-8 processed line based input -
/// Hooks::SetCallbackAndDisableCmdProcessing(...)

View File

@ -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, ())
)
}

View File

@ -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);

View File

@ -48,6 +48,9 @@ namespace Aurora::Debug
*/
AUKN_SYM void PrintError();
AUKN_SYM void CheckErrors();
/**
Immediately terminates the process.
May attempt some hardened telemetry debug ops

View File

@ -33,6 +33,7 @@ namespace Aurora::Debug
kFailureSyntaxError,
kFailureDisconnected,
kFailureUninitialized,
kFailureUnimplemented,
kFailureUserBegin = 256
};

View File

@ -13,6 +13,7 @@ namespace Aurora::Debug
{
AuOptional<AuString> label;
AuUInt64 address;
AuUInt64 relAddress;
AuOptional<AuString> module;
AuOptional<AuTuple<AuString, int, int>> file; // file, line, offset

View File

@ -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

View File

@ -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"

View File

@ -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;
}
}

View File

@ -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;
};
}

View File

@ -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;
@ -89,6 +20,13 @@ namespace Aurora::HWInfo
AuUInt8 cores;
AuUInt8 threads;
AuList<AuInt64> threadTopology;
AuList<CpuBitId> serverTopology;
CpuBitId maskECores;
bool maskMTContig;
bool maskMTHalf;
CpuId cpuId;
};

View File

@ -9,6 +9,7 @@
#include "ECodePage.hpp"
#include "Encoding/Encoding.hpp"
#include "LocaleStrings.hpp"
namespace Aurora::Locale
{

View File

@ -0,0 +1,19 @@
#pragma once
#include <Aurora/Time/ETimezoneShift.hpp>
#include <Aurora/Time/TM.hpp>
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);
}

View File

@ -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<PublicModule> moduleMeta;
};
using Segments = AuList<Segment>;
struct PublicModule
{
AuList<Segment> segments;
AuSPtr<ModuleMeta> moduleMeta;
};
AUKN_SYM AuOptional<Segment> GetSegment(AuUInt pointer);
AUKN_SYM Segments DumpExecutableRoot();
AUKN_SYM PublicModule DumpExecutableRoot();
AUKN_SYM Segments DumpExecutableAll();
}

View File

@ -10,5 +10,6 @@
#include "ESpawnType.hpp"
#include "IProcess.hpp"
#include "Spawn.hpp"
#include "UtilRun.hpp"
#include "Open.hpp"

View File

@ -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<AuString> &, buffer)),
AUI_METHOD(void, OnBuffered, (const Memory::ByteBuffer &, buffer))
);
struct CommandRun_s
{
AuString cmd;
AuList<AuString> 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<ICommandFinished> callback;
};
AUKN_SYM void RunCommand(const CommandRun_s &in);
}

View File

@ -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();
@ -196,6 +194,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
LocalLogInfo fio;

View File

@ -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

View File

@ -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<typename Dest_t>
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<typename In_t>
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
*/

View File

@ -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
};
}

View File

@ -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<typename Dest_t>
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<typename In_t>
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;
}
};
}

View File

@ -7,114 +7,20 @@
***/
#pragma once
#include <Aurora/Time/ETimezoneShift.hpp>
#include <Aurora/Locale/LocaleStrings.hpp>
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"

View File

@ -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();
}
}

View File

@ -1002,7 +1002,7 @@ namespace Aurora::Async
}
catch (...)
{
LogWarn("Couldn't clean up thread feature!");
AuLogWarn("Couldn't clean up thread feature!");
Debug::PrintError();
}
}

View File

@ -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<Async::BasicWorkStdFunc>([&commands]()
{
DispatchCommandsFromThis(commands);
}),
true)->Dispatch()->BlockUntilComplete();
}), true)->Dispatch()->BlockUntilComplete();
}
gMutex->Unlock();

View File

@ -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<ILogger> CreateDefaultLogger()
{
return {};
return Logging::NewLoggerShared(gDefaultSinks);
}
AUKN_SYM void WriteLine(AuUInt8 level, const ConsoleMessage &msg)
@ -57,6 +58,16 @@ namespace Aurora::Console
//gDefaultSinks.clear();
}
AUKN_SYM void SetGlobalLogger(const AuSPtr<Logging::ILogger> &defaultGlobalLogger)
{
gUserLogger = defaultGlobalLogger;
}
AUKN_SYM AuSPtr<Logging::ILogger> GetDefaultLogInterface()
{
return gDefaultLogger;
}
AUKN_SYM AuUInt32 ReadStdIn(void *buffer, AuUInt32 length)
{
return ConsoleStd::ReadStdIn(buffer, 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();
}

View File

@ -9,7 +9,6 @@
namespace Aurora::Console
{
void AddDefaultLogger(const AuSPtr<IBasicSink> &logger);
void Init();

View File

@ -7,12 +7,12 @@
***/
#include <Source/RuntimeInternal.hpp>
#include "ConsoleFIO.hpp"
#include "FileSink.hpp"
#include "../Console.hpp"
namespace Aurora::Console::ConsoleFIO
{
static AuList<AuUInt8> 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<AuString> files;
AuBST<AuString, IO::FS::Stat> fileMeta;
AuBST<AuString, AuIOFS::Stat> 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<bool>(gFileHandle);
gFileSink = NewFileSinkNew(path);
return gFileSink;
}
void FIOCleanup()
@ -143,26 +131,7 @@ 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<AuUInt8 *>(str.data()), reinterpret_cast<AuUInt8 *>(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;
}
}
}

View File

@ -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 <Source/RuntimeInternal.hpp>
#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<bool>(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<AuUInt8 *>(str.data()), reinterpret_cast<AuUInt8 *>(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<FIOSink *>(logger);
}
}

View File

@ -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<AuUInt8> logBuffer_;
AuThreadPrimitives::RWLockUnique_t logMutex_;
};
void NewFileSinkRelease(IBasicSink *logger);
IBasicSink *NewFileSinkNew(const AuString &str);
}

View File

@ -29,6 +29,8 @@ namespace Aurora::Console
};
AuString ConsoleMessage::StringifyTime(bool simple) const
{
try
{
std::tm localized;
@ -43,6 +45,11 @@ namespace Aurora::Console
return fmt::format("{:%Y-%m-%d %H:%M:%S}", localized);
}
}
catch (...)
{
return {};
}
}
AuString ConsoleMessage::GetWrappedTag() const
{
@ -51,11 +58,33 @@ namespace Aurora::Console
AuString ConsoleMessage::ToConsole() const
{
return fmt::format("{}[{}] {:<7} | {}{}", kAnsiCheats[static_cast<size_t>(color)], StringifyTime(), GetWrappedTag(), line, kAnsiCheats[static_cast<size_t>(EAnsiColor::eReset)]);
try
{
return fmt::format("{}[{}] {:<7} | {}{}",
static_cast<EAnsiColor>(color) <= EAnsiColor::eCount ?
kAnsiCheats[static_cast<size_t>(color)] :
"",
StringifyTime(),
GetWrappedTag(),
line,
kAnsiCheats[static_cast<size_t>(EAnsiColor::eReset)]);
}
catch (...)
{
return {};
}
}
AuString ConsoleMessage::ToSimplified() const
{
try
{
return fmt::format("{:<9} {:<7} | {}", StringifyTime(true), GetWrappedTag(), line);
}
catch (...)
{
return {};
}
}
}

View File

@ -7,7 +7,8 @@
***/
#include <Source/RuntimeInternal.hpp>
#include "ConsoleStd.hpp"
#include "Source/Locale/Locale.hpp"
#include <Source/Locale/Locale.hpp>
#include <Source/Console/Console.hpp>
#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 (defined(DEBUG) || defined(STAGING)) && defined(AURORA_IS_MODERNNT_DERIVED)
auto debugLine = string.ToSimplified() + "\r\n";
OutputDebugStringW(Locale::ConvertFromUTF8(debugLine).c_str());
#endif
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()
@ -288,6 +287,46 @@ 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)

View File

@ -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);
}

View File

@ -605,7 +605,7 @@ void ConsoleFrame::OnAbout(wxCommandEvent &event)
void ConsoleFrame::OnHello(wxCommandEvent &event)
{
LogGame("nani?!");
AuLogGame("nani?!");
}
void ConsoleFrame::OnBugWrite(wxCommandEvent &event)

View File

@ -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>(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<ShutdownFlushHook>());
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();
}
}

View File

@ -9,6 +9,8 @@
namespace Aurora::Console
{
void PingFlushers();
void ForceFlush();
void InitFlusher();
void DeinitFlusher();

View File

@ -0,0 +1,235 @@
#include <Source/RuntimeInternal.hpp>
#include "Logger.hpp"
namespace Aurora::Console::Logging
{
static AuList<AuTuple<Logger *, AuUInt8, ConsoleMessage>> gLogTasks;
static AuThreadPrimitives::SpinLock gGlobalSpin;
static AuList<Logger *> gFlushableLoggers;
Logger::Logger(const AuList<AuSPtr<IBasicSink>> &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<AuSPtr<IBasicSink>> &sinks)
{
try
{
auto logger = _new Logger(sinks);
if (!logger)
{
return nullptr;
}
return logger;
}
catch (...)
{
return {};
}
}
AUKN_SYM void NewLoggerRelease(ILogger *logger)
{
SafeDelete<Logger *>(logger);
}
}

View File

@ -0,0 +1,31 @@
#pragma once
namespace Aurora::Console::Logging
{
struct Logger : ILogger
{
Logger(const AuList<AuSPtr<IBasicSink>> &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<AuSPtr<IBasicSink>> sinks;
AuList<AuTuple<AuUInt8, bool>> 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();
}

View File

@ -0,0 +1,54 @@
#include <Source/RuntimeInternal.hpp>
#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)
{}
}

View File

@ -0,0 +1,6 @@
#pragma once
namespace Aurora::Console::Logging
{
}

View File

@ -16,12 +16,12 @@
namespace Aurora::Debug
{
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,9 +310,11 @@ namespace Aurora::Debug
const auto frame = *this;
AuString backTraceBuffer;
try
{
backTraceBuffer.reserve(512 - 32); // 512 seems like a nice length minus some overhead for a bucket allocator
backTraceBuffer += fmt::format("\tAddress: {:x}", frame.address);
backTraceBuffer += fmt::format("\tAddress: 0x{:x} (0x{:x})", frame.relAddress ? frame.relAddress : frame.address, frame.relAddress ? frame.address : frame.relAddress);
if (frame.module)
{
@ -352,11 +354,18 @@ namespace Aurora::Debug
return backTraceBuffer;
}
catch (...)
{
return {};
}
}
AUKN_SYM AuString StringifyStackTrace(const StackTrace &backtrace)
{
AuString backTraceBuffer;
try
{
backTraceBuffer.reserve(2048);
backTraceBuffer += "Unwinding call frame:";
@ -369,6 +378,11 @@ namespace Aurora::Debug
return backTraceBuffer;
}
catch (...)
{
return {};
}
}
void InitDebug()
{

View File

@ -19,10 +19,33 @@
#include <vcruntime_exception.h>
#include <ehdata.h>
#include <Source/Process/ProcessMap.hpp>
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<AuUInt>(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<AuUInt>(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

View File

@ -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;
try
{
Init();
}
catch (...)
{
SysPanic("A fatal error occurred during the initialization of Aurora Runtime");
}
gRuntimeHasStarted = true;
}

View File

@ -23,6 +23,10 @@
#include <cpuid.h>
#endif
#if defined(AURORA_IS_MODERNNT_DERIVED)
#include <VersionHelpers.h>
#endif
namespace Aurora::HWInfo
{
static CpuInfo gCpuInfo;
@ -348,10 +352,10 @@ namespace Aurora::HWInfo
}
char vendor[0x20];
memset(vendor, 0, sizeof(vendor));
*reinterpret_cast<int*>(vendor) = cpuInfo.ebx;
*reinterpret_cast<int*>(vendor + 4) = cpuInfo.edx;
*reinterpret_cast<int*>(vendor + 8) = cpuInfo.ecx;
AuMemset(vendor, 0, sizeof(vendor));
*reinterpret_cast<AuUInt32 *>(vendor) = cpuInfo.ebx;
*reinterpret_cast<AuUInt32 *>(vendor + 4) = cpuInfo.edx;
*reinterpret_cast<AuUInt32 *>(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,20 +404,112 @@ 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<AuUInt8> low;
AuList<CpuBitId> server;
CpuBitId mask;
};
AuBST<AuUInt8, CpuInfo> 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()
{
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;
@ -430,15 +526,24 @@ namespace Aurora::HWInfo
gCpuInfo.cores = 0;
gCpuInfo.threads = 0;
bool sparse = false;
for (auto i = 0; i < length; i++)
{
if (sysinfo[i].Relationship == RelationProcessorCore)
{
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.
gCpuInfo.cores++;
auto mask = sysinfo[i].ProcessorMask;
int counter {};
unsigned long offset {}, tmp;
while (offset != (sizeof(offset) * 8))
{
@ -450,6 +555,8 @@ namespace Aurora::HWInfo
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();
}
}

View File

@ -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 {};
}

View File

@ -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;
}

View File

@ -56,6 +56,16 @@ namespace Aurora::IO::FS
pathNormalized = NormalizePathRet(path);
win32Path = Locale::ConvertFromUTF8(pathNormalized);
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);
@ -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;
}
@ -150,38 +165,80 @@ namespace Aurora::IO::FS
}
AUKN_SYM bool FileExists(const AuString &path)
{
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)
{
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)
{
try
{
return CreateDirectories(NormalizePathRet(path), false);
}
catch (...)
{
return false;
}
}
AUKN_SYM bool Remove(const AuString &path)
{
try
{
return DeleteFileW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str());
}
catch (...)
{
return false;
}
}
AUKN_SYM bool Relink(const AuString &src, const AuString &dest)
{
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)
{
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)
{

View File

@ -42,20 +42,36 @@ namespace Aurora::IO::FS
void _NormalizePath(AuString &str);
static void NormalizePath(AuString &str)
{
try
{
_NormalizePath(str);
}
catch (...)
{
str = {};
}
}
static inline AuString NormalizePathRet(const AuString &str)
static auline AuString NormalizePathRet(const AuString &str)
{
try
{
AuString ret = str;
_NormalizePath(ret);
return ret;
}
catch (...)
{
return {};
}
}
bool _MkDir(const AuString &str);
static bool CreateDirectories(const AuString &cpath, bool isFile)
{
try
{
for (int i = 0; i < cpath.size(); i++)
{
@ -82,6 +98,11 @@ namespace Aurora::IO::FS
return true;
}
catch (...)
{
return false;
}
}
static bool IterateDirEntriesSTL(const AuString &path, bool filesOnly, AuList<AuString> &patches)
{

View File

@ -189,7 +189,7 @@ namespace Aurora::IO::FS
}
catch (...)
{
LogWarn("Couldn't flush file stream");
AuLogWarn("Couldn't flush file stream");
}
}
};

View File

@ -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<char *>(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<const char *>(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;
}
@ -195,9 +195,20 @@ namespace Aurora::IO::FS
}
static IFileStream *OpenNew(const AuString &path, bool read)
{
try
{
auto pathex = NormalizePathRet(path);
if (pathex.empty())
{
return nullptr;
}
auto win32Path = Locale::ConvertFromUTF8(pathex);
if (win32Path.empty())
{
return nullptr;
}
HANDLE fileHandle;
if (read)
@ -212,7 +223,7 @@ namespace Aurora::IO::FS
if (fileHandle == INVALID_HANDLE_VALUE)
{
LogWarn("Missing file: {}", path);
AuLogWarn("Missing file: {}", path);
SysPushErrorIO("Missing file: {}", path);
return nullptr;
}
@ -227,6 +238,11 @@ namespace Aurora::IO::FS
stream->Init(fileHandle, pathex);
return stream;
}
catch (...)
{
return nullptr;
}
}
AUKN_SYM IFileStream *OpenReadNew(const AuString &path)
{

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -31,11 +31,21 @@ namespace Aurora::Locale
#endif
AUKN_SYM AuString ConvertFromWChar(const wchar_t *in)
{
try
{
return ConvertFromWChar(in, wcslen(in));
}
catch (...)
{
SysPushErrorMem("ConvertFromWChar failed");
return {};
}
}
AUKN_SYM AuString ConvertFromWChar(const wchar_t *in, AuMach length)
{
try
{
#if defined(AU_HAS_MSFT_NATIONALLANGSUPPORT)
AuString ret;
@ -52,11 +62,21 @@ namespace Aurora::Locale
#elif !defined(AU_NO_CPPLOCALE)
return gUtf8Conv.to_bytes(std::wstring(in, wcslen(in)));
#else
return false;
SysPushErrorUnimplemented("ConvertFromWChar");
return {};
#endif
}
catch (...)
{
SysPushErrorMem("ConvertFromWChar failed");
Debug::CheckErrors();
}
return {};
}
AUKN_SYM std::wstring ConvertFromUTF8(const AuString &in)
{
try
{
#if defined(AU_HAS_MSFT_NATIONALLANGSUPPORT)
std::wstring ret;
@ -73,9 +93,17 @@ namespace Aurora::Locale
#elif !defined(AU_NO_CPPLOCALE)
return gUtf8Conv.from_bytes(in);
#else
return false;
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;

View File

@ -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 <Source/RuntimeInternal.hpp>
#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 {};
}
}
}

View File

@ -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

View File

@ -36,11 +36,6 @@ namespace Aurora::Loop
return {};
}
if (!(ret = AuMakeShared<Mutex>(mutex)))
{
return {};
}
return ret;
return AuMakeShared<Mutex>(mutex);
}
}

View File

@ -37,11 +37,6 @@ namespace Aurora::Loop
return {};
}
if (!(ret = AuMakeShared<Semaphore>(mutex)))
{
return {};
}
return ret;
return AuMakeShared<Semaphore>(mutex);
}
}

View File

@ -19,6 +19,8 @@ namespace Aurora::Loop
AuList<HANDLE> handleArray;
AuSPtr<ILoopSource> msgSource;
try
{
isWinLoop = false;
loopSourceExs.reserve(objects.size());
handleArray.reserve(objects.size());
@ -48,6 +50,11 @@ namespace Aurora::Loop
}
}
}
}
catch (...)
{
return {};
}
for (const auto &source : loopSourceExs)
{
@ -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;

View File

@ -20,7 +20,7 @@ namespace Aurora::Loop
if (handles.size() == 1)
{
return WaitForSingleObject(reinterpret_cast<HANDLE>(handles.at(0)), 0) == WAIT_OBJECT_0;
return WaitForSingleObjectEx(reinterpret_cast<HANDLE>(handles.at(0)), 0, true) == WAIT_OBJECT_0;
}
else
{
@ -30,7 +30,7 @@ namespace Aurora::Loop
{
ntHandles.push_back(reinterpret_cast<HANDLE>(handle));
}
return WaitForMultipleObjects(ntHandles.size(), ntHandles.data(), false, 0) >= WAIT_OBJECT_0;
return WaitForMultipleObjectsEx(ntHandles.size(), ntHandles.data(), false, 0, true) >= WAIT_OBJECT_0;
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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,12 +181,19 @@ namespace Aurora::Process
{
AuString module, partial, full;
try
{
if (!GetModulePath(module, partial, full))
{
return false;
}
executable = module;
}
catch (...)
{
return false;
}
return true;
}
@ -192,6 +202,8 @@ namespace Aurora::Process
{
AuString module, partial, full;
try
{
if (!GetModulePath(module, partial, full))
{
return false;
@ -203,6 +215,11 @@ namespace Aurora::Process
{
return GetWorkingDirectory(path);
}
}
catch (...)
{
return false;
}
return true;
}
@ -211,12 +228,19 @@ namespace Aurora::Process
{
AuString module, partial, full;
try
{
if (!GetModulePath(module, partial, full))
{
return false;
}
path = full;
}
catch (...)
{
return false;
}
return true;
}

View File

@ -23,6 +23,8 @@
#include <Source/IO/FS/FS.hpp>
#include <Source/IO/FS/Resources.hpp>
#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();
}
}

View File

@ -9,5 +9,6 @@
namespace Aurora::Process
{
void InitProcess();
void DeinitProcess();
}

View File

@ -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 <Source/RuntimeInternal.hpp>
#include "ProcessMap.NT.hpp"
#include "ProcessMap.hpp"
namespace Aurora::Process
{
static AuThreadPrimitives::MutexUnique_t gMutex;
static AuBST<AuUInt, AuString> gPathCache;
static AuBST<AuUInt, AuString> 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<AuUInt>(handle));
if (itr != gPathCache.end()) return itr->second;
}
else
{
auto itr = gModNameCache.find(reinterpret_cast<AuUInt>(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<AuUInt>(handle), ret));
}
else
{
AuTryInsert(gModNameCache, AuMakePair(reinterpret_cast<AuUInt>(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<PIMAGE_DOS_HEADER>(mod);
auto nt = &(reinterpret_cast<PIMAGE_NT_HEADERS>(reinterpret_cast<AuUInt>(mod) + dosHeader->e_lfanew)->OptionalHeader.ImageBase);
auto offset = static_cast<AuUInt32>(reinterpret_cast<const AuUInt8 *>(nt) - reinterpret_cast<const AuUInt8 *>(mod));
using Value_t = AuRemovePointer_t<decltype(nt)>;
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<PIMAGE_DOS_HEADER>(mod);
auto nt = reinterpret_cast<PIMAGE_NT_HEADERS>(reinterpret_cast<AuUInt>(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<AuUInt>(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<const char *>(cur->Name), sizeof(cur->Name)));
AuTryInsert(segments, seg);
}
}
static AuSPtr<PublicModule> HandleToPublicModule(HMODULE h)
{
auto pub = AuMakeShared<PublicModule>();
if (!pub) return {};
pub->moduleMeta = AuMakeShared<ModuleMeta>();
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<AuUInt>(hmod));
if (itr1 != gPathCache.end()) gPathCache.erase(itr1);
auto itr2 = gModNameCache.find(reinterpret_cast<AuUInt>(hmod));
if (itr2 != gModNameCache.end()) gModNameCache.erase(itr2);
}
// release lock
{
RemoveModuleCache({"", reinterpret_cast<AuUInt>(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<LPCWSTR>(pointer), &handle))
{
return false;
}
MakeAware(handle);
return true;
}
AuOptional<Segment> LookupArbitrarySegment(AuUInt address)
{
MEMORY_BASIC_INFORMATION info;
Segment segment;
if (!VirtualQuery((LPCVOID)address, &info, sizeof(info)))
{
return {};
}
segment.baseVa = reinterpret_cast<AuUInt>(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<AuUInt>(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<AuUInt>(handle));
}
catch (...)
{
return {};
}
}
void InitProcessMapNt()
{
gMutex = AuThreadPrimitives::MutexUnique();
}
void DeinitProcessMapNt()
{
gMutex.reset();
}
}

View File

@ -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<Segment> 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);
}

View File

@ -7,47 +7,39 @@
***/
#include <Source/RuntimeInternal.hpp>
#include "ProcessMap.Win32.hpp"
#include "ProcessMap.NT.hpp"
#include <tlhelp32.h>
namespace Aurora::Process
{
static AuString ModuleToSomething(HMODULE handle, bool path)
void MakeToolHelp32Snapshot()
{
std::wstring file;
file.resize(16 * 1024);
MODULEENTRY32 me32;
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
// HMODULE arent handles, they're COFF pointers
if (!handle)
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<HMODULE>(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);
}
}

View File

@ -9,6 +9,8 @@
namespace Aurora::Process
{
void MakeToolHelp32Snapshot();
AuString ModuleToName(HMODULE handle);
AuString ModuleToPath(HMODULE handle);
}

View File

@ -0,0 +1,225 @@
#include <Source/RuntimeInternal.hpp>
#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<AuUInt, ModuleLookup> gModulePtrMap;
static const auto kMinPageAlignment = 4096;
static const auto kPageBufferPad = 20;
static AuThreadPrimitives::MutexUnique_t gMutexUnique;
static AuHashMapEx<ModuleBasePair, AuSPtr<PublicModule>, ModuleBasePairUtil> gModuleMap;
static AuUInt ToLowestPageAlignment(AuUInt in)
{
return in & ~(kMinPageAlignment - 1);
}
static AuSPtr<PublicModule> GetModuleFromSegmentCache(AuUInt pointer)
{
AU_LOCK_GUARD(gMutexUnique);
auto itr = gModulePtrMap.find(pointer);
if (itr == gModulePtrMap.end()) return {};
return itr->second.moduleMeta.lock();
}
static AuOptional<Segment> 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<PublicModule> &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<Segment> 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<Segment>{};
}
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<Segment> 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 (...)
{
}
}
}

View File

@ -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<PublicModule> &mod);
void RemoveModuleCache(const ModuleBasePair &eitherOr);
bool IsInModuleCache(const ModuleBasePair &pair);
void InitProcessMap();
void DeinitProcessMap();
}

View File

@ -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>(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));
}
}

View File

@ -0,0 +1,14 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: UtilRun.cpp
Date:
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "UtilRun.hpp"
namespace Aurora::Processes
{
}

View File

@ -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
{
}

View File

@ -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);
@ -294,7 +294,6 @@ namespace Aurora::Registry
CloseSave();
}
void FSRegistry::OpenRead(const AuString &path)
{
Read(path, EReadType::eClearCacheAndStore);
@ -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;

View File

@ -21,10 +21,10 @@
#endif
#if defined(AURORA_PLATFORM_WIN32)
#include <process.h>
#include <Aux_ulib.h>
#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)
auto ret = SpawnThread([this]()
{
this->_ThreadEP();
}, GetName(), info_.stackSize);
unsigned(WINAPI * OSEP_f)(void *) = [](void *that) -> unsigned
if (ret.first)
{
auto thiz = reinterpret_cast<OSThread *>(that);
thiz->_ThreadEP();
return 0;
};
DWORD(WINAPI * OSCreateThreadEP_f)(void *) = [](void *that) -> DWORD
{
auto thiz = reinterpret_cast<OSThread *>(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<LPVOID>(this), NULL, NULL);
if (!handle_)
{
handle_ = INVALID_HANDLE_VALUE;
SysPushErrorGen("Couldn't create locked thread: {}", GetName());
return false;
handle_ = (decltype(handle_))ret.second;
}
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_ = reinterpret_cast<HANDLE>(ok);
#elif defined(AURORA_HAS_PTHREADS)
pthread_attr_t tattr;
void *(*OSEP_f)(void *) = [](void *that) -> void *
{
auto thiz = reinterpret_cast<OSThread *>(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();
}

View File

@ -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<TLSView> GetTlsView() override;
@ -48,7 +48,7 @@ namespace Aurora::Threading::Threads
bool Exit(bool willReturnToOS);
bool ExecuteNewOSContext(AuFunction<void()> 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;

View File

@ -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 <Source/RuntimeInternal.hpp>
#include "Threads.hpp"
#include "SpawnThread.hpp"
#if defined(AURORA_PLATFORM_WIN32)
#include <process.h>
#include <Aux_ulib.h>
#endif
namespace Aurora::Threading::Threads
{
AuPair<bool, AuUInt> /*success, oshandle*/ SpawnThread(const AuFunction<void()> &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<void()>(entrypoint);
if (!callbackClone)
{
return {false, 0};
}
static auto callVoidPtr_f = [](void *that) -> void
{
auto handle = reinterpret_cast<AuFunction<void()> *>(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<LPVOID>(callbackClone), NULL, NULL);
if (!handle)
{
handle = INVALID_HANDLE_VALUE;
SysPushErrorGen("Couldn't create locked thread: {}", debugString);
return {false, 0};
}
return {true, reinterpret_cast<AuUInt>(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};
}
}

View File

@ -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
{
// ...
}

View File

@ -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 <Source/RuntimeInternal.hpp>
#include "Threads.hpp"
#include "SpawnThread.hpp"
#if defined(AURORA_HAS_PTHREADS)
#include <sched.h>
#endif
namespace Aurora::Threading::Threads
{
AuPair<bool, AuUInt> /*success, oshandle*/ SpawnThread(const AuFunction<void()> &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<void()>(entrypoint);
if (!callbackClone)
{
return {false, 0};
}
static auto callVoidPtr_f = [](void *that) -> void
{
auto handle = reinterpret_cast<AuFunction<void()> *>(that);
auto callMe = *handle;
delete handle;
callMe();
};
void *(*OSEP_f)(void *) = [](void *that) -> void *
{
auto thiz = reinterpret_cast<OSThread *>(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};
}
}

View File

@ -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<bool, AuUInt> /*success, oshandle*/ SpawnThread(const AuFunction<void()> &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

View File

@ -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<std::chrono::milliseconds>(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));
}
}