]> Dogcows Code - chaz/yoink/blobdiff - src/moof/thread.hh
pch support
[chaz/yoink] / src / moof / thread.hh
index 09caefd3048800a0cab77380bbceb62743700e96..af251e157b8a64ef433c70794ddde72509c8a98f 100644 (file)
@@ -1,32 +1,36 @@
 
-/*]  Copyright (c) 2009-2010, Charles McGarvey  [**************************
+/*]  Copyright (c) 2009-2011, Charles McGarvey  [*****************************
 **]  All rights reserved.
 *
-* vi:ts=4 sw=4 tw=75
-*
 * Distributable under the terms and conditions of the 2-clause BSD license;
 * see the file COPYING for a complete text of the license.
 *
-**************************************************************************/
-
-/**
- * \file thread.hh
- * Light C++ wrapper around the SDL threads API.
- */
+*****************************************************************************/
 
 #ifndef _MOOF_THREAD_HH_
 #define _MOOF_THREAD_HH_
 
 #include <boost/bind.hpp>
 #include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
 #include <SDL/SDL.h>
 
 #include <moof/math.hh>
+#include <moof/timer.hh>
 
 
+/**
+ * \file thread.hh
+ * Light C++ wrapper around the SDL threads API.
+ */
+
 namespace moof {
 
 
+// forward declarations
+class runloop;
+typedef boost::shared_ptr<runloop> runloop_ptr;
+
 /**
  * Represents a thread which may be running.  You cannot instantiate a
  * thread object directly; new threads are created by detaching functions
@@ -38,29 +42,27 @@ class thread
 {
 public:
 
-       typedef boost::function<int(void)> function;
-
+       typedef boost::function<int(thread&)> function;
 
        /**
         * Construct an invalid thread object which has no association with any
         * real thread.
         */
-       thread() :
-               thread_(0) {}
+       thread();
 
        /**
         * Execute a function in a new thread.
         * \param function The function to execute.
         * \return The new thread, or an invalid thread if an error occurred.
         */
-       static thread detach(const function& function)
-       {
-               thread::function* fcopy = new thread::function(function);
-               SDL_Thread* thread = SDL_CreateThread(&thread::run, (void*)fcopy);
-               if (thread == 0) delete fcopy;
-               return moof::thread(thread);
-       }
+       static thread detach(const function& function);
 
+       /**
+        * Detach a new thread and run its runloop with an initial timer.
+        * \param timer The timer to schedule on the thread.
+        * \return The new thread, or an invalid thread if an error occurred.
+        */
+       static thread detach(timer& timer);
 
        /**
         * Wait for the thread to terminate, getting its return value.  The
@@ -69,21 +71,21 @@ public:
         */
        int wait()
        {
-               int i;
-               SDL_WaitThread(thread_, &i);
-               thread_ = 0;
-               return i;
+               if (thread_)
+               {
+                       int i;
+                       SDL_WaitThread(thread_, &i);
+                       thread_ = 0;
+                       return i;
+               }
+               return 1;
        }
 
        /**
         * Forcefully kill the thread without giving it a chance to clean up
         * after itself.  The thread will be invalidated.  Don't use this.
         */
-       void kill()
-       {
-               SDL_KillThread(thread_);
-               thread_ = 0;
-       }
+       void kill();
 
        /**
         * Get whether or not the thread object is associated with a real
@@ -95,7 +97,6 @@ public:
                return thread_ != 0;
        }
 
-
        /**
         * Get a unique identifier for this thread, if it is valid.
         * \return The identifier.
@@ -114,21 +115,26 @@ public:
                return SDL_ThreadID();
        }
 
+       /**
+        * Get the thread's runloop.
+        * \return The thread's runloop.
+        */
+       moof::runloop& runloop() const;
 
-private:
-
-       thread(SDL_Thread* thread) :
-               thread_(thread) {}
+       /**
+        * Get the runloop for the main thread.
+        * \return The runloop.
+        */
+       static moof::runloop& main_runloop();
 
-       static int run(void* arg)
-       {
-               int code = (*(function*)arg)();
-               delete (function*)arg;
-               return code;
-       }
+private:
 
+       static void spawn(thread* thread);
+       static int run(void* arg);
 
-       SDL_Thread* thread_;
+       function        function_;
+       SDL_Thread*     thread_;
+       runloop_ptr     runloop_;
 };
 
 
