diff options
Diffstat (limited to 'src/threads.cc')
| -rw-r--r-- | src/threads.cc | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/src/threads.cc b/src/threads.cc new file mode 100644 index 0000000..a7acb41 --- /dev/null +++ b/src/threads.cc @@ -0,0 +1,158 @@ +#include "threads.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; +} + +ThreadHandle StartThread(ThreadFunction *Function, void *Argument, size_t StackSize, bool Detach){ + TThreadStarter *Starter = new TThreadStarter; + Starter->Function = Function; + Starter->Argument = Argument; + Starter->Detach = Detach; + + pthread_t Handle; + pthread_attr_t Attr; + pthread_attr_init(&Attr); + pthread_attr_setstacksize(&Attr, StackSize); + int err = pthread_create(&Handle, &Attr, ThreadStarter, Starter); + pthread_attr_destroy(&Attr); + 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; +} + +ThreadHandle StartThread(ThreadFunction *Function, void *Argument, void *Stack, size_t StackSize, bool Detach){ + TThreadStarter *Starter = new TThreadStarter; + Starter->Function = Function; + Starter->Argument = Argument; + Starter->Detach = Detach; + + pthread_t Handle; + pthread_attr_t Attr; + pthread_attr_init(&Attr); + pthread_attr_setstack(&Attr, Stack, StackSize); + int err = pthread_create(&Handle, &Attr, ThreadStarter, Starter); + pthread_attr_destroy(&Attr); + 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, (void**)&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); +} |
