[+] Added AuroraInterface IThreadVectors for thread creation

[+] ThreadInfo's constructor now accepts additional arguments for name and stack
[*] Deprecate AbstractThreadVectors
[+] note about detaching threads
This commit is contained in:
Reece Wilson 2021-10-23 19:25:43 +01:00
parent 81abb38316
commit fe529f3dc4
7 changed files with 69 additions and 18 deletions

View File

@ -15,9 +15,15 @@ namespace Aurora::Threading::Threads
User-provided interface-style callback structure of thread related events <br>
DoRun/DoExit are called within the threads context
*/
/// @deprecated
struct AbstractThreadVectors
{
std::function<void(IAuroraThread *)> DoRun;
std::function<void(IAuroraThread *)> DoExit;
AuConsumer<IAuroraThread *> DoRun;
AuConsumer<IAuroraThread *> DoExit;
};
AUKN_INTERFACE(IThreadVectors,
AUI_METHOD(void, OnEntry, (IAuroraThread *, thread)),
AUI_METHOD(void, OnExit, (IAuroraThread *, thread))
);
}

View File

@ -15,6 +15,25 @@ namespace Aurora::Threading::Threads
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.
virtual bool Run() = 0;
virtual void Exit() = 0;
virtual bool Exiting() = 0;

View File

@ -11,11 +11,26 @@ namespace Aurora::Threading::Threads
{
struct ThreadInfo
{
const AbstractThreadVectors &vectors;
/// @deprecated
AbstractThreadVectors vectors;
AuSPtr<IThreadVectors> callbacks;
/// @deprecated
ThreadInfo(const AbstractThreadVectors &vectors) : vectors(vectors)
{}
ThreadInfo(const AuSPtr<IThreadVectors> &callbacks) : callbacks(callbacks)
{}
ThreadInfo(const AuSPtr<IThreadVectors> &callbacks, const AuString &name) : callbacks(callbacks), name(name)
{}
ThreadInfo(const AuSPtr<IThreadVectors> &callbacks, const AuString &name, AuUInt32 stackSize) : callbacks(callbacks), name(name), stackSize(stackSize)
{}
ThreadInfo(const AuSPtr<IThreadVectors> &callbacks, AuUInt32 stackSize) : callbacks(callbacks), name(name), stackSize(stackSize)
{}
AuOptional<AuUInt32> stackSize;
AuOptional<AuString> name;
};

View File

@ -30,9 +30,8 @@ namespace Aurora::Threading::Threads
static AbstractThreadVectors gDummyVectors {};
static ThreadInfo gDummyThreadInfo(gDummyVectors);
OSThread::OSThread(const ThreadInfo &info) : info_(vecs)
OSThread::OSThread(const ThreadInfo &info) : info_(info)
{
vecs = info.vectors;
info_.stackSize = info.stackSize;
info_.name = info.name;
name_ = info.name.value_or("Aurora Thread");
@ -121,10 +120,15 @@ namespace Aurora::Threading::Threads
{
try
{
// this functional backends are being deprecated
if (info_.vectors.DoRun)
{
info_.vectors.DoRun(this);
}
else if (info_.callbacks)
{
info_.callbacks->OnEntry(this);
}
}
catch (...)
{
@ -553,23 +557,27 @@ namespace Aurora::Threading::Threads
HookOnExit();
// dispatch kill callback
if (info_.vectors.DoExit)
try
{
try
// dispatch kill callback
if (info_.vectors.DoExit)
{
info_.vectors.DoExit(this);
}
catch (...)
else if (info_.callbacks)
{
Debug::PrintError();
LogWarn("Couldn't deinitialize thread");
LogWarn("The smart thing to do at this point would be to panic");
LogWarn("...but we could continue");
LogWarn("Carrying on despite the potential for data integrity loss and memory leaks");
Telemetry::Mayday();
info_.callbacks->OnExit(this);
}
}
catch (...)
{
Debug::PrintError();
LogWarn("Couldn't deinitialize thread");
LogWarn("The smart thing to do at this point would be to panic");
LogWarn("...but we could continue");
LogWarn("Carrying on despite the potential for data integrity loss and memory leaks");
Telemetry::Mayday();
}
HookReleaseThreadResources();

View File

@ -59,7 +59,6 @@ namespace Aurora::Threading::Threads
Primitives::SpinLock tlsLock_;
AuSPtr<TLSView> tls_;
AuString name_;
AbstractThreadVectors vecs;
ThreadInfo info_;
AuUInt32 affinityProcessMask_ = 0xFFFFFFFF;
EThreadPrio prio_ = EThreadPrio::ePrioNormal;

View File

@ -87,7 +87,10 @@ namespace Aurora::Threading::Threads
void OsThreadShutdown(AuUInt64 threadId)
{
SysAssertDbg(tlsOsFallbackThread.threadId == threadId);
SafeDelete<OSThread *>(tlsOsFallbackThread.handle);
if (tlsOsFallbackThread.handle)
{
SafeDelete<OSThread *>(tlsOsFallbackThread.handle);
}
}
AUKN_SYM IAuroraThread *GetThread()

View File

@ -13,6 +13,7 @@ namespace Aurora::Threading::Threads
{
AUKN_SYM IAuroraThread *ThreadNew(const ThreadInfo &info)
{
if (!info.callbacks && !(info.vectors.DoRun)) return {};
return _new OSThread(info);
}