@@ -163,6 +169,7 @@ public:
        virtual int wait() = 0;
 };
 
+
 /**
  * An asynchronous task that is run to be executed in a separated thread.
  */
@@ -174,7 +181,10 @@ public:
         * Get the thread object the task is executing in.
         * \return The thread.
         */
-       const class thread& thread() const { return thread_; }
+       const class thread& thread() const
+       {
+               return thread_;
+       }
 
        /**
         * Block the current thread until the task thread is finished.
@@ -185,7 +195,6 @@ public:
                return thread_.wait();
        }
 
-
 protected:
 
        class thread thread_;
@@ -203,27 +212,26 @@ public:
        /**
         * Construct a mutex.
         */
-    mutex() :
+       mutex() :
                mutex_(SDL_CreateMutex()) {}
 
        /**
         * Deconstruct a mutex.
         */
-    ~mutex()
+       ~mutex()
        {
                SDL_DestroyMutex(mutex_);
        }
 
-
        /**
         * Block until the calling thread can secure exclusive access to the
         * code protected by the mutex.
         * \return True if the lock was acquired, false otherwise.
         * \see lock
         */
-    bool acquire_lock()
+       bool acquire_lock()
        {
-               return (SDL_LockMutex(mutex_) == 0);
+               return SDL_LockMutex(mutex_) == 0;
        }
 
        /**
@@ -232,45 +240,46 @@ public:
         * \return True if the mutex was unlocked, false otherwise.
         * \see lock
         */
-    bool release_lock()
+       bool release_lock()
        {
-               return (SDL_UnlockMutex(mutex_) == 0);
+               return SDL_UnlockMutex(mutex_) == 0;
        }
 
-
        /**
         * As an alternative method for locking, objects of this class will
         * automagically release the lock if it is still locked at
         * deconstruction.  Therefore, it's generally safer to use this method
         * since it makes it much more difficult to forget to unlock a mutex.
         */
-    class lock
-    {
-    public:
+       class lock
+       {
+       public:
 
                /**
                 * Construct a lock.
                 * \param mutex The mutex.
                 */
-        explicit lock(mutex& mutex) :
+               explicit lock(mutex& mutex, bool lock = true) :
                        mutex_(mutex),
-                       is_locked_(false) {}
+                       is_locked_(false)
+               {
+                       if (lock && !acquire()) throw "mutex lock not acquired";
+               }
 
                /**
                 * Deconstruct a lock.  The lock is automagically released if it is
                 * still locked.
                 */
-        ~lock()
+               ~lock()
                {
                        if (is_locked_) release();
                }
 
-
                /**
                 * Try to acquire a lock on the mutex.
                 * \return True if the mutex was locked, false otherwise.
                 */
-        bool acquire()
+               bool acquire()
                {
                        return (is_locked_ = mutex_.acquire_lock());
                }
@@ -279,60 +288,29 @@ public:
                 * Release the lock.
                 * \return True if the mutex was unlocked, false otherwise.
                 */
-        bool release()
+               bool release()
                {
                        bool result = mutex_.release_lock();
                        is_locked_ = false;
                        return result;
                }
 
-
                /**
                 * Get whether or not the mutex is locked.
                 * \return True if the mutex is locked, false otherwise.
                 */
-        bool is_locked() const
+               bool is_locked() const
                {
                        return is_locked_;
                }
 
+       protected:
 
-    protected:
-
-        mutex& mutex_;
-        bool   is_locked_;
-
-        friend class condition;
-    };
-
-       /**
-        * This type of lock tries to acquire a lock on the mutex during
-        * construction and releases the lock on deconstruction.
-        */
-    class scoped_lock : private lock
-    {
-       public:
-
-               /**
-                * Construct a lock.
-                * \param mutex The mutex.
-                */
-               explicit scoped_lock(mutex& mutex) :
-                       lock(mutex)
-               {
-                       acquire();
-               }
-
-               /**
-                * Get whether or not the mutex is locked.
-                * \return True if the mutex is locked, false otherwise.
-                */
-               bool is_locked() const
-               {
-                       return lock::is_locked();
-               }
-    };
+               mutex&  mutex_;
+               bool    is_locked_;
 
+               friend class condition;
+       };
 
 private:
 
@@ -352,7 +330,7 @@ public:
        /**
         * Construct a condition.
         */
-    condition()
+       condition()
        {
                condition_ = SDL_CreateCond();
        }
@@ -360,12 +338,11 @@ public:
        /**
         * Deconstruct a condition.
         */
-    ~condition()
+       ~condition()
        {
                SDL_DestroyCond(condition_);
        }
 
-
        /**
         * Unlock the mutex and wait for another thread to notify the thread,
         * at which point the mutex will be re-locked and the method will
@@ -375,7 +352,7 @@ public:
         */
        bool wait(mutex& mutex)
        {
-        return (SDL_CondWait(condition_, mutex.mutex_) == 0);
+               return SDL_CondWait(condition_, mutex.mutex_) == 0;
        }
 
        /**
@@ -385,10 +362,10 @@ public:
         * \param lock The lock.
         * \return True if the thread was notified, false otherwise.
         */
-    bool wait(mutex::lock& lock)
+       bool wait(mutex::lock& lock)
        {
-        return (SDL_CondWait(condition_, lock.mutex_.mutex_) == 0);
-    }
+               return SDL_CondWait(condition_, lock.mutex_.mutex_) == 0;
+       }
 
        /**
         * Unlock the mutex and wait for another thread to notify the thread,
@@ -399,10 +376,10 @@ public:
         * \param timeout Number of seconds to wait.
         * \return True if the thread was notified, false otherwise.
         */
-    bool wait(mutex& mutex, scalar timeout)
+       bool wait(mutex& mutex, scalar timeout)
        {
                Uint32 ms = timeout * SCALAR(1000.0);
-        return (SDL_CondWaitTimeout(condition_, mutex.mutex_, ms) == 0);
+               return SDL_CondWaitTimeout(condition_, mutex.mutex_, ms) == 0;
        }
 
        /**
@@ -414,33 +391,31 @@ public:
         * \param timeout Number of seconds to wait.
         * \return True if the thread was notified, false otherwise.
         */
-    bool wait(mutex::lock& lock, scalar timeout)
+       bool wait(mutex::lock& lock, scalar timeout)
        {
                Uint32 ms = timeout * SCALAR(1000.0);
-        return (SDL_CondWaitTimeout(condition_,
-                                                                       lock.mutex_.mutex_, ms) == 0);
+               return SDL_CondWaitTimeout(condition_,
+                                       lock.mutex_.mutex_, ms) == 0;
        }
 
-
        /**
         * Notify one other thread that is waiting on the condition.
         * \return True on success, false otherwise.
         */
-    bool notify()
+       bool notify()
        {
-               return (SDL_CondSignal(condition_) == 0);
+               return SDL_CondSignal(condition_) == 0;
        }
 
        /**
         * Notify all other threads that are waiting on the condition.
         * \return True on success, false otherwise.
         */
-    bool notify_all()
+       bool notify_all()
        {
-               return (SDL_CondBroadcast(condition_) == 0);
+               return SDL_CondBroadcast(condition_) == 0;
        }
 
-
 private:
 
     SDL_cond* condition_;
@@ -458,7 +433,7 @@ public:
         * Construct a semaphore.
         * \param value The initial value of the semaphore.
         */
-    explicit semaphore(uint32_t value)
+       explicit semaphore(uint32_t value)
        {
                semaphore_ = SDL_CreateSemaphore(value);
        }
@@ -466,21 +441,20 @@ public:
        /**
         * Deconstruct a semaphore.
         */
-    ~semaphore()
+       ~semaphore()
        {
                SDL_DestroySemaphore(semaphore_);
        }
 
-
        /**
         * Block until the calling thread can secure exclusive access to the
         * code protected by the semaphore.
         * \return True if the lock was acquired, false otherwise.
         * \see lock
         */
