From c2748a22469e8529ca4b27ad4ab1f31bffa51fb5 Mon Sep 17 00:00:00 2001 From: Liru Date: Fri, 18 Apr 2014 04:43:46 -0400 Subject: [PATCH] [LLMeshRepo sync] The rest of the changes from upstream --- indra/newview/llmeshrepository.cpp | 185 ++++++++++++++++++++++------- indra/newview/llmeshrepository.h | 8 +- 2 files changed, 147 insertions(+), 46 deletions(-) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 4b46e1ca0..033619628 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -67,6 +67,7 @@ #include "aicurl.h" #include "boost/lexical_cast.hpp" + #ifndef LL_WINDOWS #include "netdb.h" #endif @@ -303,7 +304,14 @@ public: ~LLMeshSkinInfoResponder() { - llassert(mProcessed || LLApp::isExiting()); + if (!LLApp::isQuitting() && + !mProcessed && + mMeshID.notNull()) + { // Something went wrong, retry + llwarns << "Timeout or service unavailable, retrying loadMeshSkinInfo() for " << mMeshID << llendl; + LLMeshRepository::sHTTPRetryCount++; + gMeshRepo.mThread->loadMeshSkinInfo(mMeshID); + } } virtual void completedRaw(U32 status, const std::string& reason, @@ -331,7 +339,14 @@ public: ~LLMeshDecompositionResponder() { - llassert(mProcessed || LLApp::isExiting()); + if (!LLApp::isQuitting() && + !mProcessed && + mMeshID.notNull()) + { // Something went wrong, retry + llwarns << "Timeout or service unavailable, retrying loadMeshDecomposition() for " << mMeshID << llendl; + LLMeshRepository::sHTTPRetryCount++; + gMeshRepo.mThread->loadMeshDecomposition(mMeshID); + } } virtual void completedRaw(U32 status, const std::string& reason, @@ -359,7 +374,14 @@ public: ~LLMeshPhysicsShapeResponder() { - llassert(mProcessed || LLApp::isExiting()); + if (!LLApp::isQuitting() && + !mProcessed && + mMeshID.notNull()) + { // Something went wrong, retry + llwarns << "Timeout or service unavailable, retrying loadMeshPhysicsShape() for " << mMeshID << llendl; + LLMeshRepository::sHTTPRetryCount++; + gMeshRepo.mThread->loadMeshPhysicsShape(mMeshID); + } } virtual void completedRaw(U32 status, const std::string& reason, @@ -542,6 +564,7 @@ public: LLMeshRepoThread::LLMeshRepoThread() : LLThread("mesh repo") { + mWaiting = false; mMutex = new LLMutex(); mHeaderMutex = new LLMutex(); mSignal = new LLCondition(); @@ -565,9 +588,13 @@ void LLMeshRepoThread::run() llwarns << "convex decomposition unable to be loaded" << llendl; } - mSignal->lock(); while (!LLApp::isQuitting()) { + mWaiting = true; + mSignal->wait(); + mWaiting = false; + + if (!LLApp::isQuitting()) { static U32 count = 0; @@ -659,7 +686,11 @@ void LLMeshRepoThread::run() mSignal->wait(); } - mSignal->unlock(); + + if (mSignal->isLocked()) + { //make sure to let go of the mutex associated with the given signal before shutting down + mSignal->unlock(); + } res = LLConvexDecomposition::quitThread(); if (res != LLCD_OK) @@ -692,6 +723,8 @@ void LLMeshRepoThread::lockAndLoadMeshLOD(const LLVolumeParams& mesh_params, S32 } } + + void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod) { //could be called from any thread LLMutexLock lock(mMutex); @@ -713,7 +746,7 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod) if (pending != mPendingLOD.end()) { //append this lod request to existing header request pending->second.push_back(lod); - llassert(pending->second.size() <= LLModel::NUM_LODS); + llassert(pending->second.size() <= LLModel::NUM_LODS) } else { //if no header request is pending, fetch header @@ -748,11 +781,16 @@ std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id) bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) { //protected by mMutex + + if (!mHeaderMutex) + { + return false; + } + mHeaderMutex->lock(); if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) - { - // We have no header info for this mesh, try again later. + { //we have no header info for this mesh, do nothing mHeaderMutex->unlock(); return false; } @@ -822,14 +860,17 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) return ret; } -//return false if failed to get header bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) { //protected by mMutex + if (!mHeaderMutex) + { + return false; + } + mHeaderMutex->lock(); if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) - { - // We have no header info for this mesh, try again later. + { //we have no header info for this mesh, do nothing mHeaderMutex->unlock(); return false; } @@ -852,6 +893,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) if (file.getSize() >= offset+size) { LLMeshRepository::sCacheBytesRead += size; + file.seek(offset); U8* buffer = new U8[size]; file.read(buffer, size); @@ -899,14 +941,17 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) return ret; } -//return false if failed to get header bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) { //protected by mMutex + if (!mHeaderMutex) + { + return false; + } + mHeaderMutex->lock(); if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) - { - // We have no header info for this mesh, retry later. + { //we have no header info for this mesh, do nothing mHeaderMutex->unlock(); return false; } @@ -933,7 +978,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) U8* buffer = new U8[size]; file.read(buffer, size); - //make sure buffer isn't all 0's (reserved block but not written) + //make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written) bool zero = true; for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) { @@ -1055,6 +1100,11 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& c //return false if failed to get mesh lod. bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count) { //protected by mMutex + if (!mHeaderMutex) + { + return false; + } + mHeaderMutex->lock(); bool retval = true; @@ -1082,7 +1132,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U8* buffer = new U8[size]; file.read(buffer, size); - //make sure buffer isn't all 0's (reserved block but not written) + //make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written) bool zero = true; for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) { @@ -1130,6 +1180,8 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, { mHeaderMutex->unlock(); } + + return retval; } bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size) @@ -1176,7 +1228,6 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat mMeshHeader[mesh_id] = header; } - LLMutexLock lock(mMutex); // make sure only one thread access mPendingLOD at the same time. //check for pending requests @@ -1189,10 +1240,8 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat mLODReqQ.push(req); LLMeshRepository::sLODProcessing++; } - - mPendingLOD.erase(iter); // FIRE-7182, only call erase if iter is really valid. + mPendingLOD.erase(iter); } - // mPendingLOD.erase(iter); // avoid crash by moving erase up. } return true; @@ -1352,6 +1401,11 @@ void LLMeshUploadThread::init(LLMeshUploadThread::instance_list& data, LLVector3 mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut") ; } +LLMeshUploadThread::~LLMeshUploadThread() +{ + +} + LLMeshUploadThread::DecompRequest::DecompRequest(LLModel* mdl, LLModel* base_model, LLMeshUploadThread* thread) { mStage = "single_hull"; @@ -1712,8 +1766,14 @@ void LLMeshUploadThread::generateHulls() } } + void LLMeshRepoThread::notifyLoadedMeshes() -{//called via gMeshRepo.notifyLoadedMeshes(). mMutex already locked +{ + if (!mMutex) + { + return; + } + while (!mLoadedQ.empty()) { mMutex->lock(); @@ -1837,6 +1897,12 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason, { mProcessed = true; + // thread could have already be destroyed during logout + if( !gMeshRepo.mThread ) + { + return; + } + S32 data_size = buffer->countAfter(channels.in(), NULL); if (status < 200 || status >= 400) @@ -1895,6 +1961,12 @@ void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason { mProcessed = true; + // thread could have already be destroyed during logout + if( !gMeshRepo.mThread ) + { + return; + } + S32 data_size = buffer->countAfter(channels.in(), NULL); if (status < 200 || status >= 400) @@ -1953,6 +2025,11 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r { mProcessed = true; + if( !gMeshRepo.mThread ) + { + return; + } + S32 data_size = buffer->countAfter(channels.in(), NULL); if (status < 200 || status >= 400) @@ -1964,12 +2041,13 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r { if (is_internal_http_error_that_warrants_a_retry(status) || status == HTTP_SERVICE_UNAVAILABLE) { //timeout or service unavailable, try again - llwarns << "Timeout or service unavailable, retrying." << llendl; + llwarns << "Timeout or service unavailable, retrying loadMeshDecomposition() for " << mMeshID << llendl; LLMeshRepository::sHTTPRetryCount++; gMeshRepo.mThread->loadMeshDecomposition(mMeshID); } else { + llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint llwarns << "Unhandled status " << status << llendl; } return; @@ -2010,6 +2088,12 @@ void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& re { mProcessed = true; + // thread could have already be destroyed during logout + if( !gMeshRepo.mThread ) + { + return; + } + S32 data_size = buffer->countAfter(channels.in(), NULL); if (status < 200 || status >= 400) @@ -2021,12 +2105,13 @@ void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& re { if (is_internal_http_error_that_warrants_a_retry(status) || status == HTTP_SERVICE_UNAVAILABLE) { //timeout or service unavailable, try again - llwarns << "Timeout or service unavailable, retrying." << llendl; + llwarns << "Timeout or service unavailable, retrying loadMeshPhysicsShape() for " << mMeshID << llendl; LLMeshRepository::sHTTPRetryCount++; gMeshRepo.mThread->loadMeshPhysicsShape(mMeshID); } else { + llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint llwarns << "Unhandled status " << status << llendl; } return; @@ -2067,18 +2152,27 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, { mProcessed = true; + // thread could have already be destroyed during logout + if( !gMeshRepo.mThread ) + { + return; + } + if (status < 200 || status >= 400) { //llwarns // << "Header responder failed with status: " // << status << ": " << reason << llendl; - // HTTP_SERVICE_UNAVAILABLE (503) or HTTP_INTERNAL_ERROR_*'s. + // 503 (service unavailable) or HTTP_INTERNAL_ERROR_*'s. // can be due to server load and can be retried // TODO*: Add maximum retry logic, exponential backoff // and (somewhat more optional than the others) retries // again after some set period of time + + llassert(status == HTTP_NOT_FOUND || status == HTTP_SERVICE_UNAVAILABLE || status == HTTP_REQUEST_TIME_OUT || status == HTTP_INTERNAL_ERROR); + if (is_internal_http_error_that_warrants_a_retry(status) || status == HTTP_SERVICE_UNAVAILABLE) { //retry llwarns << "Timeout or service unavailable, retrying." << llendl; @@ -2091,7 +2185,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, } else { - llwarns << "Unhandled status." << llendl; + llwarns << "Unhandled status: " << status << llendl; } } @@ -2379,12 +2473,10 @@ void LLMeshRepository::notifyLoadedMeshes() //call completed callbacks on finished decompositions mDecompThread->notifyCompleted(); - if (!mThread->mSignal->tryLock()) - { - // Curl thread is churning, wait for it to go idle. + if (!mThread->mWaiting) + { //curl thread is churning, wait for it to go idle return; } - mThread->mSignal->unlock(); static std::string region_name("never name a region this"); @@ -2393,7 +2485,6 @@ void LLMeshRepository::notifyLoadedMeshes() if (gAgent.getRegion()->getName() != region_name && gAgent.getRegion()->capabilitiesReceived()) { region_name = gAgent.getRegion()->getName(); - mGetMeshCapability = gAgent.getRegion()->getCapability("GetMesh2"); if (mGetMeshCapability.empty()) { @@ -2751,8 +2842,9 @@ void LLMeshRepository::uploadModel(std::vector& data, LLVector3 llinfos << "unable to upload, fee request failed" << llendl; return; } - AIMeshUpload* uploader = new AIMeshUpload(data, scale, upload_textures, upload_skin, upload_joints, upload_url, do_upload, fee_observer, upload_observer); - uploader->run(NULL, 0, false, true, &gMainThreadEngine); + AIMeshUpload* thread = new AIMeshUpload(data, scale, upload_textures, upload_skin, upload_joints, upload_url, + do_upload, fee_observer, upload_observer); + thread->run(NULL, 0, false, true, &gMainThreadEngine); } S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod) @@ -3048,13 +3140,15 @@ bool needTriangles( LLConvexDecomposition *aDC ) void LLPhysicsDecomp::setMeshData(LLCDMeshData& mesh, bool vertex_based) { - LLConvexDecomposition *pDeComp = LLConvexDecomposition::getInstance(); - - if( !pDeComp ) - return; - - if( vertex_based ) - vertex_based = !needTriangles( pDeComp ); + // HACD + if (vertex_based) + { + if (LLConvexDecomposition* pDeComp = LLConvexDecomposition::getInstance()) + vertex_based = !needTriangles(pDeComp); + else + return; + } + // mesh.mVertexBase = mCurRequest->mPositions[0].mV; mesh.mVertexStrideBytes = 12; @@ -3072,7 +3166,10 @@ void LLPhysicsDecomp::setMeshData(LLCDMeshData& mesh, bool vertex_based) if ((vertex_based || mesh.mNumTriangles > 0) && mesh.mNumVertices > 2) { LLCDResult ret = LLCD_OK; - ret = LLConvexDecomposition::getInstance()->setMeshData(&mesh, vertex_based); + if (LLConvexDecomposition::getInstance() != NULL) + { + ret = LLConvexDecomposition::getInstance()->setMeshData(&mesh, vertex_based); + } if (ret) { @@ -3127,6 +3224,7 @@ void LLPhysicsDecomp::doDecomposition() continue; } + if (param->mType == LLCDParam::LLCD_FLOAT) { ret = LLConvexDecomposition::getInstance()->setParam(param->mName, (F32) value.asReal()); @@ -3440,10 +3538,12 @@ void LLPhysicsDecomp::run() } } - mSignal->unlock(); - decomp->quitThread(); + if (mSignal->isLocked()) + { //let go of mSignal's associated mutex + mSignal->unlock(); + } mDone = true; } @@ -3649,4 +3749,3 @@ bool LLMeshRepository::meshRezEnabled() } return false; } - diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 4ef99f1b1..c408f8a12 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -225,6 +225,8 @@ public: LLMutex* mHeaderMutex; LLCondition* mSignal; + bool mWaiting; + //map of known mesh headers typedef std::map mesh_header_map; mesh_header_map mMeshHeader; @@ -405,10 +407,11 @@ public: #endif void init(instance_list& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, bool do_upload, LLHandle const& fee_observer, LLHandle const& upload_observer); + ~LLMeshUploadThread(); void postRequest(std::string& url, AIMeshUpload* state_machine); - /*virtual*/ bool run(); + virtual bool run(); void preStart(); void generateHulls(); @@ -504,8 +507,7 @@ public: void uploadModel(std::vector& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload = true, - LLHandle fee_observer= (LLHandle()), - LLHandle upload_observer = (LLHandle())); + LLHandle fee_observer= (LLHandle()), LLHandle upload_observer = (LLHandle())); S32 getMeshSize(const LLUUID& mesh_id, S32 lod);