void LLThread::shutdown() { // Warning! If you somehow call the thread destructor from itself, // the thread will die in an unclean fashion! if (mAPRThreadp) { if (!isStopped()) { // The thread isn't already stopped // First, set the flag that indicates that we're ready to die setQuitting(); llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl; // Now wait a bit for the thread to exit // It's unclear whether I should even bother doing this - this destructor // should netver get called unless we're already stopped, really... S32 counter = 0; const S32 MAX_WAIT = 600; while (counter < MAX_WAIT) { if (isStopped()) { break; } // Sleep for a tenth of a second ms_sleep(100); yield(); counter++; } } if (!isStopped()) { // This thread just wouldn't stop, even though we gave it time llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl; // Put a stake in its heart. apr_thread_exit(mAPRThreadp, -1); return; } mAPRThreadp = NULL; } delete mRunCondition; mRunCondition = 0; if (mIsLocalPool && mAPRPoolp) { apr_pool_destroy(mAPRPoolp); mAPRPoolp = 0; } }
void LLQueuedThread::shutdown() { setQuitting(); unpause(); // MAIN THREAD if (mThreaded) { S32 timeout = 100; for ( ; timeout>0; timeout--) { if (isStopped()) { break; } ms_sleep(100); LLThread::yield(); } if (timeout == 0) { llwarns << "~LLQueuedThread (" << mName << ") timed out!" << llendl; } } else { mStatus = STOPPED; } QueuedRequest* req; S32 active_count = 0; while ( (req = (QueuedRequest*)mRequestHash.pop_element()) ) { if (req->getStatus() == STATUS_QUEUED || req->getStatus() == STATUS_INPROGRESS) { ++active_count; req->setStatus(STATUS_ABORTED); // avoid assert in deleteRequest } req->deleteRequest(); } if (active_count) { llwarns << "~LLQueuedThread() called with active requests: " << active_count << llendl; } }