PageRenderTime 35ms CodeModel.GetById 16ms app.highlight 15ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/llcommon/llerrorthread.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 209 lines | 147 code | 17 blank | 45 comment | 27 complexity | 3eb21fc1664da16d2a51529f285d5cfb MD5 | raw file
  1/** 
  2 * @file llerrorthread.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 "llerrorthread.h"
 28
 29#include "llapp.h"
 30#include "lltimer.h"	// ms_sleep()
 31
 32LLErrorThread::LLErrorThread()
 33	: LLThread("Error"),
 34	  mUserDatap(NULL)
 35{
 36}
 37
 38LLErrorThread::~LLErrorThread()
 39{
 40}
 41
 42void LLErrorThread::setUserData(void* user_data)
 43{
 44	mUserDatap = user_data;
 45}
 46
 47
 48void* LLErrorThread::getUserData() const
 49{
 50	return mUserDatap;
 51}
 52
 53#if !LL_WINDOWS
 54//
 55// Various signal/error handling functions that can't be put into the class
 56//
 57void get_child_status(const int waitpid_status, int &process_status, bool &exited, bool do_logging)
 58{
 59	exited = false;
 60	process_status = -1;
 61	// The child process exited.  Call its callback, and then clean it up
 62	if (WIFEXITED(waitpid_status))
 63	{
 64		process_status = WEXITSTATUS(waitpid_status);
 65		exited = true;
 66		if (do_logging)
 67		{
 68			llinfos << "get_child_status - Child exited cleanly with return of " << process_status << llendl;
 69		}
 70		return;
 71	}
 72	else if (WIFSIGNALED(waitpid_status))
 73	{
 74		process_status = WTERMSIG(waitpid_status);
 75		exited = true;
 76		if (do_logging)
 77		{
 78			llinfos << "get_child_status - Child died because of uncaught signal " << process_status << llendl;
 79#ifdef WCOREDUMP
 80			if (WCOREDUMP(waitpid_status))
 81			{
 82				llinfos << "get_child_status - Child dumped core" << llendl;
 83			}
 84			else
 85			{
 86				llinfos << "get_child_status - Child didn't dump core" << llendl;
 87			}
 88#endif
 89		}
 90		return;
 91	}
 92	else if (do_logging)
 93	{
 94		// This is weird.  I just dump the waitpid status into the status code,
 95		// not that there's any way of telling what it is...
 96		llinfos << "get_child_status - Got SIGCHILD but child didn't exit" << llendl;
 97		process_status = waitpid_status;
 98	}
 99
100}
101#endif
102
103void LLErrorThread::run()
104{
105	LLApp::sErrorThreadRunning = TRUE;
106	// This thread sits and waits for the sole purpose
107	// of waiting for the signal/exception handlers to flag the
108	// application state as APP_STATUS_ERROR.
109	llinfos << "thread_error - Waiting for an error" << llendl;
110
111	S32 counter = 0;
112#if !LL_WINDOWS
113	U32 last_sig_child_count = 0;
114#endif
115	while (1)
116	{
117		if (LLApp::isError() || LLApp::isStopped())
118		{
119			// The application has stopped running, time to take action (maybe)
120			break;
121		}
122#if !LL_WINDOWS
123		// Check whether or not the main thread had a sig child we haven't handled.
124		U32 current_sig_child_count = LLApp::getSigChildCount();
125		if (last_sig_child_count != current_sig_child_count)
126		{
127			int status = 0;
128			pid_t child_pid = 0;
129			last_sig_child_count = current_sig_child_count;
130			if (LLApp::sLogInSignal)
131			{
132				llinfos << "thread_error handling SIGCHLD #" << current_sig_child_count << llendl;
133			}
134			for (LLApp::child_map::iterator iter = LLApp::sChildMap.begin(); iter != LLApp::sChildMap.end();)
135			{
136				child_pid = iter->first;
137				LLChildInfo &child_info = iter->second;
138				// check the status of *all* children, in case we missed a signal
139				if (0 != waitpid(child_pid, &status, WNOHANG))
140				{
141					bool exited = false;
142					int exit_status = -1;
143					get_child_status(status, exit_status, exited, LLApp::sLogInSignal);
144
145					if (child_info.mCallback)
146					{
147						if (LLApp::sLogInSignal)
148						{
149							llinfos << "Signal handler - Running child callback" << llendl;
150						}
151						child_info.mCallback(child_pid, exited, status);
152					}
153					LLApp::sChildMap.erase(iter++);
154				}
155				else
156				{
157					// Child didn't terminate, yet we got a sigchild somewhere...
158					if (child_info.mGotSigChild && child_info.mCallback)
159					{
160						child_info.mCallback(child_pid, false, 0);
161					}
162					child_info.mGotSigChild = FALSE;
163					iter++;
164				}
165			}
166
167			// check the status of *all* children, in case we missed a signal
168			// Same as above, but use the default child callback
169			while(0 < (child_pid = waitpid( -1, &status, WNOHANG )))
170			{
171				if (0 != waitpid(child_pid, &status, WNOHANG))
172				{
173					bool exited = false;
174					int exit_status = -1;
175					get_child_status(status, exit_status, exited, LLApp::sLogInSignal);
176					if (LLApp::sDefaultChildCallback)
177					{
178						if (LLApp::sLogInSignal)
179						{
180							llinfos << "Signal handler - Running default child callback" << llendl;
181						}
182						LLApp::sDefaultChildCallback(child_pid, true, status);
183					}
184				}
185			}
186		}
187
188
189#endif
190		ms_sleep(10);
191		counter++;
192	}
193	if (LLApp::isError())
194	{
195		// The app is in an error state, run the application's error handler.
196		//llinfos << "thread_error - An error has occurred, running error callback!" << llendl;
197		// Run the error handling callback
198		LLApp::runErrorHandler();
199	}
200	else
201	{
202		// Everything is okay, a clean exit.
203		//llinfos << "thread_error - Application exited cleanly" << llendl;
204	}
205	
206	//llinfos << "thread_error - Exiting" << llendl;
207	LLApp::sErrorThreadRunning = FALSE;
208}
209