PageRenderTime 71ms CodeModel.GetById 20ms app.highlight 19ms RepoModel.GetById 11ms app.codeStats 0ms

/indra/newview/llwatchdog.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 269 lines | 191 code | 40 blank | 38 comment | 14 complexity | 4cae86df3da722949bf385c827c17f50 MD5 | raw file
  1/** 
  2 * @file llthreadwatchdog.cpp
  3 * @brief The LLThreadWatchdog class definitions
  4 *
  5 * $LicenseInfo:firstyear=2007&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27
 28#include "llviewerprecompiledheaders.h"
 29#include "llwatchdog.h"
 30
 31const U32 WATCHDOG_SLEEP_TIME_USEC = 1000000;
 32
 33void default_killer_callback()
 34{
 35#ifdef LL_WINDOWS
 36	RaiseException(0,0,0,0);
 37#else
 38	raise(SIGQUIT);
 39#endif
 40}
 41
 42// This class runs the watchdog timing thread.
 43class LLWatchdogTimerThread : public LLThread
 44{
 45public:
 46	LLWatchdogTimerThread() : 
 47		LLThread("Watchdog"),
 48		mSleepMsecs(0),
 49		mStopping(false)
 50	{
 51	}
 52            
 53	~LLWatchdogTimerThread() {}
 54    
 55	void setSleepTime(long ms) { mSleepMsecs = ms; }
 56	void stop() 
 57	{
 58		mStopping = true; 
 59		mSleepMsecs = 1;
 60	}
 61    
 62	/* virtual */ void run()
 63	{
 64		while(!mStopping)
 65		{
 66			LLWatchdog::getInstance()->run();
 67			ms_sleep(mSleepMsecs);
 68		}
 69	}
 70
 71private:
 72	long mSleepMsecs;
 73	bool mStopping;
 74};
 75
 76// LLWatchdogEntry
 77LLWatchdogEntry::LLWatchdogEntry()
 78{
 79}
 80
 81LLWatchdogEntry::~LLWatchdogEntry()
 82{
 83	stop();
 84}
 85
 86void LLWatchdogEntry::start()
 87{
 88	LLWatchdog::getInstance()->add(this);
 89}
 90
 91void LLWatchdogEntry::stop()
 92{
 93	LLWatchdog::getInstance()->remove(this);
 94}
 95
 96// LLWatchdogTimeout
 97const std::string UNINIT_STRING = "uninitialized";
 98
 99LLWatchdogTimeout::LLWatchdogTimeout() : 
100	mTimeout(0.0f),
101	mPingState(UNINIT_STRING)
102{
103}
104
105LLWatchdogTimeout::~LLWatchdogTimeout() 
106{
107}
108
109bool LLWatchdogTimeout::isAlive() const 
110{ 
111	return (mTimer.getStarted() && !mTimer.hasExpired()); 
112}
113
114void LLWatchdogTimeout::reset()
115{
116	mTimer.setTimerExpirySec(mTimeout); 
117}
118
119void LLWatchdogTimeout::setTimeout(F32 d) 
120{
121	mTimeout = d;
122}
123
124void LLWatchdogTimeout::start(const std::string& state) 
125{
126	// Order of operation is very impmortant here.
127	// After LLWatchdogEntry::start() is called
128	// LLWatchdogTimeout::isAlive() will be called asynchronously. 
129	ping(state);
130	mTimer.start(); 
131	LLWatchdogEntry::start();
132}
133
134void LLWatchdogTimeout::stop() 
135{
136	LLWatchdogEntry::stop();
137	mTimer.stop();
138}
139
140void LLWatchdogTimeout::ping(const std::string& state) 
141{ 
142	if(!state.empty())
143	{
144		mPingState = state;
145	}
146	reset();
147}
148
149// LLWatchdog
150LLWatchdog::LLWatchdog() :
151	mSuspectsAccessMutex(NULL),
152	mTimer(NULL),
153	mLastClockCount(0),
154	mKillerCallback(&default_killer_callback)
155{
156}
157
158LLWatchdog::~LLWatchdog()
159{
160}
161
162void LLWatchdog::add(LLWatchdogEntry* e)
163{
164	lockThread();
165	mSuspects.insert(e);
166	unlockThread();
167}
168
169void LLWatchdog::remove(LLWatchdogEntry* e)
170{
171	lockThread();
172    mSuspects.erase(e);
173	unlockThread();
174}
175
176void LLWatchdog::init(killer_event_callback func)
177{
178	mKillerCallback = func;
179	if(!mSuspectsAccessMutex && !mTimer)
180	{
181		mSuspectsAccessMutex = new LLMutex(NULL);
182		mTimer = new LLWatchdogTimerThread();
183		mTimer->setSleepTime(WATCHDOG_SLEEP_TIME_USEC / 1000);
184		mLastClockCount = LLTimer::getTotalTime();
185
186		// mTimer->start() kicks off the thread, any code after
187		// start needs to use the mSuspectsAccessMutex
188		mTimer->start();
189	}
190}
191
192void LLWatchdog::cleanup()
193{
194	if(mTimer)
195	{
196		mTimer->stop();
197		delete mTimer;
198		mTimer = NULL;
199	}
200
201	if(mSuspectsAccessMutex)
202	{
203		delete mSuspectsAccessMutex;
204		mSuspectsAccessMutex = NULL;
205	}
206
207	mLastClockCount = 0;
208}
209
210void LLWatchdog::run()
211{
212	lockThread();
213
214	// Check the time since the last call to run...
215	// If the time elapsed is two times greater than the regualr sleep time
216	// reset the active timeouts.
217	const U32 TIME_ELAPSED_MULTIPLIER = 2;
218	U64 current_time = LLTimer::getTotalTime();
219	U64 current_run_delta = current_time - mLastClockCount;
220	mLastClockCount = current_time;
221	
222	if(current_run_delta > (WATCHDOG_SLEEP_TIME_USEC * TIME_ELAPSED_MULTIPLIER))
223	{
224		llinfos << "Watchdog thread delayed: resetting entries." << llendl;
225		std::for_each(mSuspects.begin(), 
226			mSuspects.end(), 
227			std::mem_fun(&LLWatchdogEntry::reset)
228			);
229	}
230	else
231	{
232		SuspectsRegistry::iterator result = 
233			std::find_if(mSuspects.begin(), 
234				mSuspects.end(), 
235				std::not1(std::mem_fun(&LLWatchdogEntry::isAlive))
236				);
237
238		if(result != mSuspects.end())
239		{
240			// error!!!
241			if(mTimer)
242			{
243				mTimer->stop();
244			}
245
246			llinfos << "Watchdog detected error:" << llendl;
247			mKillerCallback();
248		}
249	}
250
251
252	unlockThread();
253}
254
255void LLWatchdog::lockThread()
256{
257	if(mSuspectsAccessMutex != NULL)
258	{
259		mSuspectsAccessMutex->lock();
260	}
261}
262
263void LLWatchdog::unlockThread()
264{
265	if(mSuspectsAccessMutex != NULL)
266	{
267		mSuspectsAccessMutex->unlock();
268	}
269}