diff --git a/Include/Aurora/Async/Async.hpp b/Include/Aurora/Async/Async.hpp index a356ef55..d265c683 100644 --- a/Include/Aurora/Async/Async.hpp +++ b/Include/Aurora/Async/Async.hpp @@ -139,6 +139,28 @@ namespace Aurora::Async }; return ret; } + + + template + static inline FJob JobFromDerivedJob(const FJob &reference) + { + FJob ret; + ret.onSuccess = [=](const Info_t &in, const Result_t &a) + { + if (reference.onSuccess) + { + reference.onSuccess(in, a); + } + }; + ret.onFailure = [=](const Info_t &a) + { + if (reference.onFailure) + { + reference.onSuccess(a); + } + }; + return ret; + } using FVoidJob = FJob; @@ -176,13 +198,13 @@ namespace Aurora::Async return ret; } - template - FTask TaskFromVoidVoid(AuVoidFunc &&func) + template + FTask TaskFromVoidVoid(const AuVoidFunc &func) { FTask ret; ret.onFrame = [callable = func](const Info_t &in) -> Out_t { - func(); + callable(); return {}; }; return ret; @@ -652,12 +674,24 @@ namespace Aurora::Async // It would be nice if we didn't have to drag the job callback pair around with us return Async::NewWorkItem(worker, AuMakeShared>(task, job, inputParameters), enableWait)->Dispatch(); } - + template, typename Job_t = FJob, typename ClazzImpl> AuSPtr DispatchFunctional(const WorkerId_t &worker, ClazzImpl task, const Job_t &job, const Info_t &inputParameters, bool enableWait = false) { return Async::DispatchBasicWorkCallback(worker, Async::TaskFromConsumerRefT(task), job, inputParameters, enableWait); } + + template, typename Job_t = FJob, typename ClazzImpl> + AuSPtr DispatchFunctor(const WorkerId_t &worker, ClazzImpl task, const Job_t &job, const Info_t &inputParameters, bool enableWait = false) + { + return Async::DispatchBasicWorkCallback(worker, Async::TaskFromConsumerRefT(task), job, inputParameters, enableWait); + } + + template, typename Job_t = FJob, typename ClazzImpl> + AuSPtr DispatchVoid(const WorkerId_t &worker, ClazzImpl task, const Job_t &job, const Info_t &inputParameters, bool enableWait = false) + { + return Async::DispatchBasicWorkCallback(worker, Async::TaskFromVoidVoid(task), job, inputParameters, enableWait); + } #undef ASYNC_ERROR diff --git a/Source/Console/Commands/Commands.cpp b/Source/Console/Commands/Commands.cpp index 1ada8080..769a6a3b 100644 --- a/Source/Console/Commands/Commands.cpp +++ b/Source/Console/Commands/Commands.cpp @@ -105,14 +105,14 @@ namespace Aurora::Console::Commands } else { - Async::DispatchBasicWorkCallback(workerId, - Async::TaskFromConsumerRefT([](const CommandDispatch &dispatch) -> AuOptional + Async::DispatchBasicWorkCallback(workerId, + Async::TaskFromConsumerRefT([](const CommandDispatch &dispatch) -> void { dispatch.callback->onCommand(dispatch.arguments); - return {}; - }), + }), {}, - CommandDispatch(res.result, callback) + CommandDispatch(res.result, callback), + false ); } diff --git a/Source/Debug/ExceptionWatcher.Win32.cpp b/Source/Debug/ExceptionWatcher.Win32.cpp index e71ed07e..4c8ee5a0 100644 --- a/Source/Debug/ExceptionWatcher.Win32.cpp +++ b/Source/Debug/ExceptionWatcher.Win32.cpp @@ -186,6 +186,9 @@ namespace Aurora::Debug void InitWin32() { + static AuString kStringRawName = typeid(AuString).raw_name(); + + #if defined(DEBUG) || defined(STAGING) SymInitialize(GetCurrentProcess(), NULL, TRUE); #endif @@ -234,60 +237,61 @@ namespace Aurora::Debug handle = reinterpret_cast(ExceptionInfo->ExceptionRecord->ExceptionInformation[3]); } - const auto catchableTypeArray = reinterpret_cast(reinterpret_cast(handle) + static_cast(throwInfo->pCatchableTypeArray)); - const auto type = reinterpret_cast (reinterpret_cast(handle) + static_cast(catchableTypeArray->arrayOfCatchableTypes[0])); - const auto descriptor = reinterpret_cast (reinterpret_cast(handle) + static_cast(type->pType)); - - // .?AVException and .?AVexception follow the same abi of const char * at pos 0 (__std_exception_data) after a vtable ptr of i dont care to define how many functions - // odds are, these assumptions about the ABI will never break. the QOL improvement of knowing of who is farting in my address space far exceeds an issue under win 720 targets 10 years in the future - if (strnicmp(descriptor->name, ".?AVException@", AuArraySize(".?AVException@") - 1) == 0) + auto exception = reinterpret_cast(ExceptionInfo->ExceptionRecord->ExceptionInformation[1]); + const auto catchableTypeArray = reinterpret_cast(reinterpret_cast(handle) + static_cast(throwInfo->pCatchableTypeArray)); + + AuString suffix; + bool derivedFromException = {}; + + for (int i = 0; i < catchableTypeArray->nCatchableTypes; i++) { - auto exception = reinterpret_cast(ExceptionInfo->ExceptionRecord->ExceptionInformation[1]); - if (IsReadable(exception)) + const auto type = reinterpret_cast (reinterpret_cast(handle) + static_cast(catchableTypeArray->arrayOfCatchableTypes[i])); + const auto descriptor = reinterpret_cast (reinterpret_cast(handle) + static_cast(type->pType)); + + entry.wincxx.str += (i == 0 ? "" : AuString(", ")) + descriptor->name(); + + if (strnicmp(descriptor->raw_name(), ".?AVException@", AuArraySize(".?AVException@") - 1) == 0) { - entry.wincxx.str = exception->what(); + derivedFromException = true; } - } - else if (((type->properties & CT_IsSimpleType) != 0) && - ((type->properties & CT_IsWinRTHandle) == 0)) - { - // assert descriptor->name == ".PEAD"? `DEAP.`? - auto possibleStringPointer = reinterpret_cast(ExceptionInfo->ExceptionRecord->ExceptionInformation[1]); - if (IsReadable(possibleStringPointer)) + else if (strncmp(descriptor->raw_name(), ".PEAD", AuArraySize(".PEAD") - 1) == 0) { - auto string = *possibleStringPointer; - // Not a string? I don't care, it has a null byte under 1k in a readable page - if (IsReadable(string) && (strnlen(string, 4096) < 1024)) + auto possibleStringPointer = reinterpret_cast(ExceptionInfo->ExceptionRecord->ExceptionInformation[1]); + if (IsReadable(possibleStringPointer)) { - entry.wincxx.str = string; + auto string = *possibleStringPointer; + if (IsReadable(string) && (strnlen(string, 4096) < 1024)) + { + if (suffix.size()) suffix += ", "; + suffix += string; + } + } + } + else if (strncmp(descriptor->raw_name(), kStringRawName.data(), kStringRawName.size()) == 0) + { + auto possibleStdStringPointer = reinterpret_cast(ExceptionInfo->ExceptionRecord->ExceptionInformation[1]); + if (IsReadable(possibleStdStringPointer)) + { + auto string = *possibleStdStringPointer; + if (suffix.size()) suffix += ", "; + suffix += string; } } } - //else if (strnicmp(descriptor->name, ".?AV", AuArraySize(".?AV") - 1) == 0) - //{ - // /* Annoying - // https://blog.quarkslab.com/visual-c-rtti-inspection.html - // This structure is very important to identify an object since it contains its VFT (field pVFTable) and its mangled name. That's why it usually starts with ".?AV", which means "a C++ class". These structures are stored in the section ".data". - // We decided to do pattern matching on ".?AV" to get the field name of _TypeInformation and thus retrieves the RTTICompleteObjectLocator. - // ... we would then have to traverse the hierarchy to determine the root most signature (std::exceptions vtable hash) - // TODO(Reece): fix me, this is evil and shouldn't make it into the wild - // Fix before 1.0 - // */ - // - // auto exception = reinterpret_cast(ExceptionInfo->ExceptionRecord->ExceptionInformation[1]); - // if (IsReadable(exception)) - // { - // entry.wincxx.str = exception->what(); - // } - //} - else if (strlen(descriptor->name) == 0) + + if (derivedFromException) { - auto exception = reinterpret_cast(ExceptionInfo->ExceptionRecord->ExceptionInformation[1]); - if (IsReadable(exception)) + auto fatanthony = exception->what(); + if (fatanthony) { - entry.wincxx.str = exception->what(); + entry.wincxx.str += AuString("\r\n ") + fatanthony; } } + + if (suffix.size()) + { + entry.wincxx.str += AuString("\r\n ") + suffix; + } } } diff --git a/Source/IO/FS/Async.NT.cpp b/Source/IO/FS/Async.NT.cpp index 7072edf6..c02c128e 100644 --- a/Source/IO/FS/Async.NT.cpp +++ b/Source/IO/FS/Async.NT.cpp @@ -183,11 +183,10 @@ namespace Aurora::IO::FS bool NtAsyncFileTransaction::StartRead(AuUInt64 offset, void *buffer, AuUInt32 length) { - if (this->latch_) + if (std::exchange(this->latch_, {})) { return {}; } - this->latch_ = {}; this->lastAbstractStat_ = length; this->lastAbstractOffset_ = offset; this->overlap_.Offset = offset & 0xFFFFFFFF; @@ -199,11 +198,10 @@ namespace Aurora::IO::FS bool NtAsyncFileTransaction::StartWrite(AuUInt64 offset, const void *buffer, AuUInt32 length) { - if (this->latch_) + if (std::exchange(this->latch_, {})) { return {}; } - this->latch_ = {}; this->lastAbstractStat_ = length; this->lastAbstractOffset_ = offset; this->overlap_.Offset = offset & 0xFFFFFFFF; @@ -219,8 +217,6 @@ namespace Aurora::IO::FS { return; } - - this->pin_ = {}; if (this->sub_) { @@ -228,6 +224,9 @@ namespace Aurora::IO::FS GetOverlappedResult(this->handle_->handle, &this->overlap_, &read, false); this->sub_->OnAsyncFileOpFinished(this->lastAbstractOffset_, read); } + + // TODO: test for write after free + std::exchange(this->pin_, {}); } bool NtAsyncFileTransaction::Complete()