diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index 8cef4293cd7cdb4ec204a6ad59e8ba37cf4fe6a1..2f967304d0d643bab4cbbd39cb6f3321379dee7a 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -36,9 +36,10 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool should_pause) : LLThread(name), mThreaded(threaded), - mIdleThread(TRUE), - mNextHandle(0), - mStarted(FALSE) + mStarted(false), + mIdleThread(true), + mRequestQueueSize(0), + mNextHandle(0) { if (mThreaded) { @@ -117,7 +118,7 @@ S32 LLQueuedThread::update(F32 max_time_ms) if (!mThreaded) { startThread(); - mStarted = TRUE; + mStarted = true; } } return updateQueue(max_time_ms); @@ -162,17 +163,6 @@ void LLQueuedThread::incQueue() } } -//virtual -// May be called from any thread -S32 LLQueuedThread::getPending() -{ - S32 res; - lockData(); - res = mRequestQueue.size(); - unlockData(); - return res; -} - // MAIN thread void LLQueuedThread::waitOnPending() { @@ -236,6 +226,7 @@ bool LLQueuedThread::addRequest(QueuedRequest* req) #if _DEBUG // LL_INFOS() << llformat("LLQueuedThread::Added req [%08d]",handle) << LL_ENDL; #endif + mRequestQueueSize = mRequestQueue.size(); unlockData(); incQueue(); @@ -289,7 +280,7 @@ LLQueuedThread::QueuedRequest* LLQueuedThread::getRequest(handle_t handle) { if (handle == nullHandle()) { - return 0; + return nullptr; } lockData(); QueuedRequest* res = (QueuedRequest*)mRequestHash.find(handle); @@ -429,6 +420,10 @@ S32 LLQueuedThread::processNextRequest() llassert_always(req->getStatus() == STATUS_QUEUED); break; } + + // Update queue size after processing + mRequestQueueSize = mRequestQueue.size(); + U32 start_priority = 0 ; if (req) { @@ -463,6 +458,7 @@ S32 LLQueuedThread::processNextRequest() lockData(); req->setStatus(STATUS_QUEUED); mRequestQueue.insert(req); + mRequestQueueSize = mRequestQueue.size(); unlockData(); if (mThreaded && start_priority < PRIORITY_NORMAL) { @@ -481,10 +477,7 @@ S32 LLQueuedThread::processNextRequest() bool LLQueuedThread::runCondition() { // mRunCondition must be locked here - if (mRequestQueue.empty() && mIdleThread) - return false; - else - return true; + return !((mRequestQueueSize <= 0) && mIdleThread); } // virtual @@ -493,7 +486,7 @@ void LLQueuedThread::run() // call checPause() immediately so we don't try to do anything before the class is fully constructed checkPause(); startThread(); - mStarted = TRUE; + mStarted = true; while (1) { @@ -507,7 +500,7 @@ void LLQueuedThread::run() break; } - mIdleThread = FALSE; + mIdleThread = false; threadedUpdate(); @@ -515,7 +508,7 @@ void LLQueuedThread::run() if (pending_work == 0) { - mIdleThread = TRUE; + mIdleThread = true; ms_sleep(1); } //LLThread::yield(); // thread should yield after each request diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h index 5d3f8736467fa7f6967d6d9017f53d7bd4d16227..05dcaf10eb6f71c873fc31af5dccbdc536089ad1 100644 --- a/indra/llcommon/llqueuedthread.h +++ b/indra/llcommon/llqueuedthread.h @@ -153,11 +153,10 @@ class LL_COMMON_API LLQueuedThread : public LLThread virtual ~LLQueuedThread(); virtual void shutdown(); -private: - // No copy constructor or copy assignment - LLQueuedThread(const LLQueuedThread&); - LLQueuedThread& operator=(const LLQueuedThread&); + LLQueuedThread(const LLQueuedThread&) = delete; + LLQueuedThread& operator=(const LLQueuedThread&) = delete; +private: virtual bool runCondition(void); virtual void run(void); virtual void startThread(void); @@ -179,8 +178,8 @@ class LL_COMMON_API LLQueuedThread : public LLThread void waitOnPending(); void printQueueStats(); - virtual S32 getPending(); - bool getThreaded() { return mThreaded ? true : false; } + virtual S32 getPending() const { return mRequestQueueSize; } // May be called from any thread + bool getThreaded() const { return mThreaded; } // Request accessors status_t getRequestStatus(handle_t handle); @@ -196,12 +195,13 @@ class LL_COMMON_API LLQueuedThread : public LLThread bool check(); protected: - BOOL mThreaded; // if false, run on main thread and do updates during update() - BOOL mStarted; // required when mThreaded is false to call startThread() from update() + bool mThreaded; // if false, run on main thread and do updates during update() + bool mStarted; // required when mThreaded is false to call startThread() from update() LLAtomicBool mIdleThread; // request queue is empty (or we are quitting) and the thread is idle typedef std::set<QueuedRequest*, queued_request_less> request_queue_t; request_queue_t mRequestQueue; + std::atomic<S32> mRequestQueueSize; enum { REQUEST_HASH_SIZE = 512 }; // must be power of 2 typedef LLSimpleHash<handle_t, REQUEST_HASH_SIZE> request_hash_t; diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp index 4b91b2cacaf4007ab467ff4a7c505a7e32ff8826..fcd7eb89d29b7a906a9aa9f8bd8b786627efdaad 100644 --- a/indra/llcommon/llworkerthread.cpp +++ b/indra/llcommon/llworkerthread.cpp @@ -35,7 +35,8 @@ // Run on MAIN thread LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded, bool should_pause) : - LLQueuedThread(name, threaded, should_pause) + LLQueuedThread(name, threaded, should_pause), + mDeleteListSize(0) { mDeleteMutex = new LLMutex(); @@ -76,6 +77,7 @@ void LLWorkerThread::clearDeleteList() delete *iter ; } mDeleteList.clear() ; + mDeleteListSize = mDeleteList.size(); mDeleteMutex->unlock() ; } } @@ -87,26 +89,30 @@ S32 LLWorkerThread::update(F32 max_time_ms) // Delete scheduled workers std::vector<LLWorkerClass*> delete_list; std::vector<LLWorkerClass*> abort_list; - mDeleteMutex->lock(); - for (delete_list_t::iterator iter = mDeleteList.begin(); - iter != mDeleteList.end(); ) + if (mDeleteListSize) { - delete_list_t::iterator curiter = iter++; - LLWorkerClass* worker = *curiter; - if (worker->deleteOK()) + mDeleteMutex->lock(); + for (delete_list_t::iterator iter = mDeleteList.begin(); + iter != mDeleteList.end(); ) { - if (worker->getFlags(LLWorkerClass::WCF_WORK_FINISHED)) - { - delete_list.push_back(worker); - mDeleteList.erase(curiter); - } - else if (!worker->getFlags(LLWorkerClass::WCF_ABORT_REQUESTED)) + delete_list_t::iterator curiter = iter++; + LLWorkerClass* worker = *curiter; + if (worker->deleteOK()) { - abort_list.push_back(worker); + if (worker->getFlags(LLWorkerClass::WCF_WORK_FINISHED)) + { + delete_list.push_back(worker); + mDeleteList.erase(curiter); + } + else if (!worker->getFlags(LLWorkerClass::WCF_ABORT_REQUESTED)) + { + abort_list.push_back(worker); + } } } + mDeleteListSize = mDeleteList.size(); + mDeleteMutex->unlock(); } - mDeleteMutex->unlock(); // abort and delete after releasing mutex for (std::vector<LLWorkerClass*>::iterator iter = abort_list.begin(); iter != abort_list.end(); ++iter) @@ -154,6 +160,7 @@ void LLWorkerThread::deleteWorker(LLWorkerClass* workerclass) { mDeleteMutex->lock(); mDeleteList.push_back(workerclass); + mDeleteListSize = mDeleteList.size(); mDeleteMutex->unlock(); } diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h index b1a6f613607c908e505a316dbbd5df8bce5abb31..87ded2d35f935884b29fa05458cc658330211227 100644 --- a/indra/llcommon/llworkerthread.h +++ b/indra/llcommon/llworkerthread.h @@ -81,6 +81,7 @@ class LL_COMMON_API LLWorkerThread : public LLQueuedThread private: typedef std::list<LLWorkerClass*> delete_list_t; delete_list_t mDeleteList; + std::atomic<S32> mDeleteListSize; LLMutex* mDeleteMutex; public: @@ -91,7 +92,7 @@ class LL_COMMON_API LLWorkerThread : public LLQueuedThread handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority = PRIORITY_NORMAL); - S32 getNumDeletes() { return (S32)mDeleteList.size(); } // debug + S32 getNumDeletes() const { return mDeleteListSize; } // debug private: void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index 5f42fba86602ecf4df3b609ebae06b4ff947495a..d1030721a7986a89d8bdcd34573bef23450656fe 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -34,6 +34,7 @@ // MAIN THREAD LLImageDecodeThread::LLImageDecodeThread(bool threaded) : LLQueuedThread("imagedecode", threaded) + , mCreationListSize(0) { mCreationMutex = new LLMutex(); } @@ -48,22 +49,26 @@ LLImageDecodeThread::~LLImageDecodeThread() // virtual S32 LLImageDecodeThread::update(F32 max_time_ms) { - LLMutexLock lock(mCreationMutex); - for (creation_list_t::iterator iter = mCreationList.begin(); - iter != mCreationList.end(); ++iter) + if (mCreationListSize > 0) { - creation_info& info = *iter; - ImageRequest* req = new ImageRequest(info.handle, info.image, - info.priority, info.discard, info.needs_aux, - info.responder); - - bool res = addRequest(req); - if (!res) + LLMutexLock lock(mCreationMutex); + for (creation_list_t::iterator iter = mCreationList.begin(); + iter != mCreationList.end(); ++iter) { - LL_ERRS() << "request added after LLLFSThread::cleanupClass()" << LL_ENDL; + creation_info& info = *iter; + ImageRequest* req = new ImageRequest(info.handle, info.image, + info.priority, info.discard, info.needs_aux, + info.responder); + + bool res = addRequest(req); + if (!res) + { + LL_ERRS() << "request added after LLLFSThread::cleanupClass()" << LL_ENDL; + } } + mCreationList.clear(); + mCreationListSize = 0; } - mCreationList.clear(); S32 res = LLQueuedThread::update(max_time_ms); return res; } @@ -74,6 +79,7 @@ LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* LLMutexLock lock(mCreationMutex); handle_t handle = generateHandle(); mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder)); + mCreationListSize = mCreationList.size(); return handle; } diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h index 1bfb0ddfd3f28ca36ff3dd1b760a61dd7cff32fa..c6adfab327841d02f9dda86a987cc99a37932577 100644 --- a/indra/llimage/llimageworker.h +++ b/indra/llimage/llimageworker.h @@ -86,18 +86,20 @@ class LLImageDecodeThread : public LLQueuedThread private: struct creation_info { - handle_t handle; LLPointer<LLImageFormatted> image; + LLPointer<Responder> responder; + handle_t handle; U32 priority; S32 discard; BOOL needs_aux; - LLPointer<Responder> responder; creation_info(handle_t h, LLImageFormatted* i, U32 p, S32 d, BOOL aux, Responder* r) - : handle(h), image(i), priority(p), discard(d), needs_aux(aux), responder(r) + : image(i), responder(r), handle(h), priority(p), discard(d), needs_aux(aux) {} }; + typedef std::list<creation_info> creation_list_t; creation_list_t mCreationList; + std::atomic<S32> mCreationListSize; LLMutex* mCreationMutex; }; diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 2e52414d71950c5d5cf1ca87e4bf47367ecc7d3f..a3f203943c0f38b65e178af52ee5602a5bacb337 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -831,6 +831,8 @@ LLTextureCache::LLTextureCache(bool threaded) mListMutex(), mFastCacheMutex(), mHeaderAPRFile(NULL), + mPrioritizeWriteListEmpty(true), + mCompletedListEmpty(true), mReadOnly(TRUE), //do not allow to change the texture cache until setReadOnly() is called. mTexturesSizeTotal(0), mDoPurge(FALSE), @@ -862,35 +864,41 @@ S32 LLTextureCache::update(F32 max_time_ms) S32 res; res = LLWorkerThread::update(max_time_ms); - mListMutex.lock(); - handle_list_t priorty_list = mPrioritizeWriteList; // copy list - mPrioritizeWriteList.clear(); - responder_list_t completed_list = mCompletedList; // copy list - mCompletedList.clear(); - mListMutex.unlock(); - - lockWorkers(); + handle_list_t priorty_list; + responder_list_t completed_list; + if ((!mPrioritizeWriteListEmpty) || (!mCompletedListEmpty)) + { + LLMutexLock lock(&mListMutex); + priorty_list.swap(mPrioritizeWriteList); // copy list + mPrioritizeWriteList.clear(); + mPrioritizeWriteListEmpty = mPrioritizeWriteList.empty(); + completed_list.swap(mCompletedList); // copy list + mCompletedList.clear(); + mCompletedListEmpty = mCompletedList.empty(); + } - for (handle_list_t::iterator iter1 = priorty_list.begin(); - iter1 != priorty_list.end(); ++iter1) + if (!priorty_list.empty()) { - handle_t handle = *iter1; - handle_map_t::iterator iter2 = mWriters.find(handle); - if(iter2 != mWriters.end()) + lockWorkers(); + + for (handle_t handle : priorty_list) { - LLTextureCacheWorker* worker = iter2->second; - worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mPriority); + handle_map_t::iterator iter2 = mWriters.find(handle); + if (iter2 != mWriters.end()) + { + LLTextureCacheWorker* worker = iter2->second; + worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mPriority); + } } - } - unlockWorkers(); + unlockWorkers(); + } // call 'completed' with workers list unlocked (may call readComplete() or writeComplete() - for (responder_list_t::iterator iter1 = completed_list.begin(); - iter1 != completed_list.end(); ++iter1) - { - Responder *responder = iter1->first; - bool success = iter1->second; + for (auto& iter1 : completed_list) + { + Responder *responder = iter1.first; + bool success = iter1.second; responder->completed(success); } @@ -917,7 +925,7 @@ std::string LLTextureCache::getLocalFileName(const LLUUID& id) std::string LLTextureCache::getTextureFileName(const LLUUID& id) { std::string idstr = id.asString(); - std::string delem = gDirUtilp->getDirDelimiter(); + const std::string& delem = gDirUtilp->getDirDelimiter(); std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr + ".texture"; return filename; } @@ -993,8 +1001,6 @@ const char* fast_cache_filename = "FastCache.cache"; void LLTextureCache::setDirNames(ELLPath location) { - std::string delem = gDirUtilp->getDirDelimiter(); - mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, textures_dirname, entries_filename); mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, textures_dirname, cache_filename); mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname); @@ -2300,12 +2306,14 @@ void LLTextureCache::prioritizeWrite(handle_t handle) // which could create a deadlock LLMutexLock lock(&mListMutex); mPrioritizeWriteList.push_back(handle); + mPrioritizeWriteListEmpty = mPrioritizeWriteList.empty(); } void LLTextureCache::addCompleted(Responder* responder, bool success) { LLMutexLock lock(&mListMutex); mCompletedList.push_back(std::make_pair(responder,success)); + mCompletedListEmpty = mCompletedList.empty(); } ////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h index e1c752b58ed09a39e3c5e710d44bc6bcf03d0c0e..1be195a60aba608d7812c06beb92867bb5a55a8c 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -210,9 +210,11 @@ class LLTextureCache : public LLWorkerThread typedef std::vector<handle_t> handle_list_t; handle_list_t mPrioritizeWriteList; + std::atomic<bool> mPrioritizeWriteListEmpty; typedef std::vector<std::pair<LLPointer<Responder>, bool> > responder_list_t; responder_list_t mCompletedList; + std::atomic<bool> mCompletedListEmpty; BOOL mReadOnly; diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 485d3fc8780574bbd88915f225273d8c34dd1efc..6c12c276278ca0678db32b7386bba1f1abf0be69 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -2569,8 +2569,9 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image mTextureCache(cache), mImageDecodeThread(imagedecodethread), mTextureBandwidth(0), - mHTTPTextureBits(0), + mHTTPTextureBits((U32Bits)0), mTotalHTTPRequests(0), + mCommandsSize(0), mQAMode(qa_mode), mHttpRequest(NULL), mHttpOptions(), @@ -2632,6 +2633,7 @@ LLTextureFetch::~LLTextureFetch() mCommands.erase(mCommands.begin()); delete req; } + mCommandsSize = 0; mHttpWaitResource.clear(); @@ -2814,7 +2816,7 @@ void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id, S32Bytes received_siz { LLMutexLock lock(&mNetworkQueueMutex); // +Mfnq mHTTPTextureQueue.erase(id); - mHTTPTextureBits += received_size; // Approximate - does not include header bits + mHTTPTextureBits = U32Bits(mHTTPTextureBits) + received_size; } // -Mfnq // NB: If you change deleteRequest() you should probably make @@ -3013,54 +3015,12 @@ bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority) return res; } -// Replicates and expands upon the base class's -// getPending() implementation. getPending() and -// runCondition() replicate one another's logic to -// an extent and are sometimes used for the same -// function (deciding whether or not to sleep/pause -// a thread). So the implementations need to stay -// in step, at least until this can be refactored and -// the redundancy eliminated. -// -// Threads: T* - -//virtual -S32 LLTextureFetch::getPending() -{ - S32 res; - lockData(); // +Ct - { - LLMutexLock lock(&mQueueMutex); // +Mfq - - res = mRequestQueue.size(); - res += mCommands.size(); - } // -Mfq - unlockData(); // -Ct - return res; -} - // Locks: Ct // virtual bool LLTextureFetch::runCondition() { - // Caller is holding the lock on LLThread's condition variable. - - // LLQueuedThread, unlike its base class LLThread, makes this a - // private method which is unfortunate. I want to use it directly - // but I'm going to have to re-implement the logic here (or change - // declarations, which I don't want to do right now). - // - // Changes here may need to be reflected in getPending(). - - bool have_no_commands(false); - { - LLMutexLock lock(&mQueueMutex); // +Mfq - - have_no_commands = mCommands.empty(); - } // -Mfq - - return ! (have_no_commands - && (mRequestQueue.empty() && mIdleThread)); // From base class + return ! ( !mCommandsSize && (!mRequestQueueSize && mIdleThread) ); // From base class + } ////////////////////////////////////////////////////////////////////////////// @@ -3104,16 +3064,12 @@ void LLTextureFetch::commonUpdate() //virtual S32 LLTextureFetch::update(F32 max_time_ms) { - static LLCachedControl<F32> band_width(gSavedSettings,"ThrottleBandwidthKBPS", 3000.0); + static LLCachedControl<F32> band_width(gSavedSettings,"ThrottleBandwidthKBPS", 3000.0f); { - mNetworkQueueMutex.lock(); // +Mfnq mMaxBandwidth = band_width(); - add(LLStatViewer::TEXTURE_NETWORK_DATA_RECEIVED, mHTTPTextureBits); - mHTTPTextureBits = (U32Bits)0; - - mNetworkQueueMutex.unlock(); // -Mfnq + add(LLStatViewer::TEXTURE_NETWORK_DATA_RECEIVED, mHTTPTextureBits.exchange((U32Bits)0)); } S32 res = LLWorkerThread::update(max_time_ms); @@ -3288,10 +3244,9 @@ void LLTextureFetch::sendRequestListToSimulators() } } // -Mfnq - for (work_request_map_t::iterator iter1 = requests.begin(); - iter1 != requests.end(); ++iter1) - { - LLHost host = iter1->first; + for (auto& request : requests) + { + LLHost host = request.first; // invalid host = use agent host if (host.isInvalid()) { @@ -3300,10 +3255,8 @@ void LLTextureFetch::sendRequestListToSimulators() S32 sim_request_count = 0; - for (request_list_t::iterator iter2 = iter1->second.begin(); - iter2 != iter1->second.end(); ++iter2) - { - LLTextureFetchWorker* req = *iter2; + for (LLTextureFetchWorker* req : request.second) + { if (gMessageSystem) { if (req->mSentRequest != LLTextureFetchWorker::SENT_SIM) @@ -3932,6 +3885,7 @@ void LLTextureFetch::cmdEnqueue(TFRequest * req) { lockQueue(); // +Mfq mCommands.push_back(req); + mCommandsSize = mCommands.size(); unlockQueue(); // -Mfq unpause(); @@ -3948,6 +3902,7 @@ LLTextureFetch::TFRequest * LLTextureFetch::cmdDequeue() ret = mCommands.front(); mCommands.pop_front(); } + mCommandsSize = mCommands.size(); unlockQueue(); // -Mfq return ret; diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index f9b0855d5eaab045e0a644ef49b9782ed508dfff..839cc366af5ae6c6a039b2870c175cdb7e67231a 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -135,7 +135,7 @@ class LLTextureFetch : public LLWorkerThread U32 getTotalNumHTTPRequests(); // Threads: T* - S32 getPending(); + S32 getPending() const override { return mCommandsSize + mRequestQueueSize; } // Threads: T* void lockQueue() { mQueueMutex.lock(); } @@ -332,12 +332,12 @@ class LLTextureFetch : public LLWorkerThread typedef std::map<LLHost,std::set<LLUUID> > cancel_queue_t; cancel_queue_t mCancelQueue; // Mfnq F32 mTextureBandwidth; // <none> - F32 mMaxBandwidth; // Mfnq + std::atomic<F32> mMaxBandwidth; LLTextureInfo mTextureInfo; LLTextureInfo mTextureInfoMainThread; // XXX possible delete - U32Bits mHTTPTextureBits; // Mfnq + std::atomic<U32Bits> mHTTPTextureBits; // XXX possible delete //debug use @@ -349,6 +349,7 @@ class LLTextureFetch : public LLWorkerThread // same locks. typedef std::deque<TFRequest *> command_queue_t; command_queue_t mCommands; // Mfq + std::atomic<S32> mCommandsSize; // If true, modifies some behaviors that help with QA tasks. const bool mQAMode;