aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon/llthread.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/llthread.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 '')
-rw-r--r--linden/indra/llcommon/llthread.cpp349
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//
61void *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
80LLThread::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
101LLThread::~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
150void 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()
163void 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
172void 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.
183bool 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.
192void 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
208bool LLThread::isQuitting() const
209{
210 return (QUITTING == mStatus);
211}
212
213
214bool LLThread::isStopped() const
215{
216 return (STOPPED == mStatus);
217}
218
219
220void 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
233void 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
242void LLThread::wake()
243{
244 mRunCondition->lock();
245 if(!shouldSleep())
246 {
247 mRunCondition->signal();
248 }
249 mRunCondition->unlock();
250}
251
252void LLThread::wakeLocked()
253{
254 if(!shouldSleep())
255 {
256 mRunCondition->signal();
257 }
258}
259
260//============================================================================
261
262LLMutex::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
279LLMutex::~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
293void LLMutex::lock()
294{
295 apr_thread_mutex_lock(mAPRMutexp);
296}
297
298void LLMutex::unlock()
299{
300 apr_thread_mutex_unlock(mAPRMutexp);
301}
302
303bool 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
319LLCondition::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
328LLCondition::~LLCondition()
329{
330 apr_thread_cond_destroy(mAPRCondp);
331 mAPRCondp = NULL;
332}
333
334
335void LLCondition::wait()
336{
337 apr_thread_cond_wait(mAPRCondp, mAPRMutexp);
338}
339
340void LLCondition::signal()
341{
342 apr_thread_cond_signal(mAPRCondp);
343}
344
345void LLCondition::broadcast()
346{
347 apr_thread_cond_broadcast(mAPRCondp);
348}
349