From f26e86a77f77008babaf873e9ce3c12d517d3e9a Mon Sep 17 00:00:00 2001 From: riccardom Date: Sun, 13 Nov 2011 14:55:25 +0000 Subject: [PATCH] task: Add Mac OS X backend (#3414787) As of October 2011, Mac OS X does not support named semaphores. So instead of trying to rework the existing Linux code to work with semaphores in both OS X and Linux, it's easier to reimplement with pthread mutexes for just OS X. From rogerman. xrmx: fixed gcc warnings for storing NULL in a pthread_t. Also while at it moved the includes on top. --- desmume/src/utils/task.cpp | 160 +++++++++++++++++++++++++++++++++++-- 1 file changed, 153 insertions(+), 7 deletions(-) diff --git a/desmume/src/utils/task.cpp b/desmume/src/utils/task.cpp index e805136c5..fc9a4d804 100644 --- a/desmume/src/utils/task.cpp +++ b/desmume/src/utils/task.cpp @@ -1,4 +1,4 @@ -/* Copyright 2009 DeSmuME team +/* Copyright 2009,2011 DeSmuME team This file is part of DeSmuME @@ -21,13 +21,16 @@ #include "task.h" #include -#ifdef _MSC_VER - #ifdef _WINDOWS #include +#else +#include +#if !defined(__APPLE__) +#include +#endif #endif - +#ifdef _MSC_VER class Task::Impl { public: Impl(); @@ -154,10 +157,153 @@ void* Task::Impl::finish() return param; } -#else +#elif defined(__APPLE__) -#include -#include +class Task::Impl { +public: + Impl(); + ~Impl(); + + void start(bool spinlock); + void execute(const TWork &work, void *param); + void* finish(); + void shutdown(); + + pthread_t thread; + pthread_mutex_t mutex; + pthread_cond_t condWork; + + TWork work; + void *param; + void *ret; + bool exitThread; +}; + +void* taskProc(void *arg) +{ + Task::Impl *ctx = (Task::Impl *)arg; + + do { + pthread_mutex_lock(&ctx->mutex); + + while (ctx->work == NULL && !ctx->exitThread) { + pthread_cond_wait(&ctx->condWork, &ctx->mutex); + } + + if (ctx->work != NULL) { + ctx->ret = ctx->work(ctx->param); + } else { + ctx->ret = NULL; + } + + ctx->work = NULL; + pthread_cond_signal(&ctx->condWork); + + pthread_mutex_unlock(&ctx->mutex); + + } while(!ctx->exitThread); + + return NULL; +} + +Task::Impl::Impl() +{ + thread = -1; + work = NULL; + param = NULL; + ret = NULL; + exitThread = false; + + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&condWork, NULL); +} + +Task::Impl::~Impl() +{ + shutdown(); + pthread_mutex_destroy(&mutex); + pthread_cond_destroy(&condWork); +} + +void Task::Impl::start(bool spinlock) +{ + pthread_mutex_lock(&this->mutex); + + if (this->thread != -1) { + pthread_mutex_unlock(&this->mutex); + return; + } + + this->work = NULL; + this->param = NULL; + this->ret = NULL; + this->exitThread = false; + pthread_create(&this->thread, NULL, &taskProc, this); + + pthread_mutex_unlock(&this->mutex); +} + +void Task::Impl::execute(const TWork &work, void *param) +{ + pthread_mutex_lock(&this->mutex); + + if (work == NULL || this->thread == -1) { + pthread_mutex_unlock(&this->mutex); + return; + } + + this->work = work; + this->param = param; + pthread_cond_signal(&this->condWork); + + pthread_mutex_unlock(&this->mutex); +} + +void* Task::Impl::finish() +{ + void *returnValue = NULL; + + pthread_mutex_lock(&this->mutex); + + if (this->thread == -1) { + pthread_mutex_unlock(&this->mutex); + return returnValue; + } + + while (this->work != NULL) { + pthread_cond_wait(&this->condWork, &this->mutex); + } + + returnValue = this->ret; + + pthread_mutex_unlock(&this->mutex); + + return returnValue; +} + +void Task::Impl::shutdown() +{ + pthread_mutex_lock(&this->mutex); + + if (this->thread == -1) { + pthread_mutex_unlock(&this->mutex); + return; + } + + this->work = NULL; + this->exitThread = true; + pthread_cond_signal(&this->condWork); + + pthread_mutex_unlock(&this->mutex); + + pthread_join(this->thread, NULL); + + pthread_mutex_lock(&this->mutex); + this->thread = -1; + pthread_mutex_unlock(&this->mutex); +} + +#else class Task::Impl { public: