EHS/src/system/Thread.cpp

284 lines
6.5 KiB
C++
Raw Normal View History

2024-02-05 22:25:30 -08:00
#include "ehs/system/Thread.h"
#include "ehs/system/CPU.h"
#if defined(EHS_OS_WINDOWS)
#include <avrt.h>
#elif defined(EHS_OS_LINUX)
#include <pthread.h>
#include <unistd.h>
#endif
namespace ehs
{
UInt_32 Thread::mainId = GetCurrentId();
#ifdef EHS_OS_WINDOWS
Handle Thread::mainTaskHdl = nullptr;
UInt_32 Thread::mainTaskIndex = 0;
#endif
Thread::~Thread()
{
Join();
}
Thread::Thread(const UInt_64 stackSize)
: stackSize(stackSize), hdl(EHS_INVALID_THREAD), id(0)
#ifdef EHS_OS_WINDOWS
,taskHdl(nullptr), taskIndex(0)
#endif
{
}
Thread::Thread(const Thread& thread)
: stackSize(thread.stackSize), hdl(EHS_INVALID_THREAD), id(0)
#ifdef EHS_OS_WINDOWS
, taskHdl(nullptr), taskIndex(0)
#endif
{
}
Thread& Thread::operator=(const Thread& thread)
{
if (this == &thread)
return *this;
stackSize = thread.stackSize;
hdl = EHS_INVALID_THREAD;
id = 0;
#ifdef EHS_OS_WINDOWS
taskHdl = nullptr;
taskIndex = 0;
#endif
return* this;
}
void Thread::Start(UInt_32 (*cb)(void*), void* args)
{
#if defined(EHS_OS_WINDOWS)
hdl = CreateThread(nullptr, stackSize, (LPTHREAD_START_ROUTINE)cb, args, 0, (DWORD*)&id);
if (!hdl)
EHS_LOG_INT("Error", 0, "Failed to start thread with error #" + Str_8::FromNum(GetLastError()) + ".");
#elif defined(EHS_OS_LINUX)
UInt_64* rArgs = new UInt_64[sizeof(UInt_64) * 2];
rArgs[0] = (UInt_64)cb;
rArgs[1] = (UInt_64)args;
pthread_create((pthread_t*)&hdl, nullptr, Redirect, (void*)rArgs);
#endif
}
bool Thread::Join(const unsigned int timeout)
{
if (hdl == EHS_INVALID_THREAD)
return false;
#if defined(EHS_WINDOWS)
unsigned int r = WaitForSingleObject(hdl, timeout);
if (r == WAIT_ABANDONED)
{
EHS_LOG_INT("Error", 0, "Abandoned wait because a mutex was not released.");
return false;
}
else if (r == WAIT_TIMEOUT)
{
return false;
}
else if (r == WAIT_FAILED)
{
EHS_LOG_INT("Error", 1, "Failed to wait for thread with error #" + Str_8::FromNum(GetLastError()) + ".");
return false;
}
mainTaskIndex = 0;
#elif defined(EHS_OS_LINUX)
int code = pthread_join((pthread_t)hdl, nullptr);
if (code != 0)
EHS_LOG_INT("Error", 1, "Failed to wait for thread with error #" + Str_8::FromNum(code) + ".");
hdl = EHS_INVALID_THREAD;
#endif
return true;
}
void Thread::Detach()
{
if (!hdl)
return;
#if defined(EHS_OS_WINDOWS)
if (!CloseHandle(hdl))
{
EHS_LOG_INT("Error", 0, "Failed to detach thread with error #" + Str_8::FromNum(GetLastError()) + ".");
return;
}
#elif defined(EHS_OS_LINUX)
pthread_detach(hdl);
hdl = EHS_INVALID_THREAD;
#endif
}
UInt_64 Thread::GetStackSize() const
{
return stackSize;
}
THandle Thread::GetHandle() const
{
return hdl;
}
UInt_32 Thread::GetId() const
{
return id;
}
bool Thread::IsCurrent() const
{
return id == GetCurrentId();
}
bool Thread::IsValid() const
{
return hdl;
}
#ifdef EHS_OS_WINDOWS
void Thread::SetTaskType_32(const Str_32& task)
{
if (!IsCurrent())
return;
taskHdl = AvSetMmThreadCharacteristicsW(UTF::To_16(task), (LPDWORD)&taskIndex);
if (!taskHdl)
EHS_LOG_INT("Error", 0, "Failed to set the thread's characteristics with error #" + Str_8::FromNum(GetLastError()) + ".");
}
void Thread::SetTaskType_16(const Str_16& task)
{
if (!IsCurrent())
return;
taskHdl = AvSetMmThreadCharacteristicsW(task, (LPDWORD)&taskIndex);
if (!taskHdl)
EHS_LOG_INT("Error", 0, "Failed to set the thread's characteristics with error #" + Str_8::FromNum(GetLastError()) + ".");
}
void Thread::SetTaskType_8(const Str_8& task)
{
if (!IsCurrent())
return;
taskHdl = AvSetMmThreadCharacteristicsW(UTF::To_16(task), (LPDWORD)&taskIndex);
if (!taskHdl)
EHS_LOG_INT("Error", 0, "Failed to set the thread's characteristics with error #" + Str_8::FromNum(GetLastError()) + ".");
}
void Thread::RevertTaskType()
{
if (!IsCurrent())
return;
if (!AvRevertMmThreadCharacteristics(taskHdl))
EHS_LOG_INT("Error", 0, "Failed to revert the thread's characteristics with error #" + Str_8::FromNum(GetLastError()) + ".");
taskIndex = 0;
}
#endif
UInt_32 Thread::GetMainId()
{
return mainId;
}
UInt_64 Thread::GetCurrentId()
{
#if defined(EHS_OS_WINDOWS)
return GetCurrentThreadId();
#elif defined(EHS_OS_LINUX)
return pthread_self();
#endif
}
#ifdef EHS_OS_WINDOWS
void Thread::SetMainTaskType_32(const Str_32& task)
{
if (GetCurrentId() != mainId)
return;
mainTaskHdl = AvSetMmThreadCharacteristicsW(UTF::To_16(task), (LPDWORD)&mainTaskIndex);
if (!mainTaskHdl)
EHS_LOG_INT("Error", 0, "Failed to set the main thread's characteristics with error #" + Str_8::FromNum(GetLastError()) + ".");
}
void Thread::SetMainTaskType_16(const Str_16& task)
{
if (GetCurrentId() != mainId)
return;
mainTaskHdl = AvSetMmThreadCharacteristicsW(task, (LPDWORD)&mainTaskIndex);
if (!mainTaskHdl)
EHS_LOG_INT("Error", 0, "Failed to set the main thread's characteristics with error #" + Str_8::FromNum(GetLastError()) + ".");
}
void Thread::SetMainTaskType_8(const Str_8& task)
{
if (GetCurrentId() != mainId)
return;
mainTaskHdl = AvSetMmThreadCharacteristicsW(UTF::To_16(task), (LPDWORD)&mainTaskIndex);
if (!mainTaskHdl)
EHS_LOG_INT("Error", 0, "Failed to set the main thread's characteristics with error #" + Str_8::FromNum(GetLastError()) + ".");
}
void Thread::RevertMainTaskType()
{
if (GetCurrentId() != mainId)
return;
if (!AvRevertMmThreadCharacteristics(mainTaskHdl))
EHS_LOG_INT("Error", 0, "Failed to revert the main thread's characteristics with error #" + Str_8::FromNum(GetLastError()) + ".");
mainTaskIndex = 0;
}
#endif
float Thread::HardSleepFor(const float seconds)
{
UInt_64 freq = CPU::GetTSC_Freq();
UInt_64 start = CPU::GetTSC();
float elapsed = 0.0f;
while ((elapsed = (float)(CPU::GetTSC() - start) / (float)freq) <= seconds);
return elapsed;
}
void Thread::SleepFor(const UInt_32 miliseconds)
{
#if defined(EHS_OS_WINDOWS)
Sleep(miliseconds);
#elif defined(EHS_OS_LINUX)
timespec req = {miliseconds / 1000, miliseconds % 1000 * 1000000};
nanosleep(&req, nullptr);
#endif
}
void* Thread::Redirect(void *args)
{
UInt_64* rArgs = (UInt_64*)args;
UInt_32 (*cb)(void*) = (UInt_32 (*)(void*))rArgs[0];
void* params = (void*)rArgs[1];
UInt_32* code = new UInt_32();
*code = cb(params);
delete[] rArgs;
return code;
}
}