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 static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure. 00060 00061 00062 bool isQuitting() const { return (QUITTING == mStatus); } 00063 bool isStopped() const { return (STOPPED == mStatus); } 00064 00065 // PAUSE / RESUME functionality. See source code for important usage notes. 00066 public: 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); // Defaults to global pool, could use the thread pool as well. 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