--- /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 _THREAD_HH_
+#define _THREAD_HH_
+
+/**
+ * @file thread.hh
+ * Light C++ wrapper around SDL threads.
+ */
+
+#include <boost/function.hpp>
+#include <SDL/SDL.h>
+
+
+namespace dc {
+namespace thread {
+
+//
+// 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 func = *(function*)arg;
+ int ret = func();
+
+ delete (function*)arg;
+ return ret;
+}
+
+thread detach(const function& func)
+{
+ thread t;
+ function* fcopy = new function(func);
+
+ t = SDL_CreateThread(detach_, (void*)fcopy);
+ if (t == 0) delete fcopy;
+ return t;
+}
+
+
+int wait(thread t)
+{
+ int i;
+ SDL_WaitThread(t, &i);
+ return i;
+}
+
+void kill(thread t)
+{
+ SDL_KillThread(t);
+}
+
+
+//
+// The identifier function returns a unique integer for the calling thread.
+//
+
+unsigned int identifier()
+{
+ return SDL_ThreadID();
+}
+
+unsigned int identifier(thread t)
+{
+ return SDL_GetThreadID(t);
+}
+
+
+// =============================================================================
+
+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& m) { mutex_ = &m; 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 scoped_lock : public lock
+ {
+ public:
+ scoped_lock(mutex& m) : lock(m) { acquire(); }
+ };
+
+private:
+ SDL_mutex* mutex_;
+};
+
+// =============================================================================
+
+class condition
+{
+public:
+ condition() { condition_ = SDL_CreateCond(); }
+ ~condition() { SDL_DestroyCond(condition_); }
+
+ bool wait(mutex::lock& l)
+ {
+ return (SDL_CondWait(condition_, l.mutex_->mutex_) == 0);
+ }
+ bool wait(mutex::lock& l, unsigned ms)
+ {
+ // TODO: For consistency, this function should take seconds, not ms.
+ return (SDL_CondWaitTimeout(condition_, l.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 tryLock() { return (SDL_SemTryWait(semaphore_) == 0); }
+ bool tryLock(unsigned ms)
+ {
+ // TODO: For consistency, this function should take seconds, not ms.
+ return (SDL_SemWaitTimeout(semaphore_, ms) == 0);
+ }
+ bool releaseLock() { return (SDL_SemPost(semaphore_) == 0); }
+
+ class lock
+ {
+ public:
+ lock(semaphore& m) { semaphore_ = &m; 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 scoped_lock : public lock
+ {
+ public:
+ scoped_lock(semaphore& m) : lock(m) { acquire(); }
+ };
+
+private:
+ SDL_sem* semaphore_;
+};
+
+
+} // namespace thread
+} // namespace dc
+
+
+#endif // _THREAD_HH_
+