feat(thread): add thread functions

This commit is contained in:
fallenoak 2020-09-09 00:45:46 -05:00
parent d0487caba3
commit 266bdc7737
No known key found for this signature in database
GPG key ID: 7628F8E61AEA070D
16 changed files with 523 additions and 0 deletions

View file

@ -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()

12
storm/Thread.hpp Normal file
View file

@ -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 <cstdint>
int32_t SCreateThread(uint32_t (*threadProc)(void*), void* threadParam, void* a3, SThread* syncObject, const char* threadName);
#endif

View file

@ -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
}

View file

@ -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 <pthread.h>
#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

46
storm/thread/SEvent.cpp Normal file
View file

@ -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
}

15
storm/thread/SEvent.hpp Normal file
View file

@ -0,0 +1,15 @@
#ifndef STORM_THREAD_S_EVENT_HPP
#define STORM_THREAD_S_EVENT_HPP
#include "thread/SSyncObject.hpp"
#include <cstdint>
class SEvent : public SSyncObject {
public:
// Member functions
SEvent(int32_t manualReset, int32_t);
int32_t Reset(void);
int32_t Set(void);
};
#endif

View file

@ -0,0 +1,136 @@
#include "thread/SSyncObject.hpp"
#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
#include <cerrno>
#include <sys/time.h>
#include <unistd.h>
#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
}

View file

@ -0,0 +1,31 @@
#ifndef STORM_THREAD_S_SYNC_OBJECT_HPP
#define STORM_THREAD_S_SYNC_OBJECT_HPP
#include <cstdint>
#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
#include <pthread.h>
#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

17
storm/thread/SThread.cpp Normal file
View file

@ -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
}

13
storm/thread/SThread.hpp Normal file
View file

@ -0,0 +1,13 @@
#ifndef STORM_THREAD_S_THREAD_HPP
#define STORM_THREAD_S_THREAD_HPP
#include "thread/SSyncObject.hpp"
#include <cstdint>
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

View file

@ -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];

36
storm/thread/S_Thread.hpp Normal file
View file

@ -0,0 +1,36 @@
#ifndef STORM_THREAD_S__THREAD_HPP
#define STORM_THREAD_S__THREAD_HPP
#include "thread/SThread.hpp"
#include <cstdint>
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

View file

@ -0,0 +1,19 @@
#ifndef STORM_THREAD_MAC_S_THREAD_RUNNER_H
#define STORM_THREAD_MAC_S_THREAD_RUNNER_H
#import <Foundation/Foundation.h>
struct SThreadParmBlock;
@interface SThreadRunner : NSObject
@property SThreadParmBlock* m_params;
@property(assign) NSAutoreleasePool* m_autoreleasePool;
- (instancetype)init:(SThreadParmBlock*)params;
- (void)run;
@end
#endif

View file

@ -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

View file

@ -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<SThreadParmBlock*>(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(&params->syncObject->m_mutex);
params->syncObject->m_value = 1;
pthread_mutex_unlock(&params->syncObject->m_mutex);
pthread_cond_signal(&params->syncObject->m_cond);
}
SMemFree(threadParam);
return 0;
}

View file

@ -0,0 +1,75 @@
#include "Thread.hpp"
#include "Memory.hpp"
#include "String.hpp"
#include "thread/S_Thread.hpp"
#include "thread/mac/SThreadRunner.h"
#include <new>
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;
}