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