[+] Begin expanding OSThread to offer more signals. This needs optimizing

This commit is contained in:
Reece Wilson 2021-10-25 18:08:28 +01:00
parent 8d0641ab00
commit 9ed6d2ff03
3 changed files with 69 additions and 17 deletions

View File

@ -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<void()> callback) = 0;
virtual AuSPtr<IWaitable> AsWaitable() = 0;
virtual AuSPtr<Loop::ILoopSource> AsLoopSource() = 0;
virtual AuSPtr<IWaitable> GetShutdownSignalWaitable() = 0;
virtual AuSPtr<Loop::ILoopSource> GetShutdownSignalLS() = 0;
};
}

View File

@ -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<Loop::ILoopSource> OSThread::AsLoopSource()
{
return this->terminateSignalLs_;
}
AuSPtr<IWaitable> OSThread::GetShutdownSignalWaitable()
{
return this->terminateSignal_;
}
AuSPtr<Loop::ILoopSource> OSThread::GetShutdownSignalLS()
{
return this->terminateSignalLs_;
}
}

View File

@ -38,7 +38,9 @@ namespace Aurora::Threading::Threads
void AddLastHopeTlsHook(const AuSPtr<Threading::Threads::IThreadFeature> &feature) override;
void _ThreadEP();
AuSPtr<Loop::ILoopSource> AsLoopSource() override;
AuSPtr<IWaitable> GetShutdownSignalWaitable() override;
AuSPtr<Loop::ILoopSource> 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<Loop::ILSEvent> terminateSignalLs_;
AuSPtr<Loop::ILSEvent> terminatedSignalLs_;
Primitives::CriticalSectionUnique_t exitOnlyOnce_;