[*] Wouldn't it be cool if Linux could safely exit under other conditions without core dumping?

This commit is contained in:
Reece Wilson 2022-08-14 12:01:54 +01:00
parent 88887434ae
commit 0fe4ad2087
5 changed files with 112 additions and 22 deletions

View File

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

View File

@ -62,5 +62,47 @@
#include <AuroraRuntime.hpp>
inline Aurora::RuntimeStartInfo gRuntimeConfig;
inline int gRuntimeRunLevel {0};
using namespace Aurora::Logging;
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(); \
} \
} \
}

View File

@ -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<AuMach>(&value_);
mach = reinterpret_cast<AuMach>(&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");
}

View File

@ -11,24 +11,24 @@
#if !defined(_AURUNTIME_GENERIC_SEMAPHORE) && !defined(AURORA_IS_XNU_DERIVED)
#include <Source/Time/Time.hpp>
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<AuMach>(&value_);
mach = reinterpret_cast<AuMach>(&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");
}

View File

@ -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<void()> callback)