aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfusion32 <marcopuzziello@gmail.com>2025-05-22 14:43:54 -0300
committerfusion32 <marcopuzziello@gmail.com>2025-05-22 14:44:31 -0300
commit3edeaf1f5280b88da6cf60ad65f9c5c5c8d508c2 (patch)
tree1cb1505304bdfe6b6115296340e92765e2421f63
parent297e8450d80411d81f0aaeee642053354125bd6d (diff)
downloadgame-3edeaf1f5280b88da6cf60ad65f9c5c5c8d508c2.tar.gz
game-3edeaf1f5280b88da6cf60ad65f9c5c5c8d508c2.zip
implement threading API
-rw-r--r--TODO.md2
-rw-r--r--reference/types.hh13
-rw-r--r--src/thread.cc110
-rw-r--r--src/thread.hh33
4 files changed, 144 insertions, 14 deletions
diff --git a/TODO.md b/TODO.md
index f9d6da5..2e42887 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,5 +1,5 @@
## TODO NEXT
-- THREADS
+- Split main.hh -> common.hh, shm.hh, time.hh, util.hh
- TReadStream/TWriteStream
- TReadBuffer/TWriteBuffer
- TReadBinaryFile/TWriteBinaryFile
diff --git a/reference/types.hh b/reference/types.hh
index 5bfc014..bee9117 100644
--- a/reference/types.hh
+++ b/reference/types.hh
@@ -96,12 +96,6 @@ struct TDatabasePoolConnection {
bool TransactionRunning;
};
-struct Semaphore {
- int value;
- struct pthread_mutex_t mutex;
- struct pthread_cond_t condition;
-};
-
struct TDatabaseConnectionPool {
int NumberOfConnections;
struct TDatabaseSettings DatabaseSettings;
@@ -786,13 +780,6 @@ struct TFindCreatures {
bool finished;
};
-typedef int (ThreadFunction)(void *);
-struct TThreadStarter {
- ThreadFunction *Function;
- void *Argument;
- bool Detach;
-};
-
struct TReaderThreadOrder {
enum TReaderThreadOrderType OrderType;
int SectorX;
diff --git a/src/thread.cc b/src/thread.cc
new file mode 100644
index 0000000..2d2d427
--- /dev/null
+++ b/src/thread.cc
@@ -0,0 +1,110 @@
+#include "thread.hh"
+
+struct TThreadStarter {
+ ThreadFunction *Function;
+ void *Argument;
+ bool Detach;
+};
+
+static void *ThreadStarter(void *Pointer){
+ TThreadStarter *Starter = (TThreadStarter*)Pointer;
+ ThreadFunction *Function = Starter->Function;
+ void *Argument = Starter->Argument;
+ bool Detach = Starter->Detach;
+ delete Starter;
+
+ int Result = Function(Argument);
+
+ // TODO(fusion): Just store the integer as a pointer and avoid allocation?
+ int *ResultPointer = NULL;
+ if(!Detach){
+ ResultPointer = new int;
+ *ResultPointer = Result;
+ }
+ pthread_exit(ResultPointer);
+
+ return NULL; // Unreachable.
+}
+
+ThreadHandle StartThread(ThreadFunction *Function, void *Argument, bool Detach){
+ TThreadStarter *Starter = new TThreadStarter;
+ Starter->Function = Function;
+ Starter->Argument = Argument;
+ Starter->Detach = Detach;
+
+ pthread_t Handle;
+ int err = pthread_create(&Handle, NULL, ThreadStarter, Starter);
+ if(err != 0){
+ error("StartThread: Kann Thread nicht anlegen; Fehlercode %d.\n", err);
+ return INVALID_THREAD_HANDLE;
+ }
+
+ if(Detach){
+ pthread_detach(Handle);
+ }
+
+ return (ThreadHandle)Handle;
+}
+
+int JoinThread(ThreadHandle Handle){
+ int Result = 0;
+ int *ResultPointer;
+
+ pthread_join((pthread_t)Handle, &ResultPointer);
+ if(ResultPointer != NULL){
+ Result = *ResultPointer;
+ delete ResultPointer;
+ }
+
+ return Result;
+}
+
+void DelayThread(int Seconds, int MicroSeconds){
+ if(Seconds == 0 && MicroSeconds == 0){
+ sched_yield();
+ }else if(MicroSeconds == 0){
+ sleep(Seconds);
+ }else{
+ usleep(MicroSeconds + Seconds * 1000000);
+ }
+}
+
+Semaphore::Semaphore(int Value){
+ this->value = Value;
+
+ // TODO(fusion): These should probably be non-recoverable errors.
+
+ if(pthread_mutex_init(&this->mutex, NULL) != 0){
+ error("Semaphore::Semaphore: Kann Mutex nicht einrichten.\n");
+ }
+
+ if(pthread_cond_init(&this->condition, NULL) != 0){
+ error("Semaphore::Semaphore: Kann Wartebedingung nicht einrichten.\n");
+ }
+}
+
+Semaphore::~Semaphore(void){
+ if(pthread_mutex_destroy(&this->mutex) != 0){
+ error("Semaphore::~Semaphore: Kann Mutex nicht freigeben.\n");
+ }
+
+ if(pthread_cond_destroy(&this->condition) != 0){
+ error("Semaphore::~Semaphore: Kann Wartebedingung nicht freigeben.\n");
+ }
+}
+
+void Semaphore::down(void){
+ pthread_mutex_lock(&this->mutex);
+ while(this->value <= 0){ // TODO(fusion): Make sure this is always a load operation?
+ pthread_cond_wait(&this->condition, &this->mutex);
+ }
+ this->value -= 1;
+ pthread_mutex_unlock(&this->mutex);
+}
+
+void Semaphore::up(void){
+ pthread_mutex_lock(&this->mutex);
+ this->value += 1;
+ pthread_mutex_unlock(&this->mutex);
+ pthread_cond_signal(&this->condition);
+}
diff --git a/src/thread.hh b/src/thread.hh
new file mode 100644
index 0000000..a3b0d04
--- /dev/null
+++ b/src/thread.hh
@@ -0,0 +1,33 @@
+#ifndef TIBIA_THREAD_HH_
+#define TIBIA_THREAD_HH_ 1
+
+#include "main.hh"
+#include <pthread.h>
+
+typedef pthread_t ThreadHandle;
+typedef int (ThreadFunction)(void *);
+
+// TODO(fusion): Probably have another way to tell whether the thread was
+// successfully spawned or not?
+constexpr ThreadHandle INVALID_THREAD_HANDLE = 0;
+
+ThreadHandle StartThread(ThreadFunction *Function, void *Argument, bool Detach);
+int JoinThread(ThreadHandle Handle);
+void DelayThread(int Seconds, int MicroSeconds);
+
+struct Semaphore {
+ // REGULAR FUNCTIONS
+ // =========================================================================
+ Semaphore(void);
+ ~Semaphore(void);
+ void up(void);
+ void down(void);
+
+ // DATA
+ // =========================================================================
+ int value;
+ pthread_mutex_t mutex;
+ pthread_cond_t condition;
+};
+
+#endif //TIBIA_THREAD_HH_