llthread.h

Go to the documentation of this file.
00001 
00032 #ifndef LL_LLTHREAD_H
00033 #define LL_LLTHREAD_H
00034 
00035 #include "llapr.h"
00036 #include "llapp.h"
00037 #include "llmemory.h"
00038 
00039 #include "apr-1/apr_thread_cond.h"
00040 
00041 class LLThread;
00042 class LLMutex;
00043 class LLCondition;
00044 
00045 class LLThread
00046 {
00047 public:
00048         typedef enum e_thread_status
00049         {
00050                 STOPPED = 0,    // The thread is not running.  Not started, or has exited its run function
00051                 RUNNING = 1,    // The thread is currently running
00052                 QUITTING= 2     // Someone wants this thread to quit
00053         } EThreadStatus;
00054 
00055         LLThread(const std::string& name, apr_pool_t *poolp = NULL);
00056         virtual ~LLThread(); // Warning!  You almost NEVER want to destroy a thread unless it's in the STOPPED state.
00057         virtual void shutdown(); // stops the thread
00058         
00059         bool isQuitting() const { return (QUITTING == mStatus); }
00060         bool isStopped() const { return (STOPPED == mStatus); }
00061         
00062         static U32 currentID(); // Return ID of current thread
00063         static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure.
00064         
00065 public:
00066         // PAUSE / RESUME functionality. See source code for important usage notes.
00067         // Called from MAIN THREAD.
00068         void pause();
00069         void unpause();
00070         bool isPaused() { return isStopped() || mPaused == TRUE; }
00071         
00072         // Cause the thread to wake up and check its condition
00073         void wake();
00074 
00075         // Same as above, but to be used when the condition is already locked.
00076         void wakeLocked();
00077 
00078         // Called from run() (CHILD THREAD). Pause the thread if requested until unpaused.
00079         void checkPause();
00080 
00081         // this kicks off the apr thread
00082         void start(void);
00083 
00084         apr_pool_t *getAPRPool() { return mAPRPoolp; }
00085         
00086 private:
00087         BOOL                            mPaused;
00088         
00089         // static function passed to APR thread creation routine
00090         static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap);
00091 
00092 protected:
00093         std::string                     mName;
00094         LLCondition*            mRunCondition;
00095 
00096         apr_thread_t            *mAPRThreadp;
00097         apr_pool_t                      *mAPRPoolp;
00098         BOOL                            mIsLocalPool;
00099         EThreadStatus           mStatus;
00100 
00101         void setQuitting();
00102         
00103         // virtual function overridden by subclass -- this will be called when the thread runs
00104         virtual void run(void) = 0; 
00105         
00106         // virtual predicate function -- returns true if the thread should wake up, false if it should sleep.
00107         virtual bool runCondition(void);
00108 
00109         // Lock/Unlock Run Condition -- use around modification of any variable used in runCondition()
00110         inline void lockData();
00111         inline void unlockData();
00112         
00113         // This is the predicate that decides whether the thread should sleep.  
00114         // It should only be called with mRunCondition locked, since the virtual runCondition() function may need to access
00115         // data structures that are thread-unsafe.
00116         bool shouldSleep(void) { return (mStatus == RUNNING) && (isPaused() || (!runCondition())); }
00117 
00118         // To avoid spurious signals (and the associated context switches) when the condition may or may not have changed, you can do the following:
00119         // mRunCondition->lock();
00120         // if(!shouldSleep())
00121         //     mRunCondition->signal();
00122         // mRunCondition->unlock();
00123 };
00124 
00125 //============================================================================
00126 
00127 class LLMutex
00128 {
00129 public:
00130         LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex
00131         ~LLMutex();
00132         
00133         void lock();            // blocks
00134         void unlock();
00135         bool isLocked();        // non-blocking, but does do a lock/unlock so not free
00136         
00137 protected:
00138         apr_thread_mutex_t *mAPRMutexp;
00139         apr_pool_t                      *mAPRPoolp;
00140         BOOL                            mIsLocalPool;
00141 };
00142 
00143 // Actually a condition/mutex pair (since each condition needs to be associated with a mutex).
00144 class LLCondition : public LLMutex
00145 {
00146 public:
00147         LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well.
00148         ~LLCondition();
00149         
00150         void wait();            // blocks
00151         void signal();
00152         void broadcast();
00153         
00154 protected:
00155         apr_thread_cond_t *mAPRCondp;
00156 };
00157 
00158 class LLMutexLock
00159 {
00160 public:
00161         LLMutexLock(LLMutex* mutex)
00162         {
00163                 mMutex = mutex;
00164                 mMutex->lock();
00165         }
00166         ~LLMutexLock()
00167         {
00168                 mMutex->unlock();
00169         }
00170 private:
00171         LLMutex* mMutex;
00172 };
00173 
00174 //============================================================================
00175 
00176 void LLThread::lockData()
00177 {
00178         mRunCondition->lock();
00179 }
00180 
00181 void LLThread::unlockData()
00182 {
00183         mRunCondition->unlock();
00184 }
00185 
00186 
00187 //============================================================================
00188 
00189 // see llmemory.h for LLPointer<> definition
00190 
00191 class LLThreadSafeRefCount
00192 {
00193 public:
00194         static void initClass(); // creates sMutex
00195         static void cleanupClass(); // destroys sMutex
00196         
00197 private:
00198         static LLMutex* sMutex;
00199 
00200 private:
00201         LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented
00202         LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented
00203 
00204 protected:
00205         virtual ~LLThreadSafeRefCount(); // use unref()
00206         
00207 public:
00208         LLThreadSafeRefCount();
00209         
00210         void ref()
00211         {
00212                 if (sMutex) sMutex->lock();
00213                 mRef++; 
00214                 if (sMutex) sMutex->unlock();
00215         } 
00216 
00217         S32 unref()
00218         {
00219                 llassert(mRef >= 1);
00220                 if (sMutex) sMutex->lock();
00221                 S32 res = --mRef;
00222                 if (sMutex) sMutex->unlock();
00223                 if (0 == res) 
00224                 {
00225                         delete this; 
00226                         return 0;
00227                 }
00228                 return res;
00229         }       
00230         S32 getNumRefs() const
00231         {
00232                 return mRef;
00233         }
00234 
00235 private: 
00236         S32     mRef; 
00237 };
00238 
00239 //============================================================================
00240 
00241 // Simple responder for self destructing callbacks
00242 // Pure virtual class
00243 class LLResponder : public LLThreadSafeRefCount
00244 {
00245 protected:
00246         virtual ~LLResponder();
00247 public:
00248         virtual void completed(bool success) = 0;
00249 };
00250 
00251 //============================================================================
00252 
00253 #endif // LL_LLTHREAD_H

Generated on Fri May 16 08:32:09 2008 for SecondLife by  doxygen 1.5.5