PageRenderTime 81ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/llworkerthread.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 410 lines | 310 code | 43 blank | 57 comment | 49 complexity | 879e0baf83bf1954d8190bb768e9bc9c MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llworkerthread.cpp
  3. *
  4. * $LicenseInfo:firstyear=2004&license=viewerlgpl$
  5. * Second Life Viewer Source Code
  6. * Copyright (C) 2010, Linden Research, Inc.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation;
  11. * version 2.1 of the License only.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  23. * $/LicenseInfo$
  24. */
  25. #include "linden_common.h"
  26. #include "llworkerthread.h"
  27. #include "llstl.h"
  28. #if USE_FRAME_CALLBACK_MANAGER
  29. #include "llframecallbackmanager.h"
  30. #endif
  31. //============================================================================
  32. // Run on MAIN thread
  33. LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded, bool should_pause) :
  34. LLQueuedThread(name, threaded, should_pause)
  35. {
  36. mDeleteMutex = new LLMutex(NULL);
  37. if(!mLocalAPRFilePoolp)
  38. {
  39. mLocalAPRFilePoolp = new LLVolatileAPRPool() ;
  40. }
  41. }
  42. LLWorkerThread::~LLWorkerThread()
  43. {
  44. // Delete any workers in the delete queue (should be safe - had better be!)
  45. if (!mDeleteList.empty())
  46. {
  47. llwarns << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size()
  48. << " entries in delete list." << llendl;
  49. }
  50. delete mDeleteMutex;
  51. // ~LLQueuedThread() will be called here
  52. }
  53. //called only in destructor.
  54. void LLWorkerThread::clearDeleteList()
  55. {
  56. // Delete any workers in the delete queue (should be safe - had better be!)
  57. if (!mDeleteList.empty())
  58. {
  59. llwarns << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size()
  60. << " entries in delete list." << llendl;
  61. mDeleteMutex->lock();
  62. for (delete_list_t::iterator iter = mDeleteList.begin(); iter != mDeleteList.end(); ++iter)
  63. {
  64. (*iter)->mRequestHandle = LLWorkerThread::nullHandle();
  65. (*iter)->clearFlags(LLWorkerClass::WCF_HAVE_WORK);
  66. delete *iter ;
  67. }
  68. mDeleteList.clear() ;
  69. mDeleteMutex->unlock() ;
  70. }
  71. }
  72. // virtual
  73. S32 LLWorkerThread::update(F32 max_time_ms)
  74. {
  75. S32 res = LLQueuedThread::update(max_time_ms);
  76. // Delete scheduled workers
  77. std::vector<LLWorkerClass*> delete_list;
  78. std::vector<LLWorkerClass*> abort_list;
  79. mDeleteMutex->lock();
  80. for (delete_list_t::iterator iter = mDeleteList.begin();
  81. iter != mDeleteList.end(); )
  82. {
  83. delete_list_t::iterator curiter = iter++;
  84. LLWorkerClass* worker = *curiter;
  85. if (worker->deleteOK())
  86. {
  87. if (worker->getFlags(LLWorkerClass::WCF_WORK_FINISHED))
  88. {
  89. delete_list.push_back(worker);
  90. mDeleteList.erase(curiter);
  91. }
  92. else if (!worker->getFlags(LLWorkerClass::WCF_ABORT_REQUESTED))
  93. {
  94. abort_list.push_back(worker);
  95. }
  96. }
  97. }
  98. mDeleteMutex->unlock();
  99. // abort and delete after releasing mutex
  100. for (std::vector<LLWorkerClass*>::iterator iter = abort_list.begin();
  101. iter != abort_list.end(); ++iter)
  102. {
  103. (*iter)->abortWork(false);
  104. }
  105. for (std::vector<LLWorkerClass*>::iterator iter = delete_list.begin();
  106. iter != delete_list.end(); ++iter)
  107. {
  108. LLWorkerClass* worker = *iter;
  109. if (worker->mRequestHandle)
  110. {
  111. // Finished but not completed
  112. completeRequest(worker->mRequestHandle);
  113. worker->mRequestHandle = LLWorkerThread::nullHandle();
  114. worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK);
  115. }
  116. delete *iter;
  117. }
  118. // delete and aborted entries mean there's still work to do
  119. res += delete_list.size() + abort_list.size();
  120. return res;
  121. }
  122. //----------------------------------------------------------------------------
  123. LLWorkerThread::handle_t LLWorkerThread::addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority)
  124. {
  125. handle_t handle = generateHandle();
  126. WorkRequest* req = new WorkRequest(handle, priority, workerclass, param);
  127. bool res = addRequest(req);
  128. if (!res)
  129. {
  130. llerrs << "add called after LLWorkerThread::cleanupClass()" << llendl;
  131. req->deleteRequest();
  132. handle = nullHandle();
  133. }
  134. return handle;
  135. }
  136. void LLWorkerThread::deleteWorker(LLWorkerClass* workerclass)
  137. {
  138. mDeleteMutex->lock();
  139. mDeleteList.push_back(workerclass);
  140. mDeleteMutex->unlock();
  141. }
  142. //============================================================================
  143. // Runs on its OWN thread
  144. LLWorkerThread::WorkRequest::WorkRequest(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param) :
  145. LLQueuedThread::QueuedRequest(handle, priority),
  146. mWorkerClass(workerclass),
  147. mParam(param)
  148. {
  149. }
  150. LLWorkerThread::WorkRequest::~WorkRequest()
  151. {
  152. }
  153. // virtual (required for access by LLWorkerThread)
  154. void LLWorkerThread::WorkRequest::deleteRequest()
  155. {
  156. LLQueuedThread::QueuedRequest::deleteRequest();
  157. }
  158. // virtual
  159. bool LLWorkerThread::WorkRequest::processRequest()
  160. {
  161. LLWorkerClass* workerclass = getWorkerClass();
  162. workerclass->setWorking(true);
  163. bool complete = workerclass->doWork(getParam());
  164. workerclass->setWorking(false);
  165. return complete;
  166. }
  167. // virtual
  168. void LLWorkerThread::WorkRequest::finishRequest(bool completed)
  169. {
  170. LLWorkerClass* workerclass = getWorkerClass();
  171. workerclass->finishWork(getParam(), completed);
  172. U32 flags = LLWorkerClass::WCF_WORK_FINISHED | (completed ? 0 : LLWorkerClass::WCF_WORK_ABORTED);
  173. workerclass->setFlags(flags);
  174. }
  175. //============================================================================
  176. // LLWorkerClass:: operates in main thread
  177. LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& name)
  178. : mWorkerThread(workerthread),
  179. mWorkerClassName(name),
  180. mRequestHandle(LLWorkerThread::nullHandle()),
  181. mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
  182. mMutex(NULL),
  183. mWorkFlags(0)
  184. {
  185. if (!mWorkerThread)
  186. {
  187. llerrs << "LLWorkerClass() called with NULL workerthread: " << name << llendl;
  188. }
  189. }
  190. LLWorkerClass::~LLWorkerClass()
  191. {
  192. llassert_always(!(mWorkFlags & WCF_WORKING));
  193. llassert_always(mWorkFlags & WCF_DELETE_REQUESTED);
  194. llassert_always(!mMutex.isLocked());
  195. if (mRequestHandle != LLWorkerThread::nullHandle())
  196. {
  197. LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle);
  198. if (!workreq)
  199. {
  200. llerrs << "LLWorkerClass destroyed with stale work handle" << llendl;
  201. }
  202. if (workreq->getStatus() != LLWorkerThread::STATUS_ABORTED &&
  203. workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE)
  204. {
  205. llerrs << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << llendl;
  206. }
  207. }
  208. }
  209. void LLWorkerClass::setWorkerThread(LLWorkerThread* workerthread)
  210. {
  211. mMutex.lock();
  212. if (mRequestHandle != LLWorkerThread::nullHandle())
  213. {
  214. llerrs << "LLWorkerClass attempt to change WorkerThread with active worker!" << llendl;
  215. }
  216. mWorkerThread = workerthread;
  217. mMutex.unlock();
  218. }
  219. //----------------------------------------------------------------------------
  220. //virtual
  221. void LLWorkerClass::finishWork(S32 param, bool success)
  222. {
  223. }
  224. //virtual
  225. bool LLWorkerClass::deleteOK()
  226. {
  227. return true; // default always OK
  228. }
  229. //----------------------------------------------------------------------------
  230. // Called from worker thread
  231. void LLWorkerClass::setWorking(bool working)
  232. {
  233. mMutex.lock();
  234. if (working)
  235. {
  236. llassert_always(!(mWorkFlags & WCF_WORKING));
  237. setFlags(WCF_WORKING);
  238. }
  239. else
  240. {
  241. llassert_always((mWorkFlags & WCF_WORKING));
  242. clearFlags(WCF_WORKING);
  243. }
  244. mMutex.unlock();
  245. }
  246. //----------------------------------------------------------------------------
  247. bool LLWorkerClass::yield()
  248. {
  249. LLThread::yield();
  250. mWorkerThread->checkPause();
  251. bool res;
  252. mMutex.lock();
  253. res = (getFlags() & WCF_ABORT_REQUESTED) ? true : false;
  254. mMutex.unlock();
  255. return res;
  256. }
  257. //----------------------------------------------------------------------------
  258. // calls startWork, adds doWork() to queue
  259. void LLWorkerClass::addWork(S32 param, U32 priority)
  260. {
  261. mMutex.lock();
  262. llassert_always(!(mWorkFlags & (WCF_WORKING|WCF_HAVE_WORK)));
  263. if (mRequestHandle != LLWorkerThread::nullHandle())
  264. {
  265. llerrs << "LLWorkerClass attempt to add work with active worker!" << llendl;
  266. }
  267. #if _DEBUG
  268. // llinfos << "addWork: " << mWorkerClassName << " Param: " << param << llendl;
  269. #endif
  270. startWork(param);
  271. clearFlags(WCF_WORK_FINISHED|WCF_WORK_ABORTED);
  272. setFlags(WCF_HAVE_WORK);
  273. mRequestHandle = mWorkerThread->addWorkRequest(this, param, priority);
  274. mMutex.unlock();
  275. }
  276. void LLWorkerClass::abortWork(bool autocomplete)
  277. {
  278. mMutex.lock();
  279. #if _DEBUG
  280. // LLWorkerThread::WorkRequest* workreq = mWorkerThread->getRequest(mRequestHandle);
  281. // if (workreq)
  282. // llinfos << "abortWork: " << mWorkerClassName << " Param: " << workreq->getParam() << llendl;
  283. #endif
  284. if (mRequestHandle != LLWorkerThread::nullHandle())
  285. {
  286. mWorkerThread->abortRequest(mRequestHandle, autocomplete);
  287. mWorkerThread->setPriority(mRequestHandle, LLQueuedThread::PRIORITY_IMMEDIATE);
  288. setFlags(WCF_ABORT_REQUESTED);
  289. }
  290. mMutex.unlock();
  291. }
  292. // if doWork is complete or aborted, call endWork() and return true
  293. bool LLWorkerClass::checkWork(bool aborting)
  294. {
  295. LLMutexLock lock(&mMutex);
  296. bool complete = false, abort = false;
  297. if (mRequestHandle != LLWorkerThread::nullHandle())
  298. {
  299. LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle);
  300. if(!workreq)
  301. {
  302. if(mWorkerThread->isQuitting() || mWorkerThread->isStopped()) //the mWorkerThread is not running
  303. {
  304. mRequestHandle = LLWorkerThread::nullHandle();
  305. clearFlags(WCF_HAVE_WORK);
  306. }
  307. else
  308. {
  309. llassert_always(workreq);
  310. }
  311. return true ;
  312. }
  313. LLQueuedThread::status_t status = workreq->getStatus();
  314. if (status == LLWorkerThread::STATUS_ABORTED)
  315. {
  316. complete = true;
  317. abort = true;
  318. }
  319. else if (status == LLWorkerThread::STATUS_COMPLETE)
  320. {
  321. complete = true;
  322. }
  323. else
  324. {
  325. llassert_always(!aborting || (workreq->getFlags() & LLQueuedThread::FLAG_ABORT));
  326. }
  327. if (complete)
  328. {
  329. llassert_always(!(getFlags(WCF_WORKING)));
  330. endWork(workreq->getParam(), abort);
  331. mWorkerThread->completeRequest(mRequestHandle);
  332. mRequestHandle = LLWorkerThread::nullHandle();
  333. clearFlags(WCF_HAVE_WORK);
  334. }
  335. }
  336. else
  337. {
  338. complete = true;
  339. }
  340. return complete;
  341. }
  342. void LLWorkerClass::scheduleDelete()
  343. {
  344. bool do_delete = false;
  345. mMutex.lock();
  346. if (!(getFlags(WCF_DELETE_REQUESTED)))
  347. {
  348. setFlags(WCF_DELETE_REQUESTED);
  349. do_delete = true;
  350. }
  351. mMutex.unlock();
  352. if (do_delete)
  353. {
  354. mWorkerThread->deleteWorker(this);
  355. }
  356. }
  357. void LLWorkerClass::setPriority(U32 priority)
  358. {
  359. mMutex.lock();
  360. if (mRequestHandle != LLWorkerThread::nullHandle() && mRequestPriority != priority)
  361. {
  362. mRequestPriority = priority;
  363. mWorkerThread->setPriority(mRequestHandle, priority);
  364. }
  365. mMutex.unlock();
  366. }
  367. //============================================================================