-    bool acquire_lock()
+       bool acquire_lock()
        {
-               return (SDL_SemWait(semaphore_) == 0);
+               return SDL_SemWait(semaphore_) == 0;
        }
 
        /**
@@ -492,7 +466,7 @@ public:
        bool acquire_lock(scalar timeout)
        {
                Uint32 ms = timeout * SCALAR(1000.0);
-               return (SDL_SemWaitTimeout(semaphore_, ms) == 0);
+               return SDL_SemWaitTimeout(semaphore_, ms) == 0;
        }
 
        /**
@@ -501,9 +475,9 @@ public:
         * \return True if the semaphore was unlocked, false otherwise.
         * \see lock
         */
-    bool release_lock()
+       bool release_lock()
        {
-               return (SDL_SemPost(semaphore_) == 0);
+               return SDL_SemPost(semaphore_) == 0;
        }
 
        /**
@@ -511,9 +485,9 @@ public:
         * immediately available.
         * \return True if the semaphore was locked, false otherwise.
         */
-    bool try_lock()
+       bool try_lock()
        {
-               return (SDL_SemTryWait(semaphore_) == 0);
+               return SDL_SemTryWait(semaphore_) == 0;
        }
 
        /**
@@ -523,33 +497,35 @@ public:
         * since it makes it much more difficult to forget to unlock a
         * semaphore.
         */
-    class lock
-    {
-    public:
+       class lock
+       {
+       public:
 
                /**
                 * Construct a lock.
                 * \param semaphore The semaphore.
                 */
-        explicit lock(semaphore& semaphore) :
+               explicit lock(semaphore& semaphore, bool lock = true) :
                        semaphore_(semaphore),
-                       is_locked_(false) {}
+                       is_locked_(false)
+               {
+                       if (lock && !acquire()) throw "semaphore lock not acquired";
+               }
 
                /**
                 * Deconstruct a lock.  The lock is automagically released if it is
                 * still locked.
                 */
-        ~lock()
+               ~lock()
                {
                        if (is_locked_) release();
                }
-        
 
                /**
                 * Try to acquire a lock on the semaphore.
                 * \return True if the semaphore was locked, false otherwise.
                 */
-        bool acquire()
+               bool acquire()
                {
                        return (is_locked_ = semaphore_.acquire_lock());
                }
@@ -558,7 +534,7 @@ public:
                 * Release the lock.
                 * \return True if the semaphore was unlocked, false otherwise.
                 */
-        bool release()
+               bool release()
                {
                        bool result = semaphore_.release_lock();
                        is_locked_ = false;
@@ -569,46 +545,16 @@ public:
                 * Get whether or not the semaphore is locked.
                 * \return True if the semaphore is locked, false otherwise.
                 */
-        bool is_locked() const
+               bool is_locked() const
                {
                        return is_locked_;
                }
-        
-
-    protected:
-
-        semaphore&     semaphore_;
-        bool           is_locked_;
-    };
-    
-       /**
-        * This type of lock tries to acquire a lock on the semaphore during
-        * construction and releases the lock on deconstruction.
-        */
-    class scoped_lock : private lock
-    {
-    public:
-
-               /**
-                * Construct a lock.
-                * \param semaphore The semaphore.
-                */
-        explicit scoped_lock(semaphore& semaphore) :
-                       lock(semaphore)
-               {
-                       acquire();
-               }
 
-               /**
-                * Get whether or not the semaphore is locked.
-                * \return True if the semaphore is locked, false otherwise.
-                */
-               bool is_locked() const
-               {
-                       return lock::is_locked();
-               }
-    };
+       protected:
 
+               semaphore&      semaphore_;
+               bool            is_locked_;
+       };
 
 private:
 
@@ -616,6 +562,17 @@ private:
 };
 
 
+#if ENABLE_THREADS
+#define MOOF_DECLARE_MUTEX(M)          moof::mutex M
+#define MOOF_DECLARE_STATIC_MUTEX(M)   static moof::mutex M
+#define MOOF_MUTEX_LOCK(M)             moof::mutex::lock lock_##M(M)
+#else
+#define MOOF_DECLARE_MUTEX(M)
+#define MOOF_DECLARE_STATIC_MUTEX(M)
+#define MOOF_MUTEX_LOCK(M)
+#endif
+
+
 } // namespace moof
 
 #endif // _MOOF_THREAD_HH_
This page took 0.039045 seconds and 4 git commands to generate.