diff options
| -rw-r--r-- | TODO.md | 2 | ||||
| -rw-r--r-- | reference/types.hh | 13 | ||||
| -rw-r--r-- | src/thread.cc | 110 | ||||
| -rw-r--r-- | src/thread.hh | 33 |
4 files changed, 144 insertions, 14 deletions
@@ -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_ |
