From 9ed6d2ff03c0214dcf673228a4a7127ccebe8fe7 Mon Sep 17 00:00:00 2001 From: Reece Date: Mon, 25 Oct 2021 18:08:28 +0100 Subject: [PATCH] [+] Begin expanding OSThread to offer more signals. This needs optimizing --- .../Threading/Threads/IAuroraThread.hpp | 40 ++++++++++++------- Source/Threading/Threads/OSThread.cpp | 39 +++++++++++++++++- Source/Threading/Threads/OSThread.hpp | 7 +++- 3 files changed, 69 insertions(+), 17 deletions(-) diff --git a/Include/Aurora/Threading/Threads/IAuroraThread.hpp b/Include/Aurora/Threading/Threads/IAuroraThread.hpp index 02b67f22..3c6adce6 100644 --- a/Include/Aurora/Threading/Threads/IAuroraThread.hpp +++ b/Include/Aurora/Threading/Threads/IAuroraThread.hpp @@ -7,32 +7,38 @@ ***/ #pragma once +namespace Aurora::Loop +{ + class ILoopSource; +} + namespace Aurora::Threading::Threads { class TLSView; /// Threads may be reimplemented as fibers or under some other userland context switcher + /// IAuroraThread objects when unique ownership is passed to you maintain ownership of the execution + /// Once you release your final reference to the IAuroraThread, the exit flag is set, the termination + /// signals are sent, and a watchdog watches over the termination of the thread. + /// + /// 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 + /// + /// WorkerMain() + /// while (!this->Exiting()) {} + /// + /// It's similar to Java + /// -> think while (Thread.currentThread().isAlive()) { doWork() } + /// -> plus you own the thread and its' execution class IAuroraThread { public: // TODO: consider detach support. - // It's actually really comfy that resetting/destroying the thread forces you to sync to termination - // The common/forced semantic: - // worker->SendExitSignal(); // sets the exiting flag - // DestoryThread(worker); // in the dtor, a watchdog is triggered over the shutdown of the thread - // - // WorkerMain() - // while (!this->Exiting()) {} - // - // It's Similar to Java - // -> think while (Thread.currentThread().isAlive()) { doWork() } - // -> plus you own the thread and its' execution - // - // One could always use AsWaitable() to get an event object that is triggered once the thread shuts down - // It's not like there isn't a traditional IWaitable interface support backing on thread termination // The problem is, if the aurora runtime transfers ownership of an IAuroraThread to you, you have to leak it // or you have to be forced to use the very comfy dtor mechanic. We need a detach function to overload this - // release is always terminate assumption. + // release-is-always-terminate assumption. virtual bool Run() = 0; virtual void Exit() = 0; @@ -56,5 +62,9 @@ namespace Aurora::Threading::Threads virtual void ExecuteInDeadThread(std::function callback) = 0; virtual AuSPtr AsWaitable() = 0; + virtual AuSPtr AsLoopSource() = 0; + + virtual AuSPtr GetShutdownSignalWaitable() = 0; + virtual AuSPtr GetShutdownSignalLS() = 0; }; } \ No newline at end of file diff --git a/Source/Threading/Threads/OSThread.cpp b/Source/Threading/Threads/OSThread.cpp index 992bb638..14646cd4 100644 --- a/Source/Threading/Threads/OSThread.cpp +++ b/Source/Threading/Threads/OSThread.cpp @@ -33,6 +33,12 @@ namespace Aurora::Threading::Threads { name_ = info.name.value_or("Aurora Thread"); terminated_ = Primitives::EventShared(true, false); + + // maybe we should atomic exchange compare these when needed frogthink + terminateSignal_ = Primitives::EventShared(true, false, true); + terminatedSignalLs_ = Loop::NewLSEvent(true, false); + terminateSignalLs_ = Loop::NewLSEvent(true, false, true); + exitOnlyOnce_ = Primitives::CriticalSectionUnique(); SysAssert(terminated_ ? true : false, "out of memory"); } @@ -97,6 +103,16 @@ namespace Aurora::Threading::Threads void OSThread::SendExitSignal() { exiting_ = true; + + if (this->terminateSignalLs_) + { + this->terminateSignalLs_->Set(); + } + + if (this->terminateSignal_) + { + this->terminateSignal_->Set(); + } } bool OSThread::Run() @@ -574,11 +590,17 @@ namespace Aurora::Threading::Threads { exitOnlyOnce_->Unlock(); terminated_->Set(); + + } + + if (terminatedSignalLs_) + { + terminatedSignalLs_->Set(); } + return true; } - void OSThread::TeminateOSContext(bool calledFromThis) { #if defined(AURORA_IS_MODERNNT_DERIVED) @@ -617,4 +639,19 @@ namespace Aurora::Threading::Threads } #endif } + + AuSPtr OSThread::AsLoopSource() + { + return this->terminateSignalLs_; + } + + AuSPtr OSThread::GetShutdownSignalWaitable() + { + return this->terminateSignal_; + } + + AuSPtr OSThread::GetShutdownSignalLS() + { + return this->terminateSignalLs_; + } } diff --git a/Source/Threading/Threads/OSThread.hpp b/Source/Threading/Threads/OSThread.hpp index dcff7648..79627eff 100644 --- a/Source/Threading/Threads/OSThread.hpp +++ b/Source/Threading/Threads/OSThread.hpp @@ -38,7 +38,9 @@ namespace Aurora::Threading::Threads void AddLastHopeTlsHook(const AuSPtr &feature) override; void _ThreadEP(); - + AuSPtr AsLoopSource() override; + AuSPtr GetShutdownSignalWaitable() override; + AuSPtr GetShutdownSignalLS() override; protected: bool Exit(bool willReturnToOS); @@ -66,6 +68,9 @@ namespace Aurora::Threading::Threads bool exiting_{}; bool contextUsed_{}; // can this thread instance execute code again? Primitives::EventShared_t terminated_; + Primitives::EventShared_t terminateSignal_; + AuSPtr terminateSignalLs_; + AuSPtr terminatedSignalLs_; Primitives::CriticalSectionUnique_t exitOnlyOnce_;