aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon/llworkerthread.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llcommon/llworkerthread.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llcommon/llworkerthread.cpp')
-rw-r--r--linden/indra/llcommon/llworkerthread.cpp303
1 files changed, 303 insertions, 0 deletions
diff --git a/linden/indra/llcommon/llworkerthread.cpp b/linden/indra/llcommon/llworkerthread.cpp
new file mode 100644
index 0000000..3190046
--- /dev/null
+++ b/linden/indra/llcommon/llworkerthread.cpp
@@ -0,0 +1,303 @@
1/**
2 * @file llworkerthread.cpp
3 *
4 * Copyright (c) 2004-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#include "linden_common.h"
28#include "llworkerthread.h"
29#include "llstl.h"
30
31#if USE_FRAME_CALLBACK_MANAGER
32#include "llframecallbackmanager.h"
33#endif
34
35//============================================================================
36
37/*static*/ LLWorkerThread* LLWorkerThread::sLocal = NULL;
38/*static*/ std::set<LLWorkerThread*> LLWorkerThread::sThreadList;
39
40//============================================================================
41// Run on MAIN thread
42
43//static
44void LLWorkerThread::initClass(bool local_is_threaded, bool local_run_always)
45{
46 if (!sLocal)
47 {
48 sLocal = new LLWorkerThread(local_is_threaded, local_run_always);
49 }
50}
51
52//static
53void LLWorkerThread::cleanupClass()
54{
55 if (sLocal)
56 {
57 while (sLocal->getPending())
58 {
59 sLocal->update(0);
60 }
61 delete sLocal;
62 sLocal = NULL;
63 llassert(sThreadList.size() == 0);
64 }
65}
66
67//static
68S32 LLWorkerThread::updateClass(U32 ms_elapsed)
69{
70 for (std::set<LLWorkerThread*>::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++)
71 {
72 (*iter)->update(ms_elapsed);
73 }
74 return getAllPending();
75}
76
77//static
78S32 LLWorkerThread::getAllPending()
79{
80 S32 res = 0;
81 for (std::set<LLWorkerThread*>::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++)
82 {
83 res += (*iter)->getPending();
84 }
85 return res;
86}
87
88//static
89void LLWorkerThread::pauseAll()
90{
91 for (std::set<LLWorkerThread*>::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++)
92 {
93 (*iter)->pause();
94 }
95}
96
97//static
98void LLWorkerThread::waitOnAllPending()
99{
100 for (std::set<LLWorkerThread*>::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++)
101 {
102 (*iter)->waitOnPending();
103 }
104}
105
106//----------------------------------------------------------------------------
107
108LLWorkerThread::LLWorkerThread(bool threaded, bool runalways) :
109 LLQueuedThread("Worker", threaded, runalways)
110{
111 sThreadList.insert(this);
112}
113
114LLWorkerThread::~LLWorkerThread()
115{
116 llverify(sThreadList.erase(this) == 1);
117 // ~LLQueuedThread() will be called here
118}
119
120//----------------------------------------------------------------------------
121
122
123LLWorkerThread::handle_t LLWorkerThread::add(LLWorkerClass* workerclass, S32 param, U32 priority)
124{
125 handle_t handle = generateHandle();
126
127 Request* req = new Request(handle, priority, workerclass, param);
128
129 bool res = addRequest(req);
130 if (!res)
131 {
132 llerrs << "add called after LLWorkerThread::cleanupClass()" << llendl;
133 req->deleteRequest();
134 handle = nullHandle();
135 }
136
137 return handle;
138}
139
140//============================================================================
141// Runs on its OWN thread
142
143bool LLWorkerThread::processRequest(QueuedRequest* qreq)
144{
145 Request *req = (Request*)qreq;
146
147 req->getWorkerClass()->setWorking(true);
148
149 bool complete = req->getWorkerClass()->doWork(req->getParam());
150
151 req->getWorkerClass()->setWorking(false);
152
153 LLThread::yield(); // worker thread should yield after each request
154
155 return complete;
156}
157
158//============================================================================
159
160LLWorkerThread::Request::Request(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param) :
161 LLQueuedThread::QueuedRequest(handle, priority),
162 mWorkerClass(workerclass),
163 mParam(param)
164{
165}
166
167void LLWorkerThread::Request::deleteRequest()
168{
169 LLQueuedThread::QueuedRequest::deleteRequest();
170}
171
172//============================================================================
173// LLWorkerClass:: operates in main thread
174
175LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& name)
176 : mWorkerThread(workerthread),
177 mWorkerClassName(name),
178 mWorkHandle(LLWorkerThread::nullHandle()),
179 mWorkFlags(0)
180{
181 if (!mWorkerThread)
182 {
183 mWorkerThread = LLWorkerThread::sLocal;
184 }
185}
186LLWorkerClass::~LLWorkerClass()
187{
188 if (mWorkHandle != LLWorkerThread::nullHandle())
189 {
190 LLWorkerThread::Request* workreq = (LLWorkerThread::Request*)mWorkerThread->getRequest(mWorkHandle);
191 if (!workreq)
192 {
193 llerrs << "LLWorkerClass destroyed with stale work handle" << llendl;
194 }
195 if (workreq->getStatus() != LLWorkerThread::STATUS_ABORT &&
196 workreq->getStatus() != LLWorkerThread::STATUS_ABORTED &&
197 workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE)
198 {
199 llerrs << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << llendl;
200 }
201 }
202}
203
204void LLWorkerClass::setWorkerThread(LLWorkerThread* workerthread)
205{
206 if (mWorkHandle != LLWorkerThread::nullHandle())
207 {
208 llerrs << "LLWorkerClass attempt to change WorkerThread with active worker!" << llendl;
209 }
210 mWorkerThread = workerthread;
211}
212
213//----------------------------------------------------------------------------
214
215bool LLWorkerClass::yield()
216{
217 llassert(mWorkFlags & WCF_WORKING);
218 LLThread::yield();
219 mWorkerThread->checkPause();
220 return (getFlags() & WCF_ABORT_REQUESTED) ? true : false;
221}
222
223//----------------------------------------------------------------------------
224
225// calls startWork, adds doWork() to queue
226void LLWorkerClass::addWork(S32 param, U32 priority)
227{
228 if (mWorkHandle != LLWorkerThread::nullHandle())
229 {
230 llerrs << "LLWorkerClass attempt to add work with active worker!" << llendl;
231 }
232#if _DEBUG
233// llinfos << "addWork: " << mWorkerClassName << " Param: " << param << llendl;
234#endif
235 startWork(param);
236 mWorkHandle = mWorkerThread->add(this, param, priority);
237}
238
239void LLWorkerClass::abortWork()
240{
241#if _DEBUG
242// LLWorkerThread::Request* workreq = mWorkerThread->getRequest(mWorkHandle);
243// if (workreq)
244// llinfos << "abortWork: " << mWorkerClassName << " Param: " << workreq->getParam() << llendl;
245#endif
246 mWorkerThread->abortRequest(mWorkHandle);
247 setFlags(WCF_ABORT_REQUESTED);
248}
249
250// if doWork is complete or aborted, call endWork() and return true
251bool LLWorkerClass::checkWork()
252{
253 bool complete = false, abort = false;
254 LLWorkerThread::Request* workreq = (LLWorkerThread::Request*)mWorkerThread->getRequest(mWorkHandle);
255 llassert(workreq);
256 if (getFlags(WCF_ABORT_REQUESTED) || workreq->getStatus() == LLWorkerThread::STATUS_ABORTED)
257 {
258 complete = true;
259 abort = true;
260 }
261 else if (workreq->getStatus() == LLWorkerThread::STATUS_COMPLETE)
262 {
263 complete = true;
264 }
265 if (complete)
266 {
267#if _DEBUG
268// llinfos << "endWork: " << mWorkerClassName << " Param: " << workreq->getParam() << llendl;
269#endif
270 endWork(workreq->getParam(), abort);
271 mWorkerThread->completeRequest(mWorkHandle);
272 mWorkHandle = LLWorkerThread::nullHandle();
273 }
274 return complete;
275}
276
277void LLWorkerClass::killWork()
278{
279 if (haveWork())
280 {
281 abortWork();
282 bool paused = mWorkerThread->isPaused();
283 while (!checkWork())
284 {
285 mWorkerThread->updateQueue(0);
286 }
287 if (paused)
288 {
289 mWorkerThread->pause();
290 }
291 }
292}
293
294void LLWorkerClass::setPriority(U32 priority)
295{
296 if (haveWork())
297 {
298 mWorkerThread->setPriority(mWorkHandle, priority);
299 }
300}
301
302//============================================================================
303