AuroraRuntime/Source/Threading/Threads/ThreadHandles.cpp
2022-04-02 01:48:29 +01:00

207 lines
5.7 KiB
C++

/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ThreadHandles.cpp
Date: 2021-6-19
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "Threads.hpp"
#include "ThreadHandles.hpp"
#include "OSThread.hpp"
namespace Aurora::Threading::Threads
{
struct BasicThreadId
{
AuUInt64 threadId;
AuUInt64 unixThreadId;
};
struct Temp
{
~Temp()
{
bActive = false;
}
bool bActive {true};
AuThreadPrimitives::SpinLock gMutex;
AuHashMap<AuUInt, IAuroraThread *> gUnixHandlesToThreads;
AuHashMap<AuUInt, IAuroraThread *> gNativeHandlesToThreads;
} gVariables;
static IAuroraThread *OsThreadAnnounce(AuUInt64 threadId);
static void OsThreadShutdown(AuUInt64 threadId);
static AuUInt64 GetThreadIdHandle()
{
#if defined(AURORA_IS_MODERNNT_DERIVED)
// Note: The OsThreadAnnounce function takes ownership of win32 handles.
// The detor of OSThread is responsible for cleaning up this handle.
HANDLE ret;
auto process = GetCurrentProcess();
auto thread = GetCurrentProcess();
if (!DuplicateHandle(process, thread, process, &ret, DUPLICATE_SAME_ACCESS, FALSE, DUPLICATE_SAME_ACCESS))
{
return reinterpret_cast<AuUInt64>(INVALID_HANDLE_VALUE);
}
return reinterpret_cast<AuUInt64>(ret);
#elif defined(AURORA_HAS_PTHREADS)
return pthread_self(); // todo: it's a shame. this is a huge hack, because, all we're doing is providing a pthread type for the OSThread constructor
// pthread handles free by magic. we don't need to destroy this. we can get away with chucking this as an handle in later POSIX versions
#endif
}
static void RegisterThisThread(BasicThreadId id, IAuroraThread *handle)
{
if (!gVariables.bActive)
{
return;
}
AU_LOCK_GUARD(gVariables.gMutex);
#if defined(AURORA_IS_POSIX_DERIVED)
AuTryInsert(gVariables.gUnixHandlesToThreads, id.unixThreadId, handle);
#endif
AuTryInsert(gVariables.gNativeHandlesToThreads, id.threadId, handle);
}
static void ReleaseThisThread(BasicThreadId id)
{
if (!gVariables.bActive)
{
return;
}
AU_LOCK_GUARD(gVariables.gMutex);
#if defined(AURORA_IS_POSIX_DERIVED)
AuTryRemove(gVariables.gUnixHandlesToThreads, id.unixThreadId);
#endif
AuTryRemove(gVariables.gNativeHandlesToThreads, id.threadId);
}
struct OSFallbackThread : BasicThreadId
{
IAuroraThread *handle;
OSFallbackThread()
{
threadId = GetThreadIdHandle();
handle = OsThreadAnnounce(threadId);
#if defined(AURORA_IS_POSIX_DERIVED)
unixThreadId = gettid();
#endif
RegisterThisThread({threadId, unixThreadId}, handle);
}
~OSFallbackThread()
{
OsThreadShutdown(threadId);
ReleaseThisThread({threadId, unixThreadId});
}
};
#if defined(AURORA_COMPILER_MSVC) || defined(AURORA_COMPILER_CLANG)
#define DEFINE_SPEEDY_TLS(type, name) static thread_local type name;
#elif defined(AURORA_COMPILER_GCC)
#define DEFINE_SPEEDY_TLS(type, name) __thread type name __attribute__((tls_model("initial-exec")));
#else
#define DEFINE_SPEEDY_TLS(type, name) static thread_local type name;
#endif
DEFINE_SPEEDY_TLS(OSFallbackThread, tlsOsFallbackThread);
DEFINE_SPEEDY_TLS(IAuroraThread*, tlsCurrentThread);
void HandleRemove()
{
RegisterThisThread({tlsOsFallbackThread.threadId, tlsOsFallbackThread.unixThreadId}, tlsOsFallbackThread.handle);
tlsCurrentThread = nullptr;
}
void HandleRegister(IAuroraThread *thread)
{
RegisterThisThread({tlsOsFallbackThread.threadId, tlsOsFallbackThread.unixThreadId}, thread);
tlsCurrentThread = thread;
}
IAuroraThread *HandleCurrent()
{
return tlsCurrentThread;
}
IAuroraThread *OsThreadAnnounce(AuUInt64 threadId)
{
SysAssertDbg(tlsOsFallbackThread.threadId == threadId);
return _new OSThread(threadId);
}
void OsThreadShutdown(AuUInt64 threadId)
{
SysAssertDbg(tlsOsFallbackThread.threadId == threadId);
if (tlsOsFallbackThread.handle)
{
AuSafeDelete<OSThread *>(tlsOsFallbackThread.handle);
}
}
IAuroraThread *GetThreadByPOSIXPid(AuUInt validPid)
{
if (!gVariables.bActive)
{
return {};
}
AU_LOCK_GUARD(gVariables.gMutex);
auto itr = gVariables.gUnixHandlesToThreads.find(validPid);
if (itr == gVariables.gUnixHandlesToThreads.end()) return {};
return itr->second;
}
IAuroraThread *GetThreadByOSHandle(AuUInt validPid)
{
if (!gVariables.bActive)
{
return {};
}
AU_LOCK_GUARD(gVariables.gMutex);
auto itr = gVariables.gNativeHandlesToThreads.find(validPid);
if (itr == gVariables.gNativeHandlesToThreads.end()) return {};
return itr->second;
}
AUKN_SYM bool DeadTest()
{
return !gVariables.bActive;
}
AUKN_SYM IAuroraThread *GetThread()
{
if (DeadTest())
{
return {};
}
auto ret = tlsCurrentThread;
if (ret)
{
return ret;
}
ret = tlsOsFallbackThread.handle;
if (ret)
{
return ret;
}
SysPanic("no tls context");
}
AUKN_SYM AuThreadId_t GetThreadId()
{
return reinterpret_cast<AuThreadId_t>(GetThread());
}
}