llthread.cpp

Go to the documentation of this file.
00001 
00031 #include "linden_common.h"
00032 #include "llapr.h"
00033 
00034 #include "apr-1/apr_portable.h"
00035 
00036 #include "llthread.h"
00037 
00038 #include "lltimer.h"
00039 
00040 #if LL_LINUX || LL_SOLARIS
00041 #include <sched.h>
00042 #endif
00043 
00044 //----------------------------------------------------------------------------
00045 // Usage:
00046 // void run_func(LLThread* thread)
00047 // {
00048 // }
00049 // LLThread* thread = new LLThread();
00050 // thread->run(run_func);
00051 // ...
00052 // thread->setQuitting();
00053 // while(!timeout)
00054 // {
00055 //   if (thread->isStopped())
00056 //   {
00057 //     delete thread;
00058 //     break;
00059 //   }
00060 // }
00061 // 
00062 //----------------------------------------------------------------------------
00063 
00064 //
00065 // Handed to the APR thread creation function
00066 //
00067 void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap)
00068 {
00069         LLThread *threadp = (LLThread *)datap;
00070 
00071         // Set thread state to running
00072         threadp->mStatus = RUNNING;
00073 
00074         // Run the user supplied function
00075         threadp->run();
00076 
00077         llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl;
00078         
00079         // We're done with the run function, this thread is done executing now.
00080         threadp->mStatus = STOPPED;
00081 
00082         return NULL;
00083 }
00084 
00085 
00086 LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
00087         mPaused(FALSE),
00088         mName(name),
00089         mAPRThreadp(NULL),
00090         mStatus(STOPPED)
00091 {
00092         // Thread creation probably CAN be paranoid about APR being initialized, if necessary
00093         if (poolp)
00094         {
00095                 mIsLocalPool = FALSE;
00096                 mAPRPoolp = poolp;
00097         }
00098         else
00099         {
00100                 mIsLocalPool = TRUE;
00101                 apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
00102         }
00103         mRunCondition = new LLCondition(mAPRPoolp);
00104 }
00105 
00106 
00107 LLThread::~LLThread()
00108 {
00109         shutdown();
00110 }
00111 
00112 void LLThread::shutdown()
00113 {
00114         // Warning!  If you somehow call the thread destructor from itself,
00115         // the thread will die in an unclean fashion!
00116         if (mAPRThreadp)
00117         {
00118                 if (!isStopped())
00119                 {
00120                         // The thread isn't already stopped
00121                         // First, set the flag that indicates that we're ready to die
00122                         setQuitting();
00123 
00124                         llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl;
00125                         // Now wait a bit for the thread to exit
00126                         // It's unclear whether I should even bother doing this - this destructor
00127                         // should netver get called unless we're already stopped, really...
00128                         S32 counter = 0;
00129                         const S32 MAX_WAIT = 600;
00130                         while (counter < MAX_WAIT)
00131                         {
00132                                 if (isStopped())
00133                                 {
00134                                         break;
00135                                 }
00136                                 // Sleep for a tenth of a second
00137                                 ms_sleep(100);
00138                                 yield();
00139                                 counter++;
00140                         }
00141                 }
00142 
00143                 if (!isStopped())
00144                 {
00145                         // This thread just wouldn't stop, even though we gave it time
00146                         llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl;
00147                         return;
00148                 }
00149                 mAPRThreadp = NULL;
00150         }
00151 
00152         delete mRunCondition;
00153         
00154         if (mIsLocalPool)
00155         {
00156                 apr_pool_destroy(mAPRPoolp);
00157         }
00158 }
00159 
00160 
00161 void LLThread::start()
00162 {
00163         apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);      
00164 
00165         // We won't bother joining
00166         apr_thread_detach(mAPRThreadp);
00167 }
00168 
00169 //============================================================================
00170 // Called from MAIN THREAD.
00171 
00172 // Request that the thread pause/resume.
00173 // The thread will pause when (and if) it calls checkPause()
00174 void LLThread::pause()
00175 {
00176         if (!mPaused)
00177         {
00178                 // this will cause the thread to stop execution as soon as checkPause() is called
00179                 mPaused = 1;            // Does not need to be atomic since this is only set/unset from the main thread
00180         }       
00181 }
00182 
00183 void LLThread::unpause()
00184 {
00185         if (mPaused)
00186         {
00187                 mPaused = 0;
00188         }
00189 
00190         wake(); // wake up the thread if necessary
00191 }
00192 
00193 // virtual predicate function -- returns true if the thread should wake up, false if it should sleep.
00194 bool LLThread::runCondition(void)
00195 {
00196         // by default, always run.  Handling of pause/unpause is done regardless of this function's result.
00197         return true;
00198 }
00199 
00200 //============================================================================
00201 // Called from run() (CHILD THREAD).
00202 // Stop thread execution if requested until unpaused.
00203 void LLThread::checkPause()
00204 {
00205         mRunCondition->lock();
00206 
00207         // This is in a while loop because the pthread API allows for spurious wakeups.
00208         while(shouldSleep())
00209         {
00210                 mRunCondition->wait(); // unlocks mRunCondition
00211                 // mRunCondition is locked when the thread wakes up
00212         }
00213         
00214         mRunCondition->unlock();
00215 }
00216 
00217 //============================================================================
00218 
00219 void LLThread::setQuitting()
00220 {
00221         mRunCondition->lock();
00222         if (mStatus == RUNNING)
00223         {
00224                 mStatus = QUITTING;
00225         }
00226         mRunCondition->unlock();
00227         wake();
00228 }
00229 
00230 // static
00231 U32 LLThread::currentID()
00232 {
00233         return (U32)apr_os_thread_current();
00234 }
00235 
00236 // static
00237 void LLThread::yield()
00238 {
00239 #if LL_LINUX || LL_SOLARIS
00240         sched_yield(); // annoyingly, apr_thread_yield  is a noop on linux...
00241 #else
00242         apr_thread_yield();
00243 #endif
00244 }
00245 
00246 void LLThread::wake()
00247 {
00248         mRunCondition->lock();
00249         if(!shouldSleep())
00250         {
00251                 mRunCondition->signal();
00252         }
00253         mRunCondition->unlock();
00254 }
00255 
00256 void LLThread::wakeLocked()
00257 {
00258         if(!shouldSleep())
00259         {
00260                 mRunCondition->signal();
00261         }
00262 }
00263 
00264 //============================================================================
00265 
00266 LLMutex::LLMutex(apr_pool_t *poolp) :
00267         mAPRMutexp(NULL)
00268 {
00269         if (poolp)
00270         {
00271                 mIsLocalPool = FALSE;
00272                 mAPRPoolp = poolp;
00273         }
00274         else
00275         {
00276                 mIsLocalPool = TRUE;
00277                 apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
00278         }
00279         apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp);
00280 }
00281 
00282 
00283 LLMutex::~LLMutex()
00284 {
00285 #if _DEBUG
00286         llassert(!isLocked()); // better not be locked!
00287 #endif
00288         apr_thread_mutex_destroy(mAPRMutexp);
00289         mAPRMutexp = NULL;
00290         if (mIsLocalPool)
00291         {
00292                 apr_pool_destroy(mAPRPoolp);
00293         }
00294 }
00295 
00296 
00297 void LLMutex::lock()
00298 {
00299         apr_thread_mutex_lock(mAPRMutexp);
00300 }
00301 
00302 void LLMutex::unlock()
00303 {
00304         apr_thread_mutex_unlock(mAPRMutexp);
00305 }
00306 
00307 bool LLMutex::isLocked()
00308 {
00309         apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp);
00310         if (APR_STATUS_IS_EBUSY(status))
00311         {
00312                 return true;
00313         }
00314         else
00315         {
00316                 apr_thread_mutex_unlock(mAPRMutexp);
00317                 return false;
00318         }
00319 }
00320 
00321 //============================================================================
00322 
00323 LLCondition::LLCondition(apr_pool_t *poolp) :
00324         LLMutex(poolp)
00325 {
00326         // base class (LLMutex) has already ensured that mAPRPoolp is set up.
00327 
00328         apr_thread_cond_create(&mAPRCondp, mAPRPoolp);
00329 }
00330 
00331 
00332 LLCondition::~LLCondition()
00333 {
00334         apr_thread_cond_destroy(mAPRCondp);
00335         mAPRCondp = NULL;
00336 }
00337 
00338 
00339 void LLCondition::wait()
00340 {
00341         apr_thread_cond_wait(mAPRCondp, mAPRMutexp);
00342 }
00343 
00344 void LLCondition::signal()
00345 {
00346         apr_thread_cond_signal(mAPRCondp);
00347 }
00348 
00349 void LLCondition::broadcast()
00350 {
00351         apr_thread_cond_broadcast(mAPRCondp);
00352 }
00353 
00354 //============================================================================
00355 
00356 //----------------------------------------------------------------------------
00357 
00358 //static
00359 LLMutex* LLThreadSafeRefCount::sMutex = 0;
00360 
00361 //static
00362 void LLThreadSafeRefCount::initClass()
00363 {
00364         if (!sMutex)
00365         {
00366                 sMutex = new LLMutex(0);
00367         }
00368 }
00369 
00370 //static
00371 void LLThreadSafeRefCount::cleanupClass()
00372 {
00373         delete sMutex;
00374         sMutex = NULL;
00375 }
00376         
00377 
00378 //----------------------------------------------------------------------------
00379 
00380 LLThreadSafeRefCount::LLThreadSafeRefCount() :
00381         mRef(0)
00382 {
00383 }
00384 
00385 LLThreadSafeRefCount::~LLThreadSafeRefCount()
00386 { 
00387         if (mRef != 0)
00388         {
00389                 llerrs << "deleting non-zero reference" << llendl;
00390         }
00391 }
00392 
00393 //============================================================================
00394 
00395 LLResponder::~LLResponder()
00396 {
00397 }
00398 
00399 //============================================================================

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