--- /dev/null
+
+/*******************************************************************************
+
+ Copyright (c) 2009, Charles McGarvey
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef _MOOF_THREAD_HH_
+#define _MOOF_THREAD_HH_
+
+/**
+ * @file Thread.hh
+ * Light C++ wrapper around SDL threads.
+ */
+
+#include <boost/function.hpp>
+
+#include <SDL/SDL.h>
+
+
+namespace Mf {
+
+//
+// The detach function detaches a separate thread by calling 'func' with
+// the 'arg' parameter.
+//
+
+typedef SDL_Thread* Thread;
+
+typedef boost::function<int(void)> Function;
+
+
+int detach_(void* arg)
+{
+ Function function = *(Function*)arg;
+ int ret = function();
+
+ delete (Function*)arg;
+ return ret;
+}
+
+Thread detachFunction(const Function& function)
+{
+ Thread thread;
+ Function* fcopy = new Function(function);
+
+ thread = SDL_CreateThread(detach_, (void*)fcopy);
+ if (thread == 0) delete fcopy;
+ return thread;
+}
+
+
+int waitOnThread(Thread thread)
+{
+ int i;
+ SDL_WaitThread(thread, &i);
+ return i;
+}
+
+void killThread(Thread thread)
+{
+ SDL_KillThread(thread);
+}
+
+
+//
+// The identifier function returns a unique integer for the calling thread.
+//
+
+unsigned int getThreadIdentifier()
+{
+ return SDL_ThreadID();
+}
+
+unsigned int getThreadIdentifier(Thread thread)
+{
+ return SDL_GetThreadID(thread);
+}
+
+
+// =============================================================================
+
+class Mutex
+{
+ friend class Condition;
+
+public:
+ Mutex()
+ {
+ mutex_ = SDL_CreateMutex();
+ }
+ ~Mutex()
+ {
+ SDL_DestroyMutex(mutex_);
+ }
+
+ bool acquireLock()
+ {
+ return (SDL_LockMutex(mutex_) == 0);
+ }
+ bool releaseLock()
+ {
+ return (SDL_UnlockMutex(mutex_) == 0);
+ }
+
+ class Lock
+ {
+ friend class Condition;
+
+ public:
+ Lock(Mutex& mutex)
+ {
+ mutex_ = &mutex;
+ isLocked_ = false;
+ }
+ ~Lock()
+ {
+ if (isLocked_) release();
+ }
+
+ bool acquire()
+ {
+ return (isLocked_ = mutex_->acquireLock());
+ }
+ bool release()
+ {
+ return mutex_->releaseLock();
+ isLocked_ = false;
+ }
+
+ bool isLocked() const
+ {
+ return isLocked_;
+ }
+
+ protected:
+ Mutex* mutex_;
+ bool isLocked_;
+ };
+
+ class ScopedLock : public Lock
+ {
+ public:
+ ScopedLock(Mutex& mutex) :
+ Lock(mutex)
+ {
+ acquire();
+ }
+ };
+
+private:
+ SDL_mutex* mutex_;
+};
+
+
+class Condition
+{
+public:
+ Condition()
+ {
+ condition_ = SDL_CreateCond();
+ }
+ ~Condition()
+ {
+ SDL_DestroyCond(condition_);
+ }
+
+ bool wait(Mutex::Lock& lock)
+ {
+ return (SDL_CondWait(condition_, lock.mutex_->mutex_) == 0);
+ }
+ bool wait(Mutex::Lock& lock, unsigned ms)
+ {
+ // TODO for consistency, this function should take seconds
+ return (SDL_CondWaitTimeout(condition_, lock.mutex_->mutex_, ms) == 0);
+ }
+
+ bool notify()
+ {
+ return (SDL_CondSignal(condition_) == 0);
+ }
+ bool notifyAll()
+ {
+ return (SDL_CondBroadcast(condition_) == 0);
+ }
+
+private:
+ SDL_cond* condition_;
+};
+
+
+class Semaphore
+{
+public:
+ Semaphore(unsigned int value)
+ {
+ semaphore_ = SDL_CreateSemaphore(value);
+ }
+ ~Semaphore()
+ {
+ SDL_DestroySemaphore(semaphore_);
+ }
+
+ bool acquireLock()
+ {
+ return (SDL_SemWait(semaphore_) == 0);
+ }
+ bool releaseLock()
+ {
+ return (SDL_SemPost(semaphore_) == 0);
+ }
+
+ bool tryLock()
+ {
+ return (SDL_SemTryWait(semaphore_) == 0);
+ }
+ bool tryLock(unsigned ms)
+ {
+ // TODO for consistency, this function should take seconds
+ return (SDL_SemWaitTimeout(semaphore_, ms) == 0);
+ }
+
+ class Lock
+ {
+ public:
+ Lock(Semaphore& semaphore)
+ {
+ semaphore_ = &semaphore;
+ isLocked_ = false;
+ }
+ ~Lock()
+ {
+ if (isLocked_) release();
+ }
+
+ bool acquire()
+ {
+ return (isLocked_ = semaphore_->acquireLock());
+ }
+ bool release()
+ {
+ return semaphore_->releaseLock(); isLocked_ = false;
+ }
+
+ bool isLocked() const
+ {
+ return isLocked_;
+ }
+
+ protected:
+ Semaphore* semaphore_;
+ bool isLocked_;
+ };
+
+ class ScopedLock : public Lock
+ {
+ public:
+ ScopedLock(Semaphore& semaphore) :
+ Lock(semaphore)
+ {
+ acquire();
+ }
+ };
+
+private:
+ SDL_sem* semaphore_;
+};
+
+
+} // namespace Mf
+
+
+#endif // _MOOF_THREAD_HH_
+
+/** vim: set ts=4 sw=4 tw=80: *************************************************/
+