From 266bdc7737531da9ea2134a5ab22ccee0ffec7d7 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Wed, 9 Sep 2020 00:45:46 -0500 Subject: [PATCH] feat(thread): add thread functions --- storm/CMakeLists.txt | 3 + storm/Thread.hpp | 12 +++ storm/thread/SCritSect.cpp | 21 +++++ storm/thread/SCritSect.hpp | 24 ++++++ storm/thread/SEvent.cpp | 46 ++++++++++ storm/thread/SEvent.hpp | 15 ++++ storm/thread/SSyncObject.cpp | 136 ++++++++++++++++++++++++++++++ storm/thread/SSyncObject.hpp | 31 +++++++ storm/thread/SThread.cpp | 17 ++++ storm/thread/SThread.hpp | 13 +++ storm/thread/S_Thread.cpp | 9 ++ storm/thread/S_Thread.hpp | 36 ++++++++ storm/thread/mac/SThreadRunner.h | 19 +++++ storm/thread/mac/SThreadRunner.mm | 23 +++++ storm/thread/mac/S_Thread.mm | 43 ++++++++++ storm/thread/mac/Thread.mm | 75 ++++++++++++++++ 16 files changed, 523 insertions(+) create mode 100644 storm/Thread.hpp create mode 100644 storm/thread/SCritSect.cpp create mode 100644 storm/thread/SCritSect.hpp create mode 100644 storm/thread/SEvent.cpp create mode 100644 storm/thread/SEvent.hpp create mode 100644 storm/thread/SSyncObject.cpp create mode 100644 storm/thread/SSyncObject.hpp create mode 100644 storm/thread/SThread.cpp create mode 100644 storm/thread/SThread.hpp create mode 100644 storm/thread/S_Thread.cpp create mode 100644 storm/thread/S_Thread.hpp create mode 100644 storm/thread/mac/SThreadRunner.h create mode 100644 storm/thread/mac/SThreadRunner.mm create mode 100644 storm/thread/mac/S_Thread.mm create mode 100644 storm/thread/mac/Thread.mm diff --git a/storm/CMakeLists.txt b/storm/CMakeLists.txt index 11a759c..cd2371b 100644 --- a/storm/CMakeLists.txt +++ b/storm/CMakeLists.txt @@ -1,11 +1,14 @@ file(GLOB STORM_SOURCES "*.cpp" + "thread/*.cpp" ) if(PLATFORM_MAC) file(GLOB STORM_MAC_SOURCES "mac/*.cpp" "mac/*.mm" + "thread/mac/*.cpp" + "thread/mac/*.mm" ) list(APPEND STORM_SOURCES ${STORM_MAC_SOURCES}) endif() diff --git a/storm/Thread.hpp b/storm/Thread.hpp new file mode 100644 index 0000000..dfbc442 --- /dev/null +++ b/storm/Thread.hpp @@ -0,0 +1,12 @@ +#ifndef STORM_THREAD_HPP +#define STORM_THREAD_HPP + +#include "thread/SCritSect.hpp" +#include "thread/SEvent.hpp" +#include "thread/SSyncObject.hpp" +#include "thread/SThread.hpp" +#include + +int32_t SCreateThread(uint32_t (*threadProc)(void*), void* threadParam, void* a3, SThread* syncObject, const char* threadName); + +#endif diff --git a/storm/thread/SCritSect.cpp b/storm/thread/SCritSect.cpp new file mode 100644 index 0000000..2b53660 --- /dev/null +++ b/storm/thread/SCritSect.cpp @@ -0,0 +1,21 @@ +#include "thread/SCritSect.hpp" + +void SCritSect::Enter() { +#if defined(PLATFORM_WIN) + EnterCriticalSection(&this->m_opaqueData); +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + pthread_mutex_lock(&this->m_mutex); +#endif +} + +void SCritSect::Leave() { +#if defined(PLATFORM_WIN) + LeaveCriticalSection(&this->m_opaqueData); +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + pthread_mutex_unlock(&this->m_mutex); +#endif +} diff --git a/storm/thread/SCritSect.hpp b/storm/thread/SCritSect.hpp new file mode 100644 index 0000000..35c6602 --- /dev/null +++ b/storm/thread/SCritSect.hpp @@ -0,0 +1,24 @@ +#ifndef STORM_THREAD_S_CRIT_SECT_HPP +#define STORM_THREAD_S_CRIT_SECT_HPP + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) +#include +#endif + +class SCritSect { + public: + // Member variables +#if defined(PLATFORM_WIN) + CRITICAL_SECTION m_opaqueData; +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + pthread_mutex_t m_mutex; +#endif + + // Member functions + void Enter(void); + void Leave(void); +}; + +#endif diff --git a/storm/thread/SEvent.cpp b/storm/thread/SEvent.cpp new file mode 100644 index 0000000..df8057b --- /dev/null +++ b/storm/thread/SEvent.cpp @@ -0,0 +1,46 @@ +#include "thread/SEvent.hpp" + +SEvent::SEvent(int32_t manualReset, int32_t initialValue) + : SSyncObject() { +#if defined(PLATFORM_WIN) + this->m_opaqueData = CreateEventA(nullptr, manualReset, initialValue, nullptr); +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + this->m_int0 = 2 - (manualReset >= 1); + this->m_value = initialValue; + + pthread_cond_init(&this->m_cond, nullptr); +#endif +} + +int32_t SEvent::Reset() { +#if defined(PLATFORM_WIN) + return ResetEvent(this->m_opaqueData); +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + pthread_mutex_lock(&this->m_mutex); + this->m_value = 0; + pthread_mutex_unlock(&this->m_mutex); + + return 1; +#endif +} + +int32_t SEvent::Set() { +#if defined(PLATFORM_WIN) + return SetEvent(this->m_opaqueData); +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + pthread_mutex_lock(&this->m_mutex); + + this->m_value = 1; + pthread_cond_signal(&this->m_cond); + + pthread_mutex_unlock(&this->m_mutex); + + return 1; +#endif +} diff --git a/storm/thread/SEvent.hpp b/storm/thread/SEvent.hpp new file mode 100644 index 0000000..9f08de8 --- /dev/null +++ b/storm/thread/SEvent.hpp @@ -0,0 +1,15 @@ +#ifndef STORM_THREAD_S_EVENT_HPP +#define STORM_THREAD_S_EVENT_HPP + +#include "thread/SSyncObject.hpp" +#include + +class SEvent : public SSyncObject { + public: + // Member functions + SEvent(int32_t manualReset, int32_t); + int32_t Reset(void); + int32_t Set(void); +}; + +#endif diff --git a/storm/thread/SSyncObject.cpp b/storm/thread/SSyncObject.cpp new file mode 100644 index 0000000..8cb0a48 --- /dev/null +++ b/storm/thread/SSyncObject.cpp @@ -0,0 +1,136 @@ +#include "thread/SSyncObject.hpp" + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) +#include +#include +#include +#endif + +SSyncObject::SSyncObject() { +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + pthread_mutex_init(&this->m_mutex, 0); +#endif +} + +uint32_t SSyncObject::Wait(uint32_t timeoutMs) { +#if defined(PLATFORM_WIN) + return WaitForSingleObject(this->m_opaqueData, timeoutMs); +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + if (this->m_int0 == 6) { + // WAIT_FAILED + return 0xFFFFFFFF; + } + + if (timeoutMs != 0xFFFFFFFF) { + timeval v10; + timespec v11; + + if (timeoutMs) { + gettimeofday(&v10, nullptr); + + v11.tv_sec = v10.tv_sec + timeoutMs / 1000; + uint32_t v7 = 1000 * v10.tv_usec + 1000000 * (timeoutMs % 1000); + v11.tv_nsec = v7; + + if (v7 > 999999999) { + v11.tv_sec = v10.tv_sec + timeoutMs / 1000 + 1; + v11.tv_nsec = v7 - 1000000000; + } + } else { + v11.tv_sec = 0; + v11.tv_nsec = 0; + } + + while (true) { + int32_t v3 = pthread_mutex_trylock(&this->m_mutex); + + if (!v3) { + break; + } + + if (v3 != EBUSY) { + if (v3 != ETIMEDOUT) { + // WAIT_FAILED + return 0xFFFFFFFF; + } else { + // WAIT_TIMEOUT + return 0x00000102; + } + } + + gettimeofday(&v10, nullptr); + + if (v10.tv_sec > v11.tv_sec || (v10.tv_sec == v11.tv_sec && 1000 * v10.tv_usec >= v11.tv_nsec)) { + // WAIT_TIMEOUT + return 0x00000102; + } + + usleep(0); + } + + if (this->m_int0 == 3) { + // WAIT_OBJECT_0 + return 0; + } + + int32_t v4; + + while (true) { + v4 = this->m_value; + + if (v4) { + break; + } + + int32_t v5 = pthread_cond_timedwait(&this->m_cond, &this->m_mutex, &v11); + + if (v5) { + pthread_mutex_unlock(&this->m_mutex); + + if (v5 == ETIMEDOUT) { + // WAIT_TIMEOUT + return 0x00000102; + } else { + // WAIT_FAILED + return 0xFFFFFFFF; + } + } + } + + if (this->m_int0 == 2) { + this->m_value = 0; + } else if (this->m_int0 == 4) { + this->m_value = v4 - 1; + } + + pthread_mutex_unlock(&this->m_mutex); + + // WAIT_OBJECT_0 + return 0; + } + + pthread_mutex_lock(&this->m_mutex); + + if (this->m_int0 == 3) { + // WAIT_OBJECT_0 + return 0; + } + + while (!this->m_value) { + pthread_cond_wait(&this->m_cond, &this->m_mutex); + } + + if (this->m_int0 == 2) { + this->m_value = 0; + } else if (this->m_int0 == 4) { + this->m_value = this->m_value - 1; + } + + pthread_mutex_unlock(&this->m_mutex); + + // WAIT_OBJECT_0 + return 0; +#endif +} diff --git a/storm/thread/SSyncObject.hpp b/storm/thread/SSyncObject.hpp new file mode 100644 index 0000000..dd2e256 --- /dev/null +++ b/storm/thread/SSyncObject.hpp @@ -0,0 +1,31 @@ +#ifndef STORM_THREAD_S_SYNC_OBJECT_HPP +#define STORM_THREAD_S_SYNC_OBJECT_HPP + +#include + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) +#include +#endif + +class SSyncObject { + public: + // Member variables +#if defined(PLATFORM_WIN) + HANDLE m_opaqueData = nullptr; +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + int32_t m_int0 = 6; + int32_t m_value; + pthread_cond_t m_cond; + pthread_mutex_t m_mutex; +#endif + + // Member functions + SSyncObject(); + void Close(void); + bool Valid(void); + uint32_t Wait(uint32_t timeoutMs); +}; + +#endif diff --git a/storm/thread/SThread.cpp b/storm/thread/SThread.cpp new file mode 100644 index 0000000..f43938a --- /dev/null +++ b/storm/thread/SThread.cpp @@ -0,0 +1,17 @@ +#include "thread/SThread.hpp" +#include "Thread.hpp" + +int32_t SThread::Create(uint32_t (*threadProc)(void*), void* param, SThread& thread, char* threadName, uint32_t a5) { +#if defined(PLATFORM_WIN) + // TODO implement +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + thread.m_int0 = 5; + thread.m_value = 0; + pthread_cond_init(&thread.m_cond, nullptr); + + uint32_t v8; + return SCreateThread(threadProc, param, &v8, &thread, nullptr) != 0; +#endif +} diff --git a/storm/thread/SThread.hpp b/storm/thread/SThread.hpp new file mode 100644 index 0000000..e3a18f1 --- /dev/null +++ b/storm/thread/SThread.hpp @@ -0,0 +1,13 @@ +#ifndef STORM_THREAD_S_THREAD_HPP +#define STORM_THREAD_S_THREAD_HPP + +#include "thread/SSyncObject.hpp" +#include + +class SThread : public SSyncObject { + public: + // Static functions + static int32_t Create(uint32_t (*threadProc)(void*), void* param, SThread& thread, char* threadName, uint32_t a5); +}; + +#endif diff --git a/storm/thread/S_Thread.cpp b/storm/thread/S_Thread.cpp new file mode 100644 index 0000000..c9e9113 --- /dev/null +++ b/storm/thread/S_Thread.cpp @@ -0,0 +1,9 @@ +#include "thread/S_Thread.hpp" + +int32_t S_Thread::s_numthreads; + +int32_t S_Thread::s_maxthreads = 1024; + +uint32_t S_Thread::s_threadID; + +S_Thread::SThreadTrack S_Thread::s_threads[1024]; diff --git a/storm/thread/S_Thread.hpp b/storm/thread/S_Thread.hpp new file mode 100644 index 0000000..19a8de6 --- /dev/null +++ b/storm/thread/S_Thread.hpp @@ -0,0 +1,36 @@ +#ifndef STORM_THREAD_S__THREAD_HPP +#define STORM_THREAD_S__THREAD_HPP + +#include "thread/SThread.hpp" +#include + +typedef SThread SyncObjectData; + +struct SThreadParmBlock { + uint32_t (*threadProc)(void*); + void* threadParam; + uint32_t threadID; + SyncObjectData* syncObject; +}; + +class S_Thread { + public: + // Types + struct SThreadTrack { + int32_t suspended; + int32_t live; + uint32_t threadId; + char name[16]; + }; + + // Static variables + static int32_t s_numthreads; + static int32_t s_maxthreads; + static uint32_t s_threadID; + static SThreadTrack s_threads[1024]; + + // Static functions + static uint32_t s_SLaunchThread(void* threadParam); +}; + +#endif diff --git a/storm/thread/mac/SThreadRunner.h b/storm/thread/mac/SThreadRunner.h new file mode 100644 index 0000000..c03cc5d --- /dev/null +++ b/storm/thread/mac/SThreadRunner.h @@ -0,0 +1,19 @@ +#ifndef STORM_THREAD_MAC_S_THREAD_RUNNER_H +#define STORM_THREAD_MAC_S_THREAD_RUNNER_H + +#import + +struct SThreadParmBlock; + +@interface SThreadRunner : NSObject + +@property SThreadParmBlock* m_params; +@property(assign) NSAutoreleasePool* m_autoreleasePool; + +- (instancetype)init:(SThreadParmBlock*)params; + +- (void)run; + +@end + +#endif diff --git a/storm/thread/mac/SThreadRunner.mm b/storm/thread/mac/SThreadRunner.mm new file mode 100644 index 0000000..e112d52 --- /dev/null +++ b/storm/thread/mac/SThreadRunner.mm @@ -0,0 +1,23 @@ +#include "thread/mac/SThreadRunner.h" +#include "thread/S_Thread.hpp" + +@implementation SThreadRunner + +- (instancetype)init:(SThreadParmBlock*)params { + if (self = [super init]) { + self.m_params = params; + self.m_autoreleasePool = nullptr; + } + + return self; +} + +- (void)run { + self.m_autoreleasePool = [[NSAutoreleasePool alloc] init]; + + S_Thread::s_SLaunchThread(self.m_params); + + [self.m_autoreleasePool release]; +} + +@end diff --git a/storm/thread/mac/S_Thread.mm b/storm/thread/mac/S_Thread.mm new file mode 100644 index 0000000..99b2366 --- /dev/null +++ b/storm/thread/mac/S_Thread.mm @@ -0,0 +1,43 @@ +#include "thread/S_Thread.hpp" +#include "Memory.hpp" + +uint32_t S_Thread::s_SLaunchThread(void* threadParam) { + // TODO + // SClearFP(1); + + auto params = static_cast(threadParam); + + // TODO + // S_Thread::s_threadCrit.Enter(); + + // TODO + // - something involving pthread_self() + + // TODO + // S_Thread::s_threadCrit.Leave(); + + // TODO + // SErrAddFrameText("Calling thread proc %lx\n", params->threadProc); + params->threadProc(params->threadParam); + + // TODO + // S_Thread::s_threadCrit.Enter(); + + // TODO + // - remove tracking in S_Thread::s_threads + // - decrement num threads + + // TODO + // S_Thread::s_threadCrit.Leave(); + + if (params->syncObject) { + pthread_mutex_lock(¶ms->syncObject->m_mutex); + params->syncObject->m_value = 1; + pthread_mutex_unlock(¶ms->syncObject->m_mutex); + pthread_cond_signal(¶ms->syncObject->m_cond); + } + + SMemFree(threadParam); + + return 0; +} diff --git a/storm/thread/mac/Thread.mm b/storm/thread/mac/Thread.mm new file mode 100644 index 0000000..ea51791 --- /dev/null +++ b/storm/thread/mac/Thread.mm @@ -0,0 +1,75 @@ +#include "Thread.hpp" +#include "Memory.hpp" +#include "String.hpp" +#include "thread/S_Thread.hpp" +#include "thread/mac/SThreadRunner.h" +#include + +int32_t SCreateThread(uint32_t (*threadProc)(void*), void* threadParam, void* a3, SThread* syncObject, const char* threadName) { + if (!threadName) { + threadName = ""; + } + + // TODO + // S_Thread::s_threadCrit.Enter(); + + if (!S_Thread::s_numthreads) { + uint32_t threadId = S_Thread::s_threadID++; + + auto& mainThread = S_Thread::s_threads[0]; + mainThread.suspended = 0; + mainThread.live = 1; + mainThread.threadId = threadId; + SStrCopy(mainThread.name, "main", sizeof(mainThread.name)); + + S_Thread::s_numthreads++; + + // TODO + /* + if (StormGetOption(8, &v32, v33)) { + auto& cdThread = S_Thread::s_threads[S_Thread::s_numthreads]; + cdThread.suspended = 0; + cdThread.live = 1; + cdThread.threadId = v32; + SStrCopy(cdThread.name, "CdThreadProc", sizeof(cdThread.name)); + + S_Thread::s_numthreads++; + } + */ + } + + uint32_t threadId = S_Thread::s_threadID++; + + void* m = SMemAlloc(sizeof(SThreadParmBlock), __FILE__, __LINE__, 0x8); + auto params = new (m) SThreadParmBlock(); + params->threadProc = threadProc; + params->threadParam = threadParam; + params->threadID = threadId; + params->syncObject = syncObject; + + if (syncObject) { + syncObject->m_value = 0; + pthread_cond_init(&syncObject->m_cond, nullptr); + pthread_mutex_init(&syncObject->m_mutex, nullptr); + } + + // Launch thread + auto threadRunner = [[SThreadRunner alloc] init:params]; + [NSThread + detachNewThreadSelector:@selector(run) + toTarget:threadRunner + withObject:nil]; + + auto& thread = S_Thread::s_threads[S_Thread::s_numthreads]; + thread.suspended = 0; + thread.live = 1; + thread.threadId = threadId; + SStrCopy(thread.name, threadName, sizeof(thread.name)); + + S_Thread::s_numthreads++; + + // TODO + // S_Thread::s_threadCrit.Leave(); + + return threadId; +}