diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llcommon/llthread.cpp | |
parent | README.txt (diff) | |
download | meta-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 '')
-rw-r--r-- | linden/indra/llcommon/llthread.cpp | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/linden/indra/llcommon/llthread.cpp b/linden/indra/llcommon/llthread.cpp new file mode 100644 index 0000000..290879d --- /dev/null +++ b/linden/indra/llcommon/llthread.cpp | |||
@@ -0,0 +1,349 @@ | |||
1 | /** | ||
2 | * @file llthread.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 "llapr.h" | ||
29 | |||
30 | #include "llthread.h" | ||
31 | |||
32 | #include "lltimer.h" | ||
33 | |||
34 | #if LL_LINUX | ||
35 | #include <sched.h> | ||
36 | #endif | ||
37 | |||
38 | //---------------------------------------------------------------------------- | ||
39 | // Usage: | ||
40 | // void run_func(LLThread* thread) | ||
41 | // { | ||
42 | // } | ||
43 | // LLThread* thread = new LLThread(); | ||
44 | // thread->run(run_func); | ||
45 | // ... | ||
46 | // thread->setQuitting(); | ||
47 | // while(!timeout) | ||
48 | // { | ||
49 | // if (thread->isStopped()) | ||
50 | // { | ||
51 | // delete thread; | ||
52 | // break; | ||
53 | // } | ||
54 | // } | ||
55 | // | ||
56 | //---------------------------------------------------------------------------- | ||
57 | |||
58 | // | ||
59 | // Handed to the APR thread creation function | ||
60 | // | ||
61 | void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap) | ||
62 | { | ||
63 | LLThread *threadp = (LLThread *)datap; | ||
64 | |||
65 | // Set thread state to running | ||
66 | threadp->mStatus = RUNNING; | ||
67 | |||
68 | // Run the user supplied function | ||
69 | threadp->run(); | ||
70 | |||
71 | llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl; | ||
72 | |||
73 | // We're done with the run function, this thread is done executing now. | ||
74 | threadp->mStatus = STOPPED; | ||
75 | |||
76 | return NULL; | ||
77 | } | ||
78 | |||
79 | |||
80 | LLThread::LLThread(const std::string& name, apr_pool_t *poolp) : | ||
81 | mPaused(FALSE), | ||
82 | mName(name), | ||
83 | mAPRThreadp(NULL), | ||
84 | mStatus(STOPPED) | ||
85 | { | ||
86 | // Thread creation probably CAN be paranoid about APR being initialized, if necessary | ||
87 | if (poolp) | ||
88 | { | ||
89 | mIsLocalPool = FALSE; | ||
90 | mAPRPoolp = poolp; | ||
91 | } | ||
92 | else | ||
93 | { | ||
94 | mIsLocalPool = TRUE; | ||
95 | apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread | ||
96 | } | ||
97 | mRunCondition = new LLCondition(mAPRPoolp); | ||
98 | } | ||
99 | |||
100 | |||
101 | LLThread::~LLThread() | ||
102 | { | ||
103 | // Warning! If you somehow call the thread destructor from itself, | ||
104 | // the thread will die in an unclean fashion! | ||
105 | if (mAPRThreadp) | ||
106 | { | ||
107 | if (!isStopped()) | ||
108 | { | ||
109 | // The thread isn't already stopped | ||
110 | // First, set the flag that indicates that we're ready to die | ||
111 | setQuitting(); | ||
112 | |||
113 | llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl; | ||
114 | // Now wait a bit for the thread to exit | ||
115 | // It's unclear whether I should even bother doing this - this destructor | ||
116 | // should netver get called unless we're already stopped, really... | ||
117 | S32 counter = 0; | ||
118 | const S32 MAX_WAIT = 600; | ||
119 | while (counter < MAX_WAIT) | ||
120 | { | ||
121 | if (isStopped()) | ||
122 | { | ||
123 | break; | ||
124 | } | ||
125 | // Sleep for a tenth of a second | ||
126 | ms_sleep(100); | ||
127 | yield(); | ||
128 | counter++; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | if (!isStopped()) | ||
133 | { | ||
134 | // This thread just wouldn't stop, even though we gave it time | ||
135 | llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl; | ||
136 | return; | ||
137 | } | ||
138 | mAPRThreadp = NULL; | ||
139 | } | ||
140 | |||
141 | delete mRunCondition; | ||
142 | |||
143 | if (mIsLocalPool) | ||
144 | { | ||
145 | apr_pool_destroy(mAPRPoolp); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | |||
150 | void LLThread::start() | ||
151 | { | ||
152 | apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp); | ||
153 | |||
154 | // We won't bother joining | ||
155 | apr_thread_detach(mAPRThreadp); | ||
156 | } | ||
157 | |||
158 | //============================================================================ | ||
159 | // Called from MAIN THREAD. | ||
160 | |||
161 | // Request that the thread pause/resume. | ||
162 | // The thread will pause when (and if) it calls checkPause() | ||
163 | void LLThread::pause() | ||
164 | { | ||
165 | if (!mPaused) | ||
166 | { | ||
167 | // this will cause the thread to stop execution as soon as checkPause() is called | ||
168 | mPaused = 1; // Does not need to be atomic since this is only set/unset from the main thread | ||
169 | } | ||
170 | } | ||
171 | |||
172 | void LLThread::unpause() | ||
173 | { | ||
174 | if (mPaused) | ||
175 | { | ||
176 | mPaused = 0; | ||
177 | } | ||
178 | |||
179 | wake(); // wake up the thread if necessary | ||
180 | } | ||
181 | |||
182 | // virtual predicate function -- returns true if the thread should wake up, false if it should sleep. | ||
183 | bool LLThread::runCondition(void) | ||
184 | { | ||
185 | // by default, always run. Handling of pause/unpause is done regardless of this function's result. | ||
186 | return true; | ||
187 | } | ||
188 | |||
189 | //============================================================================ | ||
190 | // Called from run() (CHILD THREAD). | ||
191 | // Stop thread execution if requested until unpaused. | ||
192 | void LLThread::checkPause() | ||
193 | { | ||
194 | mRunCondition->lock(); | ||
195 | |||
196 | // This is in a while loop because the pthread API allows for spurious wakeups. | ||
197 | while(shouldSleep()) | ||
198 | { | ||
199 | mRunCondition->wait(); // unlocks mRunCondition | ||
200 | // mRunCondition is locked when the thread wakes up | ||
201 | } | ||
202 | |||
203 | mRunCondition->unlock(); | ||
204 | } | ||
205 | |||
206 | //============================================================================ | ||
207 | |||
208 | bool LLThread::isQuitting() const | ||
209 | { | ||
210 | return (QUITTING == mStatus); | ||
211 | } | ||
212 | |||
213 | |||
214 | bool LLThread::isStopped() const | ||
215 | { | ||
216 | return (STOPPED == mStatus); | ||
217 | } | ||
218 | |||
219 | |||
220 | void LLThread::setQuitting() | ||
221 | { | ||
222 | mRunCondition->lock(); | ||
223 | if (mStatus == RUNNING) | ||
224 | { | ||
225 | mStatus = QUITTING; | ||
226 | } | ||
227 | mRunCondition->unlock(); | ||
228 | wake(); | ||
229 | } | ||
230 | |||
231 | |||
232 | // static | ||
233 | void LLThread::yield() | ||
234 | { | ||
235 | #if LL_LINUX | ||
236 | sched_yield(); // annoyingly, apr_thread_yield is a noop on linux... | ||
237 | #else | ||
238 | apr_thread_yield(); | ||
239 | #endif | ||
240 | } | ||
241 | |||
242 | void LLThread::wake() | ||
243 | { | ||
244 | mRunCondition->lock(); | ||
245 | if(!shouldSleep()) | ||
246 | { | ||
247 | mRunCondition->signal(); | ||
248 | } | ||
249 | mRunCondition->unlock(); | ||
250 | } | ||
251 | |||
252 | void LLThread::wakeLocked() | ||
253 | { | ||
254 | if(!shouldSleep()) | ||
255 | { | ||
256 | mRunCondition->signal(); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | //============================================================================ | ||
261 | |||
262 | LLMutex::LLMutex(apr_pool_t *poolp) : | ||
263 | mAPRMutexp(NULL) | ||
264 | { | ||
265 | if (poolp) | ||
266 | { | ||
267 | mIsLocalPool = FALSE; | ||
268 | mAPRPoolp = poolp; | ||
269 | } | ||
270 | else | ||
271 | { | ||
272 | mIsLocalPool = TRUE; | ||
273 | apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread | ||
274 | } | ||
275 | apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_DEFAULT, mAPRPoolp); | ||
276 | } | ||
277 | |||
278 | |||
279 | LLMutex::~LLMutex() | ||
280 | { | ||
281 | #if _DEBUG | ||
282 | llassert(!isLocked()); // better not be locked! | ||
283 | #endif | ||
284 | apr_thread_mutex_destroy(mAPRMutexp); | ||
285 | mAPRMutexp = NULL; | ||
286 | if (mIsLocalPool) | ||
287 | { | ||
288 | apr_pool_destroy(mAPRPoolp); | ||
289 | } | ||
290 | } | ||
291 | |||
292 | |||
293 | void LLMutex::lock() | ||
294 | { | ||
295 | apr_thread_mutex_lock(mAPRMutexp); | ||
296 | } | ||
297 | |||
298 | void LLMutex::unlock() | ||
299 | { | ||
300 | apr_thread_mutex_unlock(mAPRMutexp); | ||
301 | } | ||
302 | |||
303 | bool LLMutex::isLocked() | ||
304 | { | ||
305 | apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp); | ||
306 | if (APR_STATUS_IS_EBUSY(status)) | ||
307 | { | ||
308 | return true; | ||
309 | } | ||
310 | else | ||
311 | { | ||
312 | apr_thread_mutex_unlock(mAPRMutexp); | ||
313 | return false; | ||
314 | } | ||
315 | } | ||
316 | |||
317 | //============================================================================ | ||
318 | |||
319 | LLCondition::LLCondition(apr_pool_t *poolp) : | ||
320 | LLMutex(poolp) | ||
321 | { | ||
322 | // base class (LLMutex) has already ensured that mAPRPoolp is set up. | ||
323 | |||
324 | apr_thread_cond_create(&mAPRCondp, mAPRPoolp); | ||
325 | } | ||
326 | |||
327 | |||
328 | LLCondition::~LLCondition() | ||
329 | { | ||
330 | apr_thread_cond_destroy(mAPRCondp); | ||
331 | mAPRCondp = NULL; | ||
332 | } | ||
333 | |||
334 | |||
335 | void LLCondition::wait() | ||
336 | { | ||
337 | apr_thread_cond_wait(mAPRCondp, mAPRMutexp); | ||
338 | } | ||
339 | |||
340 | void LLCondition::signal() | ||
341 | { | ||
342 | apr_thread_cond_signal(mAPRCondp); | ||
343 | } | ||
344 | |||
345 | void LLCondition::broadcast() | ||
346 | { | ||
347 | apr_thread_cond_broadcast(mAPRCondp); | ||
348 | } | ||
349 | |||