diff options
Diffstat (limited to 'indra/llcommon/llworkerthread.cpp')
-rw-r--r-- | indra/llcommon/llworkerthread.cpp | 796 |
1 files changed, 398 insertions, 398 deletions
diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp index 22a922c94b..b751c95679 100644 --- a/indra/llcommon/llworkerthread.cpp +++ b/indra/llcommon/llworkerthread.cpp @@ -1,398 +1,398 @@ -/**
- * @file llworkerthread.cpp
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-#include "llworkerthread.h"
-#include "llstl.h"
-
-#if USE_FRAME_CALLBACK_MANAGER
-#include "llframecallbackmanager.h"
-#endif
-
-//============================================================================
-// Run on MAIN thread
-
-LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded, bool should_pause) :
- LLQueuedThread(name, threaded, should_pause)
-{
- mDeleteMutex = new LLMutex();
-
- if(!mLocalAPRFilePoolp)
- {
- mLocalAPRFilePoolp = new LLVolatileAPRPool() ;
- }
-}
-
-LLWorkerThread::~LLWorkerThread()
-{
- // Delete any workers in the delete queue (should be safe - had better be!)
- if (!mDeleteList.empty())
- {
- LL_WARNS() << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size()
- << " entries in delete list." << LL_ENDL;
- }
-
- delete mDeleteMutex;
-
- // ~LLQueuedThread() will be called here
-}
-
-//called only in destructor.
-void LLWorkerThread::clearDeleteList()
-{
- // Delete any workers in the delete queue (should be safe - had better be!)
- if (!mDeleteList.empty())
- {
- LL_WARNS() << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size()
- << " entries in delete list." << LL_ENDL;
-
- mDeleteMutex->lock();
- for (LLWorkerClass* worker : mDeleteList)
- {
- worker->mRequestHandle = LLWorkerThread::nullHandle();
- worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK);
- worker->clearFlags(LLWorkerClass::WCF_WORKING);
- delete worker;
- }
- mDeleteList.clear() ;
- mDeleteMutex->unlock() ;
- }
-}
-
-// virtual
-size_t LLWorkerThread::update(F32 max_time_ms)
-{
- auto res = LLQueuedThread::update(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(); )
- {
- delete_list_t::iterator curiter = iter++;
- LLWorkerClass* worker = *curiter;
- if (worker->deleteOK())
- {
- if (worker->getFlags(LLWorkerClass::WCF_WORK_FINISHED))
- {
- worker->setFlags(LLWorkerClass::WCF_DELETE_REQUESTED);
- delete_list.push_back(worker);
- mDeleteList.erase(curiter);
- }
- else if (!worker->getFlags(LLWorkerClass::WCF_ABORT_REQUESTED))
- {
- abort_list.push_back(worker);
- }
- }
- }
- mDeleteMutex->unlock();
- // abort and delete after releasing mutex
- for (LLWorkerClass* worker : abort_list)
- {
- worker->abortWork(false);
- }
- for (LLWorkerClass* worker : delete_list)
- {
- if (worker->mRequestHandle)
- {
- // Finished but not completed
- completeRequest(worker->mRequestHandle);
- worker->mRequestHandle = LLWorkerThread::nullHandle();
- worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK);
- }
- delete worker;
- }
- // delete and aborted entries mean there's still work to do
- res += delete_list.size() + abort_list.size();
- return res;
-}
-
-//----------------------------------------------------------------------------
-
-LLWorkerThread::handle_t LLWorkerThread::addWorkRequest(LLWorkerClass* workerclass, S32 param)
-{
- handle_t handle = generateHandle();
-
- WorkRequest* req = new WorkRequest(handle, workerclass, param);
-
- bool res = addRequest(req);
- if (!res)
- {
- LL_ERRS() << "add called after LLWorkerThread::cleanupClass()" << LL_ENDL;
- req->deleteRequest();
- handle = nullHandle();
- }
-
- return handle;
-}
-
-void LLWorkerThread::deleteWorker(LLWorkerClass* workerclass)
-{
- mDeleteMutex->lock();
- mDeleteList.push_back(workerclass);
- mDeleteMutex->unlock();
-}
-
-//============================================================================
-// Runs on its OWN thread
-
-LLWorkerThread::WorkRequest::WorkRequest(handle_t handle, LLWorkerClass* workerclass, S32 param) :
- LLQueuedThread::QueuedRequest(handle),
- mWorkerClass(workerclass),
- mParam(param)
-{
-}
-
-LLWorkerThread::WorkRequest::~WorkRequest()
-{
-}
-
-// virtual (required for access by LLWorkerThread)
-void LLWorkerThread::WorkRequest::deleteRequest()
-{
- LLQueuedThread::QueuedRequest::deleteRequest();
-}
-
-// virtual
-bool LLWorkerThread::WorkRequest::processRequest()
-{
- LL_PROFILE_ZONE_SCOPED;
- LLWorkerClass* workerclass = getWorkerClass();
- workerclass->setWorking(true);
- bool complete = workerclass->doWork(getParam());
- workerclass->setWorking(false);
- return complete;
-}
-
-// virtual
-void LLWorkerThread::WorkRequest::finishRequest(bool completed)
-{
- LL_PROFILE_ZONE_SCOPED;
- LLWorkerClass* workerclass = getWorkerClass();
- workerclass->finishWork(getParam(), completed);
- U32 flags = LLWorkerClass::WCF_WORK_FINISHED | (completed ? 0 : LLWorkerClass::WCF_WORK_ABORTED);
- workerclass->setFlags(flags);
-}
-
-//============================================================================
-// LLWorkerClass:: operates in main thread
-
-LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& name)
- : mWorkerThread(workerthread),
- mWorkerClassName(name),
- mRequestHandle(LLWorkerThread::nullHandle()),
- mMutex(),
- mWorkFlags(0)
-{
- if (!mWorkerThread)
- {
- LL_ERRS() << "LLWorkerClass() called with NULL workerthread: " << name << LL_ENDL;
- }
-}
-
-LLWorkerClass::~LLWorkerClass()
-{
- llassert_always(!(mWorkFlags & WCF_WORKING));
- llassert_always(mWorkFlags & WCF_DELETE_REQUESTED);
- llassert_always(!mMutex.isLocked());
- if (mRequestHandle != LLWorkerThread::nullHandle())
- {
- LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle);
- if (!workreq)
- {
- LL_ERRS() << "LLWorkerClass destroyed with stale work handle" << LL_ENDL;
- }
- if (workreq->getStatus() != LLWorkerThread::STATUS_ABORTED &&
- workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE)
- {
- LL_ERRS() << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << LL_ENDL;
- }
- }
-}
-
-void LLWorkerClass::setWorkerThread(LLWorkerThread* workerthread)
-{
- mMutex.lock();
- if (mRequestHandle != LLWorkerThread::nullHandle())
- {
- LL_ERRS() << "LLWorkerClass attempt to change WorkerThread with active worker!" << LL_ENDL;
- }
- mWorkerThread = workerthread;
- mMutex.unlock();
-}
-
-//----------------------------------------------------------------------------
-
-//virtual
-void LLWorkerClass::finishWork(S32 param, bool success)
-{
-}
-
-//virtual
-bool LLWorkerClass::deleteOK()
-{
- return true; // default always OK
-}
-
-//----------------------------------------------------------------------------
-
-// Called from worker thread
-void LLWorkerClass::setWorking(bool working)
-{
- mMutex.lock();
- if (working)
- {
- llassert_always(!(mWorkFlags & WCF_WORKING));
- setFlags(WCF_WORKING);
- }
- else
- {
- llassert_always((mWorkFlags & WCF_WORKING));
- clearFlags(WCF_WORKING);
- }
- mMutex.unlock();
-}
-
-//----------------------------------------------------------------------------
-
-bool LLWorkerClass::yield()
-{
- LLThread::yield();
- mWorkerThread->checkPause();
- bool res;
- mMutex.lock();
- res = (getFlags() & WCF_ABORT_REQUESTED) != 0;
- mMutex.unlock();
- return res;
-}
-
-//----------------------------------------------------------------------------
-
-// calls startWork, adds doWork() to queue
-void LLWorkerClass::addWork(S32 param)
-{
- mMutex.lock();
- llassert_always(!(mWorkFlags & (WCF_WORKING|WCF_HAVE_WORK)));
- if (mRequestHandle != LLWorkerThread::nullHandle())
- {
- LL_ERRS() << "LLWorkerClass attempt to add work with active worker!" << LL_ENDL;
- }
-#if _DEBUG
-// LL_INFOS() << "addWork: " << mWorkerClassName << " Param: " << param << LL_ENDL;
-#endif
- startWork(param);
- clearFlags(WCF_WORK_FINISHED|WCF_WORK_ABORTED);
- setFlags(WCF_HAVE_WORK);
- mRequestHandle = mWorkerThread->addWorkRequest(this, param);
- mMutex.unlock();
-}
-
-void LLWorkerClass::abortWork(bool autocomplete)
-{
- mMutex.lock();
-#if _DEBUG
-// LLWorkerThread::WorkRequest* workreq = mWorkerThread->getRequest(mRequestHandle);
-// if (workreq)
-// LL_INFOS() << "abortWork: " << mWorkerClassName << " Param: " << workreq->getParam() << LL_ENDL;
-#endif
- if (mRequestHandle != LLWorkerThread::nullHandle())
- {
- mWorkerThread->abortRequest(mRequestHandle, autocomplete);
- setFlags(WCF_ABORT_REQUESTED);
- }
- mMutex.unlock();
-}
-
-// if doWork is complete or aborted, call endWork() and return true
-bool LLWorkerClass::checkWork(bool aborting)
-{
- LLMutexLock lock(&mMutex);
- bool complete = false, abort = false;
- if (mRequestHandle != LLWorkerThread::nullHandle())
- {
- LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle);
- if(!workreq)
- {
- if(mWorkerThread->isQuitting() || mWorkerThread->isStopped()) //the mWorkerThread is not running
- {
- mRequestHandle = LLWorkerThread::nullHandle();
- clearFlags(WCF_HAVE_WORK);
- }
- else
- {
- llassert_always(workreq);
- }
- return true ;
- }
-
- LLQueuedThread::status_t status = workreq->getStatus();
- if (status == LLWorkerThread::STATUS_ABORTED)
- {
- complete = true;
- abort = true;
- }
- else if (status == LLWorkerThread::STATUS_COMPLETE)
- {
- complete = true;
- }
- else
- {
- llassert_always(!aborting || (workreq->getFlags() & LLQueuedThread::FLAG_ABORT));
- }
- if (complete)
- {
- llassert_always(!(getFlags(WCF_WORKING)));
- endWork(workreq->getParam(), abort);
- mWorkerThread->completeRequest(mRequestHandle);
- mRequestHandle = LLWorkerThread::nullHandle();
- clearFlags(WCF_HAVE_WORK);
- }
- }
- else
- {
- complete = true;
- }
- return complete;
-}
-
-void LLWorkerClass::scheduleDelete()
-{
- bool do_delete = false;
- mMutex.lock();
- if (!(getFlags(WCF_DELETE_REQUESTED)))
- {
- setFlags(WCF_DELETE_REQUESTED);
- do_delete = true;
- }
- mMutex.unlock();
- if (do_delete)
- {
- mWorkerThread->deleteWorker(this);
- }
-}
-
-//============================================================================
-
+/** + * @file llworkerthread.cpp + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llworkerthread.h" +#include "llstl.h" + +#if USE_FRAME_CALLBACK_MANAGER +#include "llframecallbackmanager.h" +#endif + +//============================================================================ +// Run on MAIN thread + +LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded, bool should_pause) : + LLQueuedThread(name, threaded, should_pause) +{ + mDeleteMutex = new LLMutex(); + + if(!mLocalAPRFilePoolp) + { + mLocalAPRFilePoolp = new LLVolatileAPRPool() ; + } +} + +LLWorkerThread::~LLWorkerThread() +{ + // Delete any workers in the delete queue (should be safe - had better be!) + if (!mDeleteList.empty()) + { + LL_WARNS() << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() + << " entries in delete list." << LL_ENDL; + } + + delete mDeleteMutex; + + // ~LLQueuedThread() will be called here +} + +//called only in destructor. +void LLWorkerThread::clearDeleteList() +{ + // Delete any workers in the delete queue (should be safe - had better be!) + if (!mDeleteList.empty()) + { + LL_WARNS() << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() + << " entries in delete list." << LL_ENDL; + + mDeleteMutex->lock(); + for (LLWorkerClass* worker : mDeleteList) + { + worker->mRequestHandle = LLWorkerThread::nullHandle(); + worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK); + worker->clearFlags(LLWorkerClass::WCF_WORKING); + delete worker; + } + mDeleteList.clear() ; + mDeleteMutex->unlock() ; + } +} + +// virtual +size_t LLWorkerThread::update(F32 max_time_ms) +{ + auto res = LLQueuedThread::update(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(); ) + { + delete_list_t::iterator curiter = iter++; + LLWorkerClass* worker = *curiter; + if (worker->deleteOK()) + { + if (worker->getFlags(LLWorkerClass::WCF_WORK_FINISHED)) + { + worker->setFlags(LLWorkerClass::WCF_DELETE_REQUESTED); + delete_list.push_back(worker); + mDeleteList.erase(curiter); + } + else if (!worker->getFlags(LLWorkerClass::WCF_ABORT_REQUESTED)) + { + abort_list.push_back(worker); + } + } + } + mDeleteMutex->unlock(); + // abort and delete after releasing mutex + for (LLWorkerClass* worker : abort_list) + { + worker->abortWork(false); + } + for (LLWorkerClass* worker : delete_list) + { + if (worker->mRequestHandle) + { + // Finished but not completed + completeRequest(worker->mRequestHandle); + worker->mRequestHandle = LLWorkerThread::nullHandle(); + worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK); + } + delete worker; + } + // delete and aborted entries mean there's still work to do + res += delete_list.size() + abort_list.size(); + return res; +} + +//---------------------------------------------------------------------------- + +LLWorkerThread::handle_t LLWorkerThread::addWorkRequest(LLWorkerClass* workerclass, S32 param) +{ + handle_t handle = generateHandle(); + + WorkRequest* req = new WorkRequest(handle, workerclass, param); + + bool res = addRequest(req); + if (!res) + { + LL_ERRS() << "add called after LLWorkerThread::cleanupClass()" << LL_ENDL; + req->deleteRequest(); + handle = nullHandle(); + } + + return handle; +} + +void LLWorkerThread::deleteWorker(LLWorkerClass* workerclass) +{ + mDeleteMutex->lock(); + mDeleteList.push_back(workerclass); + mDeleteMutex->unlock(); +} + +//============================================================================ +// Runs on its OWN thread + +LLWorkerThread::WorkRequest::WorkRequest(handle_t handle, LLWorkerClass* workerclass, S32 param) : + LLQueuedThread::QueuedRequest(handle), + mWorkerClass(workerclass), + mParam(param) +{ +} + +LLWorkerThread::WorkRequest::~WorkRequest() +{ +} + +// virtual (required for access by LLWorkerThread) +void LLWorkerThread::WorkRequest::deleteRequest() +{ + LLQueuedThread::QueuedRequest::deleteRequest(); +} + +// virtual +bool LLWorkerThread::WorkRequest::processRequest() +{ + LL_PROFILE_ZONE_SCOPED; + LLWorkerClass* workerclass = getWorkerClass(); + workerclass->setWorking(true); + bool complete = workerclass->doWork(getParam()); + workerclass->setWorking(false); + return complete; +} + +// virtual +void LLWorkerThread::WorkRequest::finishRequest(bool completed) +{ + LL_PROFILE_ZONE_SCOPED; + LLWorkerClass* workerclass = getWorkerClass(); + workerclass->finishWork(getParam(), completed); + U32 flags = LLWorkerClass::WCF_WORK_FINISHED | (completed ? 0 : LLWorkerClass::WCF_WORK_ABORTED); + workerclass->setFlags(flags); +} + +//============================================================================ +// LLWorkerClass:: operates in main thread + +LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& name) + : mWorkerThread(workerthread), + mWorkerClassName(name), + mRequestHandle(LLWorkerThread::nullHandle()), + mMutex(), + mWorkFlags(0) +{ + if (!mWorkerThread) + { + LL_ERRS() << "LLWorkerClass() called with NULL workerthread: " << name << LL_ENDL; + } +} + +LLWorkerClass::~LLWorkerClass() +{ + llassert_always(!(mWorkFlags & WCF_WORKING)); + llassert_always(mWorkFlags & WCF_DELETE_REQUESTED); + llassert_always(!mMutex.isLocked()); + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); + if (!workreq) + { + LL_ERRS() << "LLWorkerClass destroyed with stale work handle" << LL_ENDL; + } + if (workreq->getStatus() != LLWorkerThread::STATUS_ABORTED && + workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE) + { + LL_ERRS() << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << LL_ENDL; + } + } +} + +void LLWorkerClass::setWorkerThread(LLWorkerThread* workerthread) +{ + mMutex.lock(); + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + LL_ERRS() << "LLWorkerClass attempt to change WorkerThread with active worker!" << LL_ENDL; + } + mWorkerThread = workerthread; + mMutex.unlock(); +} + +//---------------------------------------------------------------------------- + +//virtual +void LLWorkerClass::finishWork(S32 param, bool success) +{ +} + +//virtual +bool LLWorkerClass::deleteOK() +{ + return true; // default always OK +} + +//---------------------------------------------------------------------------- + +// Called from worker thread +void LLWorkerClass::setWorking(bool working) +{ + mMutex.lock(); + if (working) + { + llassert_always(!(mWorkFlags & WCF_WORKING)); + setFlags(WCF_WORKING); + } + else + { + llassert_always((mWorkFlags & WCF_WORKING)); + clearFlags(WCF_WORKING); + } + mMutex.unlock(); +} + +//---------------------------------------------------------------------------- + +bool LLWorkerClass::yield() +{ + LLThread::yield(); + mWorkerThread->checkPause(); + bool res; + mMutex.lock(); + res = (getFlags() & WCF_ABORT_REQUESTED) != 0; + mMutex.unlock(); + return res; +} + +//---------------------------------------------------------------------------- + +// calls startWork, adds doWork() to queue +void LLWorkerClass::addWork(S32 param) +{ + mMutex.lock(); + llassert_always(!(mWorkFlags & (WCF_WORKING|WCF_HAVE_WORK))); + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + LL_ERRS() << "LLWorkerClass attempt to add work with active worker!" << LL_ENDL; + } +#if _DEBUG +// LL_INFOS() << "addWork: " << mWorkerClassName << " Param: " << param << LL_ENDL; +#endif + startWork(param); + clearFlags(WCF_WORK_FINISHED|WCF_WORK_ABORTED); + setFlags(WCF_HAVE_WORK); + mRequestHandle = mWorkerThread->addWorkRequest(this, param); + mMutex.unlock(); +} + +void LLWorkerClass::abortWork(bool autocomplete) +{ + mMutex.lock(); +#if _DEBUG +// LLWorkerThread::WorkRequest* workreq = mWorkerThread->getRequest(mRequestHandle); +// if (workreq) +// LL_INFOS() << "abortWork: " << mWorkerClassName << " Param: " << workreq->getParam() << LL_ENDL; +#endif + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + mWorkerThread->abortRequest(mRequestHandle, autocomplete); + setFlags(WCF_ABORT_REQUESTED); + } + mMutex.unlock(); +} + +// if doWork is complete or aborted, call endWork() and return true +bool LLWorkerClass::checkWork(bool aborting) +{ + LLMutexLock lock(&mMutex); + bool complete = false, abort = false; + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); + if(!workreq) + { + if(mWorkerThread->isQuitting() || mWorkerThread->isStopped()) //the mWorkerThread is not running + { + mRequestHandle = LLWorkerThread::nullHandle(); + clearFlags(WCF_HAVE_WORK); + } + else + { + llassert_always(workreq); + } + return true ; + } + + LLQueuedThread::status_t status = workreq->getStatus(); + if (status == LLWorkerThread::STATUS_ABORTED) + { + complete = true; + abort = true; + } + else if (status == LLWorkerThread::STATUS_COMPLETE) + { + complete = true; + } + else + { + llassert_always(!aborting || (workreq->getFlags() & LLQueuedThread::FLAG_ABORT)); + } + if (complete) + { + llassert_always(!(getFlags(WCF_WORKING))); + endWork(workreq->getParam(), abort); + mWorkerThread->completeRequest(mRequestHandle); + mRequestHandle = LLWorkerThread::nullHandle(); + clearFlags(WCF_HAVE_WORK); + } + } + else + { + complete = true; + } + return complete; +} + +void LLWorkerClass::scheduleDelete() +{ + bool do_delete = false; + mMutex.lock(); + if (!(getFlags(WCF_DELETE_REQUESTED))) + { + setFlags(WCF_DELETE_REQUESTED); + do_delete = true; + } + mMutex.unlock(); + if (do_delete) + { + mWorkerThread->deleteWorker(this); + } +} + +//============================================================================ + |