PageRenderTime 65ms CodeModel.GetById 10ms app.highlight 49ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/llcommon/llthread.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 498 lines | 315 code | 82 blank | 101 comment | 35 complexity | 999da7c9182cfdbb6fb201de6d52554b MD5 | raw file
  1/** 
  2 * @file llthread.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
 26#include "linden_common.h"
 27#include "llapr.h"
 28
 29#include "apr_portable.h"
 30
 31#include "llthread.h"
 32
 33#include "lltimer.h"
 34
 35#if LL_LINUX || LL_SOLARIS
 36#include <sched.h>
 37#endif
 38
 39//----------------------------------------------------------------------------
 40// Usage:
 41// void run_func(LLThread* thread)
 42// {
 43// }
 44// LLThread* thread = new LLThread();
 45// thread->run(run_func);
 46// ...
 47// thread->setQuitting();
 48// while(!timeout)
 49// {
 50//   if (thread->isStopped())
 51//   {
 52//     delete thread;
 53//     break;
 54//   }
 55// }
 56// 
 57//----------------------------------------------------------------------------
 58
 59#if !LL_DARWIN
 60U32 ll_thread_local sThreadID = 0;
 61#endif 
 62
 63U32 LLThread::sIDIter = 0;
 64
 65LL_COMMON_API void assert_main_thread()
 66{
 67	static U32 s_thread_id = LLThread::currentID();
 68	if (LLThread::currentID() != s_thread_id)
 69	{
 70		llerrs << "Illegal execution outside main thread." << llendl;
 71	}
 72}
 73
 74//
 75// Handed to the APR thread creation function
 76//
 77void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap)
 78{
 79	LLThread *threadp = (LLThread *)datap;
 80
 81#if !LL_DARWIN
 82	sThreadID = threadp->mID;
 83#endif
 84
 85	// Run the user supplied function
 86	threadp->run();
 87
 88	//llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl;
 89	
 90	// We're done with the run function, this thread is done executing now.
 91	threadp->mStatus = STOPPED;
 92
 93	return NULL;
 94}
 95
 96
 97LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
 98	mPaused(FALSE),
 99	mName(name),
100	mAPRThreadp(NULL),
101	mStatus(STOPPED)
102{
103	mID = ++sIDIter;
104
105	// Thread creation probably CAN be paranoid about APR being initialized, if necessary
106	if (poolp)
107	{
108		mIsLocalPool = FALSE;
109		mAPRPoolp = poolp;
110	}
111	else
112	{
113		mIsLocalPool = TRUE;
114		apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
115	}
116	mRunCondition = new LLCondition(mAPRPoolp);
117
118	mLocalAPRFilePoolp = NULL ;
119}
120
121
122LLThread::~LLThread()
123{
124	shutdown();
125
126	if(mLocalAPRFilePoolp)
127	{
128		delete mLocalAPRFilePoolp ;
129		mLocalAPRFilePoolp = NULL ;
130	}
131}
132
133void LLThread::shutdown()
134{
135	// Warning!  If you somehow call the thread destructor from itself,
136	// the thread will die in an unclean fashion!
137	if (mAPRThreadp)
138	{
139		if (!isStopped())
140		{
141			// The thread isn't already stopped
142			// First, set the flag that indicates that we're ready to die
143			setQuitting();
144
145			//llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl;
146			// Now wait a bit for the thread to exit
147			// It's unclear whether I should even bother doing this - this destructor
148			// should netver get called unless we're already stopped, really...
149			S32 counter = 0;
150			const S32 MAX_WAIT = 600;
151			while (counter < MAX_WAIT)
152			{
153				if (isStopped())
154				{
155					break;
156				}
157				// Sleep for a tenth of a second
158				ms_sleep(100);
159				yield();
160				counter++;
161			}
162		}
163
164		if (!isStopped())
165		{
166			// This thread just wouldn't stop, even though we gave it time
167			//llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl;
168			// Put a stake in its heart.
169			apr_thread_exit(mAPRThreadp, -1);
170			return;
171		}
172		mAPRThreadp = NULL;
173	}
174
175	delete mRunCondition;
176	mRunCondition = 0;
177	
178	if (mIsLocalPool && mAPRPoolp)
179	{
180		apr_pool_destroy(mAPRPoolp);
181		mAPRPoolp = 0;
182	}
183}
184
185
186void LLThread::start()
187{
188	llassert(isStopped());
189	
190	// Set thread state to running
191	mStatus = RUNNING;
192
193	apr_status_t status =
194		apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);
195	
196	if(status == APR_SUCCESS)
197	{	
198		// We won't bother joining
199		apr_thread_detach(mAPRThreadp);
200	}
201	else
202	{
203		mStatus = STOPPED;
204		llwarns << "failed to start thread " << mName << llendl;
205		ll_apr_warn_status(status);
206	}
207}
208
209//============================================================================
210// Called from MAIN THREAD.
211
212// Request that the thread pause/resume.
213// The thread will pause when (and if) it calls checkPause()
214void LLThread::pause()
215{
216	if (!mPaused)
217	{
218		// this will cause the thread to stop execution as soon as checkPause() is called
219		mPaused = 1;		// Does not need to be atomic since this is only set/unset from the main thread
220	}	
221}
222
223void LLThread::unpause()
224{
225	if (mPaused)
226	{
227		mPaused = 0;
228	}
229
230	wake(); // wake up the thread if necessary
231}
232
233// virtual predicate function -- returns true if the thread should wake up, false if it should sleep.
234bool LLThread::runCondition(void)
235{
236	// by default, always run.  Handling of pause/unpause is done regardless of this function's result.
237	return true;
238}
239
240//============================================================================
241// Called from run() (CHILD THREAD).
242// Stop thread execution if requested until unpaused.
243void LLThread::checkPause()
244{
245	mRunCondition->lock();
246
247	// This is in a while loop because the pthread API allows for spurious wakeups.
248	while(shouldSleep())
249	{
250		mRunCondition->wait(); // unlocks mRunCondition
251		// mRunCondition is locked when the thread wakes up
252	}
253	
254 	mRunCondition->unlock();
255}
256
257//============================================================================
258
259void LLThread::setQuitting()
260{
261	mRunCondition->lock();
262	if (mStatus == RUNNING)
263	{
264		mStatus = QUITTING;
265	}
266	mRunCondition->unlock();
267	wake();
268}
269
270// static
271U32 LLThread::currentID()
272{
273	return (U32)apr_os_thread_current();
274}
275
276// static
277void LLThread::yield()
278{
279#if LL_LINUX || LL_SOLARIS
280	sched_yield(); // annoyingly, apr_thread_yield  is a noop on linux...
281#else
282	apr_thread_yield();
283#endif
284}
285
286void LLThread::wake()
287{
288	mRunCondition->lock();
289	if(!shouldSleep())
290	{
291		mRunCondition->signal();
292	}
293	mRunCondition->unlock();
294}
295
296void LLThread::wakeLocked()
297{
298	if(!shouldSleep())
299	{
300		mRunCondition->signal();
301	}
302}
303
304//============================================================================
305
306LLMutex::LLMutex(apr_pool_t *poolp) :
307	mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD)
308{
309	//if (poolp)
310	//{
311	//	mIsLocalPool = FALSE;
312	//	mAPRPoolp = poolp;
313	//}
314	//else
315	{
316		mIsLocalPool = TRUE;
317		apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
318	}
319	apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp);
320}
321
322
323LLMutex::~LLMutex()
324{
325#if MUTEX_DEBUG
326	//bad assertion, the subclass LLSignal might be "locked", and that's OK
327	//llassert_always(!isLocked()); // better not be locked!
328#endif
329	apr_thread_mutex_destroy(mAPRMutexp);
330	mAPRMutexp = NULL;
331	if (mIsLocalPool)
332	{
333		apr_pool_destroy(mAPRPoolp);
334	}
335}
336
337
338void LLMutex::lock()
339{
340	if(isSelfLocked())
341	{ //redundant lock
342		mCount++;
343		return;
344	}
345	
346	apr_thread_mutex_lock(mAPRMutexp);
347	
348#if MUTEX_DEBUG
349	// Have to have the lock before we can access the debug info
350	U32 id = LLThread::currentID();
351	if (mIsLocked[id] != FALSE)
352		llerrs << "Already locked in Thread: " << id << llendl;
353	mIsLocked[id] = TRUE;
354#endif
355
356#if LL_DARWIN
357	mLockingThread = LLThread::currentID();
358#else
359	mLockingThread = sThreadID;
360#endif
361}
362
363void LLMutex::unlock()
364{
365	if (mCount > 0)
366	{ //not the root unlock
367		mCount--;
368		return;
369	}
370	
371#if MUTEX_DEBUG
372	// Access the debug info while we have the lock
373	U32 id = LLThread::currentID();
374	if (mIsLocked[id] != TRUE)
375		llerrs << "Not locked in Thread: " << id << llendl;	
376	mIsLocked[id] = FALSE;
377#endif
378
379	mLockingThread = NO_THREAD;
380	apr_thread_mutex_unlock(mAPRMutexp);
381}
382
383bool LLMutex::isLocked()
384{
385	apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp);
386	if (APR_STATUS_IS_EBUSY(status))
387	{
388		return true;
389	}
390	else
391	{
392		apr_thread_mutex_unlock(mAPRMutexp);
393		return false;
394	}
395}
396
397bool LLMutex::isSelfLocked()
398{
399#if LL_DARWIN
400	return mLockingThread == LLThread::currentID();
401#else
402	return mLockingThread == sThreadID;
403#endif
404}
405
406U32 LLMutex::lockingThread() const
407{
408	return mLockingThread;
409}
410
411//============================================================================
412
413LLCondition::LLCondition(apr_pool_t *poolp) :
414	LLMutex(poolp)
415{
416	// base class (LLMutex) has already ensured that mAPRPoolp is set up.
417
418	apr_thread_cond_create(&mAPRCondp, mAPRPoolp);
419}
420
421
422LLCondition::~LLCondition()
423{
424	apr_thread_cond_destroy(mAPRCondp);
425	mAPRCondp = NULL;
426}
427
428
429void LLCondition::wait()
430{
431	if (!isLocked())
432	{ //mAPRMutexp MUST be locked before calling apr_thread_cond_wait
433		apr_thread_mutex_lock(mAPRMutexp);
434#if MUTEX_DEBUG
435		// avoid asserts on destruction in non-release builds
436		U32 id = LLThread::currentID();
437		mIsLocked[id] = TRUE;
438#endif
439	}
440	apr_thread_cond_wait(mAPRCondp, mAPRMutexp);
441}
442
443void LLCondition::signal()
444{
445	apr_thread_cond_signal(mAPRCondp);
446}
447
448void LLCondition::broadcast()
449{
450	apr_thread_cond_broadcast(mAPRCondp);
451}
452
453//============================================================================
454
455//----------------------------------------------------------------------------
456
457//static
458LLMutex* LLThreadSafeRefCount::sMutex = 0;
459
460//static
461void LLThreadSafeRefCount::initThreadSafeRefCount()
462{
463	if (!sMutex)
464	{
465		sMutex = new LLMutex(0);
466	}
467}
468
469//static
470void LLThreadSafeRefCount::cleanupThreadSafeRefCount()
471{
472	delete sMutex;
473	sMutex = NULL;
474}
475	
476
477//----------------------------------------------------------------------------
478
479LLThreadSafeRefCount::LLThreadSafeRefCount() :
480	mRef(0)
481{
482}
483
484LLThreadSafeRefCount::~LLThreadSafeRefCount()
485{ 
486	if (mRef != 0)
487	{
488		llerrs << "deleting non-zero reference" << llendl;
489	}
490}
491
492//============================================================================
493
494LLResponder::~LLResponder()
495{
496}
497
498//============================================================================