207 lines
5.7 KiB
C++
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());
|
|
}
|
|
} |