#include "ehs/system/Thread.h" #include "ehs/system/CPU.h" #if defined(EHS_OS_WINDOWS) #include #elif defined(EHS_OS_LINUX) #include #include #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; } }