From 0fe4ad208760af7ef0859216f8417a242814f4cd Mon Sep 17 00:00:00 2001 From: J Reece Wilson Date: Sun, 14 Aug 2022 12:01:54 +0100 Subject: [PATCH] [*] Wouldn't it be cool if Linux could safely exit under other conditions without core dumping? --- Source/Entrypoint.cpp | 15 +++++++ Source/RuntimeInternal.hpp | 44 ++++++++++++++++++- Source/Threading/Primitives/Mutex.Unix.cpp | 16 +++---- .../Threading/Primitives/Semaphore.Unix.cpp | 18 ++++---- Source/Threading/Threads/OSThread.cpp | 41 +++++++++++++++-- 5 files changed, 112 insertions(+), 22 deletions(-) diff --git a/Source/Entrypoint.cpp b/Source/Entrypoint.cpp index e3c4b06d..a194c6f4 100644 --- a/Source/Entrypoint.cpp +++ b/Source/Entrypoint.cpp @@ -36,8 +36,13 @@ void LinuxSuperSecretIOTick(); #endif + +static thread_local bool tlsHackIsMainThread {}; + static void Init() { + gRuntimeRunLevel = 1; + tlsHackIsMainThread = true; #if defined(AURORA_PLATFORM_WIN32) Aurora::Extensions::Win32::InitDarkMode(); #endif @@ -63,6 +68,7 @@ static void Init() Aurora::Processes::Init(); Aurora::Hashing::InitHashing(); Aurora::Async::InitAsync(); + gRuntimeRunLevel = 2; } static void Pump() @@ -76,7 +82,10 @@ static void Pump() static void Deinit() { + tlsHackIsMainThread = true; // this helps + gRuntimeRunLevel = 3; Aurora::Exit::PostLevel(AuThreads::GetThread(), Aurora::Exit::ETriggerLevel::eSafeTermination); + gRuntimeRunLevel = 4; Aurora::RNG::Release(); Aurora::Async::ShutdownAsync(); Aurora::Grug::DeinitGrug(); @@ -84,12 +93,18 @@ static void Deinit() Aurora::Processes::Deinit(); Aurora::Exit::DeinitExit(); Aurora::IO::Deinit(); + gRuntimeRunLevel = 5; } namespace Aurora { static bool gRuntimeHasStarted {}; + bool RuntimeIsMainThread() + { + return tlsHackIsMainThread; + } + AUKN_SYM void RuntimeStart(const RuntimeStartInfo &info) { gRuntimeConfig = info; diff --git a/Source/RuntimeInternal.hpp b/Source/RuntimeInternal.hpp index b4aa4784..a8180a74 100644 --- a/Source/RuntimeInternal.hpp +++ b/Source/RuntimeInternal.hpp @@ -62,5 +62,47 @@ #include inline Aurora::RuntimeStartInfo gRuntimeConfig; +inline int gRuntimeRunLevel {0}; -using namespace Aurora::Logging; \ No newline at end of file + +using namespace Aurora::Logging; + +namespace Aurora +{ +#if defined(AU_CFG_ID_DEBUG) + static const bool kIsDebugBuild = true; +#else + static const bool kIsDebugBuild = false; +#endif + + bool RuntimeIsMainThread(); +} + +#define RUNTIME_ASSERT_SHUTDOWN_SAFE(value, ...) \ + if (gRuntimeRunLevel < 3) \ + { \ + SysAssert(value, __VA_ARGS__); \ + } \ + else \ + { \ + if (!bool(value)) \ + { \ + try \ + { \ + AuLogWarn("Error while shutting down: {}", fmt::format(__VA_ARGS__)); \ + } \ + catch (...) {} \ + if (!kIsDebugBuild) SysPushErrorGeneric(__VA_ARGS__); \ + if (RuntimeIsMainThread()) \ + { \ + if (gRuntimeRunLevel < /*5*/ 4 /*i dont like this and i think i know the problem*/) \ + { \ + SysPanic("Error while shutting down: {}", fmt::format(__VA_ARGS__));\ + } \ + } \ + else \ + { \ + Threading::Threads::TerminateCurrent(); \ + } \ + } \ + } \ No newline at end of file diff --git a/Source/Threading/Primitives/Mutex.Unix.cpp b/Source/Threading/Primitives/Mutex.Unix.cpp index b7c5a04f..d0bec0da 100644 --- a/Source/Threading/Primitives/Mutex.Unix.cpp +++ b/Source/Threading/Primitives/Mutex.Unix.cpp @@ -17,25 +17,25 @@ namespace Aurora::Threading::Primitives { Mutex::Mutex() { - auto status = pthread_mutex_init(&value_, nullptr) == 0; + auto status = pthread_mutex_init(&this->value_, nullptr) == 0; SysAssert(status, "Mutex init failed"); } Mutex::~Mutex() { - auto status = pthread_mutex_destroy(&value_); - SysAssert(status == 0, "Mutex destruct failed, {}", status); + int status = pthread_mutex_destroy(&this->value_); + RUNTIME_ASSERT_SHUTDOWN_SAFE(status == 0, "Mutex destruct failed, {} {}", status, errno); } bool Mutex::HasOSHandle(AuMach &mach) { - mach = reinterpret_cast(&value_); + mach = reinterpret_cast(&this->value_); return true; } bool Mutex::TryLock() { - return pthread_mutex_trylock(&value_) == 0; + return pthread_mutex_trylock(&this->value_) == 0; } bool Mutex::HasLockImplementation() @@ -56,7 +56,7 @@ namespace Aurora::Threading::Primitives int ret {}; do { - if ((ret = pthread_mutex_lock(&value_)) == 0) + if ((ret = pthread_mutex_lock(&this->value_)) == 0) { return true; } @@ -73,7 +73,7 @@ namespace Aurora::Threading::Primitives do { - ret = pthread_mutex_timedlock(&value_, &tspec); + ret = pthread_mutex_timedlock(&this->value_, &tspec); if (ret == 0) { @@ -94,7 +94,7 @@ namespace Aurora::Threading::Primitives void Mutex::Unlock() { - auto status = pthread_mutex_unlock(&value_) == 0; + auto status = pthread_mutex_unlock(&this->value_) == 0; SysAssert(status, "Mutex release error"); } diff --git a/Source/Threading/Primitives/Semaphore.Unix.cpp b/Source/Threading/Primitives/Semaphore.Unix.cpp index 647c01d4..b684785d 100644 --- a/Source/Threading/Primitives/Semaphore.Unix.cpp +++ b/Source/Threading/Primitives/Semaphore.Unix.cpp @@ -11,24 +11,24 @@ #if !defined(_AURUNTIME_GENERIC_SEMAPHORE) && !defined(AURORA_IS_XNU_DERIVED) #include - + namespace Aurora::Threading::Primitives { Semaphore::Semaphore(long intialValue) { - auto status = sem_init(&value_, 0, intialValue) == 0; + auto status = sem_init(&this->value_, 0, intialValue) == 0; SysAssert(status, "Semaphore init failed"); } Semaphore::~Semaphore() { - auto status = sem_destroy(&value_) == 0; - SysAssert(status, "Semaphore destroy failed"); + int status = sem_destroy(&this->value_); + RUNTIME_ASSERT_SHUTDOWN_SAFE(status == 0, "Semaphore destroy failed: {} {}", status, errno); } bool Semaphore::HasOSHandle(AuMach &mach) { - mach = reinterpret_cast(&value_); + mach = reinterpret_cast(&this->value_); return true; } @@ -39,7 +39,7 @@ namespace Aurora::Threading::Primitives bool Semaphore::TryLock() { - return sem_trywait(&value_) == 0; + return sem_trywait(&this->value_) == 0; } bool Semaphore::Lock(AuUInt64 timeout) @@ -50,7 +50,7 @@ namespace Aurora::Threading::Primitives do { - if ((ret = sem_wait(&value_)) == 0) + if ((ret = sem_wait(&this->value_)) == 0) { return true; } @@ -69,7 +69,7 @@ namespace Aurora::Threading::Primitives do { - ret = sem_timedwait(&value_, &tspec); + ret = sem_timedwait(&this->value_, &tspec); if (ret == 0) { @@ -104,7 +104,7 @@ namespace Aurora::Threading::Primitives void Semaphore::Unlock() { - auto status = sem_post(&value_) == 0; + auto status = sem_post(&this->value_) == 0; SysAssert(status, "Semaphore release error"); } diff --git a/Source/Threading/Threads/OSThread.cpp b/Source/Threading/Threads/OSThread.cpp index 69a6b234..c0e51f45 100644 --- a/Source/Threading/Threads/OSThread.cpp +++ b/Source/Threading/Threads/OSThread.cpp @@ -58,11 +58,11 @@ namespace Aurora::Threading::Threads OSThread::OSThread(const ThreadInfo &info) : info_(info) { this->name_ = info.name.value_or("Aurora Thread"); - this->terminated_ = Primitives::EventShared(true, false); + this->terminated_ = Primitives::EventShared(true, false, true); // maybe we should atomic exchange compare these when needed frogthink this->terminateSignal_ = Primitives::EventShared(true, false, true); - this->terminatedSignalLs_ = AuLoop::NewLSEvent(true, false); + this->terminatedSignalLs_ = AuLoop::NewLSEvent(true, false, true); this->terminateSignalLs_ = AuLoop::NewLSEvent(true, false, true); this->exitOnlyOnce_ = Primitives::CriticalSectionUnique(); @@ -114,8 +114,28 @@ namespace Aurora::Threading::Threads } else { - Exit(); - WaitFor(this->terminated_.get()); + if (gRuntimeRunLevel < 3) + { + Exit(); + } + else + { + // Kill the current OS thread instance + TeminateOSContext(false); + + // Dispatch kill callback from within an emulated thread context (no switch, just just change thread tls) + ExecuteInDeadThread([=]() + { + this->InternalKill(true); + }); + + this->exitOnlyOnce_->Unlock(); + } + + if (gRuntimeRunLevel < 4) // minimum: async deinit level + { + WaitFor(this->terminated_.get()); + } } } @@ -414,11 +434,24 @@ namespace Aurora::Threading::Threads task_(); } } + +#if !defined(AURORA_IS_POSIX_DERIVED) catch (...) { SysPushErrorHAL("OS Thread Aborted"); } Exit(true); +#else + catch (...) + { + if (!Aurora::kIsDebugBuild) + { + SysPushErrorHAL("OS Thread Aborted"); + } + Exit(true); + throw; // bc c-world cant be compatible bc free-iq half-assed software + } +#endif } void OSThread::ExecuteInDeadThread(AuFunction callback)