llworkerthread.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /**
  2. * @file llworkerthread.cpp
  3. *
  4. * $LicenseInfo:firstyear=2004&license=viewergpl$
  5. *
  6. * Copyright (c) 2004-2009, Linden Research, Inc.
  7. *
  8. * Second Life Viewer Source Code
  9. * The source code in this file ("Source Code") is provided by Linden Lab
  10. * to you under the terms of the GNU General Public License, version 2.0
  11. * ("GPL"), unless you have obtained a separate licensing agreement
  12. * ("Other License"), formally executed by you and Linden Lab. Terms of
  13. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  14. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  15. *
  16. * There are special exceptions to the terms and conditions of the GPL as
  17. * it is applied to this Source Code. View the full text of the exception
  18. * in the file doc/FLOSS-exception.txt in this software distribution, or
  19. * online at
  20. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  21. *
  22. * By copying, modifying or distributing this software, you acknowledge
  23. * that you have read and understood your obligations described above,
  24. * and agree to abide by those obligations.
  25. *
  26. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  27. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  28. * COMPLETENESS OR PERFORMANCE.
  29. * $/LicenseInfo$
  30. */
  31. #include "linden_common.h"
  32. #include "llworkerthread.h"
  33. #include "llstl.h"
  34. //============================================================================
  35. // Runs on MAIN thread
  36. LLWorkerThread::LLWorkerThread(const std::string& name)
  37. : LLQueuedThread(name)
  38. {
  39. }
  40. LLWorkerThread::~LLWorkerThread()
  41. {
  42. // Delete any workers in the delete queue (should be safe, had better be !)
  43. if (!mDeleteList.empty())
  44. {
  45. llwarns << mName << " destroyed with " << mDeleteList.size()
  46. << " entries in delete list." << llendl;
  47. }
  48. // ~LLQueuedThread() will be called here
  49. }
  50. // Called only in destructor.
  51. void LLWorkerThread::clearDeleteList()
  52. {
  53. // Delete any workers in the delete queue (should be safe; had better be)
  54. if (!mDeleteList.empty())
  55. {
  56. llwarns << mName << " destroyed with " << mDeleteList.size()
  57. << " entries in delete list." << llendl;
  58. mDeleteMutex.lock();
  59. for (delete_list_t::iterator iter = mDeleteList.begin(),
  60. end = mDeleteList.end();
  61. iter != end; ++iter)
  62. {
  63. LLWorkerClass* worker = *iter;
  64. if (worker)
  65. {
  66. worker->mRequestHandle = LLWorkerThread::nullHandle();
  67. worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK |
  68. LLWorkerClass::WCF_WORKING);
  69. delete worker;
  70. }
  71. }
  72. mDeleteList.clear();
  73. mDeleteMutex.unlock();
  74. }
  75. }
  76. //virtual
  77. size_t LLWorkerThread::update()
  78. {
  79. size_t res = LLQueuedThread::update();
  80. // Delete scheduled workers
  81. std::vector<LLWorkerClass*> delete_list, abort_list;
  82. mDeleteMutex.lock();
  83. for (delete_list_t::iterator iter = mDeleteList.begin();
  84. iter != mDeleteList.end(); )
  85. {
  86. delete_list_t::iterator curiter = iter++;
  87. LLWorkerClass* worker = *curiter;
  88. if (worker && worker->deleteOK())
  89. {
  90. if (worker->getFlags(LLWorkerClass::WCF_WORK_FINISHED))
  91. {
  92. worker->setFlags(LLWorkerClass::WCF_DELETE_REQUESTED);
  93. delete_list.push_back(worker);
  94. mDeleteList.erase(curiter);
  95. }
  96. else if (!worker->getFlags(LLWorkerClass::WCF_ABORT_REQUESTED))
  97. {
  98. abort_list.push_back(worker);
  99. }
  100. }
  101. }
  102. mDeleteMutex.unlock();
  103. // Abort and delete after releasing mutex
  104. for (std::vector<LLWorkerClass*>::iterator iter = abort_list.begin();
  105. iter != abort_list.end(); ++iter)
  106. {
  107. (*iter)->abortWork(false);
  108. }
  109. for (std::vector<LLWorkerClass*>::iterator iter = delete_list.begin();
  110. iter != delete_list.end(); ++iter)
  111. {
  112. LLWorkerClass* worker = *iter;
  113. if (worker && worker->mRequestHandle)
  114. {
  115. // Finished but not completed
  116. completeRequest(worker->mRequestHandle);
  117. worker->mRequestHandle = LLWorkerThread::nullHandle();
  118. worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK |
  119. LLWorkerClass::WCF_WORKING);
  120. }
  121. delete *iter;
  122. }
  123. // Deleted and aborted entries mean there is still work to do
  124. return res + delete_list.size() + abort_list.size();
  125. }
  126. LLWorkerThread::handle_t LLWorkerThread::addWorkRequest(LLWorkerClass* workerclass,
  127. S32 param,
  128. U32 priority)
  129. {
  130. handle_t handle = generateHandle();
  131. WorkRequest* req = new WorkRequest(handle, priority, workerclass, param);
  132. if (req)
  133. {
  134. if (!addRequest(req))
  135. {
  136. llwarns << "Failed to add request for " << mName << llendl;
  137. llassert(false);
  138. req->deleteRequest();
  139. handle = nullHandle();
  140. }
  141. }
  142. else
  143. {
  144. llwarns << "Failed to create a new request for " << mName << llendl;
  145. llassert(false);
  146. handle = nullHandle();
  147. }
  148. return handle;
  149. }
  150. void LLWorkerThread::deleteWorker(LLWorkerClass* workerclass)
  151. {
  152. mDeleteMutex.lock();
  153. mDeleteList.push_back(workerclass);
  154. mDeleteMutex.unlock();
  155. }
  156. //============================================================================
  157. // Runs on its OWN thread
  158. LLWorkerThread::WorkRequest::WorkRequest(handle_t handle, U32 priority,
  159. LLWorkerClass* workerclass, S32 param)
  160. : LLQueuedThread::QueuedRequest(handle, priority),
  161. mWorkerClass(workerclass),
  162. mParam(param)
  163. {
  164. }
  165. //virtual (required for access by LLWorkerThread)
  166. void LLWorkerThread::WorkRequest::deleteRequest()
  167. {
  168. LLQueuedThread::QueuedRequest::deleteRequest();
  169. }
  170. //virtual
  171. bool LLWorkerThread::WorkRequest::processRequest()
  172. {
  173. LLWorkerClass* workerclass = getWorkerClass();
  174. if (workerclass)
  175. {
  176. workerclass->setWorking(true);
  177. bool complete = workerclass->doWork(getParam());
  178. workerclass->setWorking(false);
  179. return complete;
  180. }
  181. llwarns << "NULL worker class !" << llendl;
  182. llassert(false);
  183. return true;
  184. }
  185. //virtual
  186. void LLWorkerThread::WorkRequest::finishRequest(bool completed)
  187. {
  188. LLWorkerClass* workerclass = getWorkerClass();
  189. if (workerclass)
  190. {
  191. workerclass->finishWork(getParam(), completed);
  192. U32 flags = LLWorkerClass::WCF_WORK_FINISHED |
  193. (completed ? 0 : LLWorkerClass::WCF_WORK_ABORTED);
  194. workerclass->setFlags(flags);
  195. }
  196. else
  197. {
  198. llwarns << "NULL worker class !" << llendl;
  199. llassert(false);
  200. }
  201. }
  202. //============================================================================
  203. // LLWorkerClass: operates in main thread
  204. LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread,
  205. const std::string& name)
  206. : mWorkerThread(workerthread),
  207. mWorkerClassName(name),
  208. mRequestHandle(LLWorkerThread::nullHandle()),
  209. mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
  210. mWorkFlags(0)
  211. {
  212. if (!mWorkerThread)
  213. {
  214. llerrs << "LLWorkerClass " << name
  215. << " created with NULL worker thread !" << llendl;
  216. }
  217. }
  218. LLWorkerClass::~LLWorkerClass()
  219. {
  220. llassert_always(!(mWorkFlags & WCF_WORKING));
  221. llassert_always(mWorkFlags & WCF_DELETE_REQUESTED);
  222. llassert_always(!mMutex.isLocked());
  223. if (mRequestHandle != LLWorkerThread::nullHandle())
  224. {
  225. LLWorkerThread::WorkRequest* workreq =
  226. (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle);
  227. if (!workreq)
  228. {
  229. llwarns << mWorkerClassName << " destroyed with stale work handle"
  230. << llendl;
  231. llassert(false);
  232. }
  233. else if (workreq->getStatus() != LLWorkerThread::STATUS_ABORTED &&
  234. workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE)
  235. {
  236. llwarns << mWorkerClassName
  237. << " destroyed with active worker ! Worker Status: "
  238. << workreq->getStatus() << llendl;
  239. llassert(false);
  240. }
  241. }
  242. }
  243. // Called from worker thread
  244. void LLWorkerClass::setWorking(bool working)
  245. {
  246. mMutex.lock();
  247. if (working)
  248. {
  249. llassert_always(!(mWorkFlags & WCF_WORKING));
  250. setFlags(WCF_WORKING);
  251. }
  252. else
  253. {
  254. llassert_always((mWorkFlags & WCF_WORKING));
  255. clearFlags(WCF_WORKING);
  256. }
  257. mMutex.unlock();
  258. }
  259. bool LLWorkerClass::yield()
  260. {
  261. LLThread::yield();
  262. mWorkerThread->checkPause();
  263. bool res;
  264. mMutex.lock();
  265. res = (getFlags() & WCF_ABORT_REQUESTED) != 0;
  266. mMutex.unlock();
  267. return res;
  268. }
  269. // Calls startWork, adds doWork() to queue
  270. void LLWorkerClass::addWork(S32 param, U32 priority)
  271. {
  272. mMutex.lock();
  273. llassert_always(!(mWorkFlags & (WCF_WORKING | WCF_HAVE_WORK)));
  274. if (mRequestHandle != LLWorkerThread::nullHandle())
  275. {
  276. llerrs << "Worker class " << mWorkerClassName
  277. << ": attempt to add work with active worker !" << llendl;
  278. }
  279. startWork(param);
  280. clearFlags(WCF_WORK_FINISHED | WCF_WORK_ABORTED);
  281. setFlags(WCF_HAVE_WORK);
  282. mRequestHandle = mWorkerThread->addWorkRequest(this, param, priority);
  283. mMutex.unlock();
  284. }
  285. void LLWorkerClass::abortWork(bool autocomplete)
  286. {
  287. mMutex.lock();
  288. if (mRequestHandle != LLWorkerThread::nullHandle())
  289. {
  290. mWorkerThread->abortRequest(mRequestHandle, autocomplete);
  291. mWorkerThread->setPriority(mRequestHandle,
  292. LLQueuedThread::PRIORITY_IMMEDIATE);
  293. setFlags(WCF_ABORT_REQUESTED);
  294. }
  295. mMutex.unlock();
  296. }
  297. // If doWork is complete or aborted, call endWork() and return true
  298. bool LLWorkerClass::checkWork(bool aborting)
  299. {
  300. mMutex.lock();
  301. bool complete = false;
  302. bool abort = false;
  303. if (mRequestHandle != LLWorkerThread::nullHandle())
  304. {
  305. LLWorkerThread::WorkRequest* workreq =
  306. (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle);
  307. if (!workreq)
  308. {
  309. if (mWorkerThread->isQuitting() || mWorkerThread->isStopped())
  310. {
  311. // The mWorkerThread is not running
  312. mRequestHandle = LLWorkerThread::nullHandle();
  313. clearFlags(WCF_HAVE_WORK | WCF_WORKING);
  314. }
  315. else
  316. {
  317. llassert_always(workreq);
  318. }
  319. mMutex.unlock();
  320. return true;
  321. }
  322. LLQueuedThread::status_t status = workreq->getStatus();
  323. if (status == LLWorkerThread::STATUS_ABORTED)
  324. {
  325. complete = true;
  326. abort = true;
  327. }
  328. else if (status == LLWorkerThread::STATUS_COMPLETE)
  329. {
  330. complete = true;
  331. }
  332. else
  333. {
  334. llassert_always(!aborting ||
  335. (workreq->getFlags() &
  336. LLQueuedThread::FLAG_ABORT));
  337. }
  338. if (complete)
  339. {
  340. llassert_always(!getFlags(WCF_WORKING));
  341. endWork(workreq->getParam(), abort);
  342. mWorkerThread->completeRequest(mRequestHandle);
  343. mRequestHandle = LLWorkerThread::nullHandle();
  344. clearFlags(WCF_HAVE_WORK);
  345. }
  346. }
  347. else
  348. {
  349. complete = true;
  350. }
  351. mMutex.unlock();
  352. return complete;
  353. }
  354. void LLWorkerClass::scheduleDelete()
  355. {
  356. bool do_delete = false;
  357. mMutex.lock();
  358. if (!getFlags(WCF_DELETE_REQUESTED))
  359. {
  360. setFlags(WCF_DELETE_REQUESTED);
  361. do_delete = true;
  362. }
  363. mMutex.unlock();
  364. if (do_delete)
  365. {
  366. mWorkerThread->deleteWorker(this);
  367. }
  368. }
  369. void LLWorkerClass::setPriority(U32 priority)
  370. {
  371. mMutex.lock();
  372. if (mRequestHandle != LLWorkerThread::nullHandle() &&
  373. mRequestPriority != priority)
  374. {
  375. mRequestPriority = priority;
  376. mWorkerThread->setPriority(mRequestHandle, priority);
  377. }
  378. mMutex.unlock();
  379. }