llthread.cpp

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

Generated on Thu Jul 1 06:09:19 2010 for Second Life Viewer by  doxygen 1.4.7