slplugin.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:9k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /**
  2.  * @file slplugin.cpp
  3.  * @brief Loader shell for plugins, intended to be launched by the plugin host application, which directly loads a plugin dynamic library.
  4.  *
  5.  * @cond
  6.  *
  7.  * $LicenseInfo:firstyear=2008&license=viewergpl$
  8.  * 
  9.  * Copyright (c) 2008-2010, Linden Research, Inc.
  10.  * 
  11.  * Second Life Viewer Source Code
  12.  * The source code in this file ("Source Code") is provided by Linden Lab
  13.  * to you under the terms of the GNU General Public License, version 2.0
  14.  * ("GPL"), unless you have obtained a separate licensing agreement
  15.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  16.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  17.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  18.  * 
  19.  * There are special exceptions to the terms and conditions of the GPL as
  20.  * it is applied to this Source Code. View the full text of the exception
  21.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  22.  * online at
  23.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  24.  * 
  25.  * By copying, modifying or distributing this software, you acknowledge
  26.  * that you have read and understood your obligations described above,
  27.  * and agree to abide by those obligations.
  28.  * 
  29.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  30.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  31.  * COMPLETENESS OR PERFORMANCE.
  32.  * $/LicenseInfo$
  33.  *
  34.  * @endcond
  35.  */
  36. #include "linden_common.h"
  37. #include "llpluginprocesschild.h"
  38. #include "llpluginmessage.h"
  39. #include "llerrorcontrol.h"
  40. #include "llapr.h"
  41. #include "llstring.h"
  42. #if LL_DARWIN
  43. #include <Carbon/Carbon.h>
  44. #endif
  45. #if LL_DARWIN || LL_LINUX
  46. #include <signal.h>
  47. #endif
  48. /*
  49. On Mac OS, since we call WaitNextEvent, this process will show up in the dock unless we set the LSBackgroundOnly flag in the Info.plist.
  50. Normally non-bundled binaries don't have an info.plist file, but it's possible to embed one in the binary by adding this to the linker flags:
  51. -sectcreate __TEXT __info_plist /path/to/slplugin_info.plist
  52. which means adding this to the gcc flags:
  53. -Wl,-sectcreate,__TEXT,__info_plist,/path/to/slplugin_info.plist
  54. */
  55. #if LL_DARWIN || LL_LINUX
  56. // Signal handlers to make crashes not show an OS dialog...
  57. static void crash_handler(int sig)
  58. {
  59. // Just exit cleanly.
  60. // TODO: add our own crash reporting
  61. _exit(1);
  62. }
  63. #endif
  64. #if LL_WINDOWS
  65. #include <windows.h>
  66. ////////////////////////////////////////////////////////////////////////////////
  67. // Our exception handler - will probably just exit and the host application
  68. // will miss the heartbeat and log the error in the usual fashion.
  69. LONG WINAPI myWin32ExceptionHandler( struct _EXCEPTION_POINTERS* exception_infop )
  70. {
  71. //std::cerr << "This plugin (" << __FILE__ << ") - ";
  72. //std::cerr << "intercepted an unhandled exception and will exit immediately." << std::endl;
  73. // TODO: replace exception handler before we exit?
  74. return EXCEPTION_EXECUTE_HANDLER;
  75. }
  76. // Taken from : http://blog.kalmbachnet.de/?postid=75
  77. // The MSVC 2005 CRT forces the call of the default-debugger (normally Dr.Watson)
  78. // even with the other exception handling code. This (terrifying) piece of code
  79. // patches things so that doesn't happen.
  80. LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(
  81. LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter )
  82. {
  83. return NULL;
  84. }
  85. BOOL PreventSetUnhandledExceptionFilter()
  86. {
  87. // WARNING: This won't work on 64-bit Windows systems so we turn it off it.
  88. //          It should work for any flavor of 32-bit Windows we care about.
  89. //          If it's off, sometimes you will see an OS message when a plugin crashes
  90. #ifndef _WIN64
  91. HMODULE hKernel32 = LoadLibraryA( "kernel32.dll" );
  92. if ( NULL == hKernel32 )
  93. return FALSE;
  94. void *pOrgEntry = GetProcAddress( hKernel32, "SetUnhandledExceptionFilter" );
  95. if( NULL == pOrgEntry )
  96. return FALSE;
  97. unsigned char newJump[ 100 ];
  98. DWORD dwOrgEntryAddr = (DWORD)pOrgEntry;
  99. dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far
  100. void *pNewFunc = &MyDummySetUnhandledExceptionFilter;
  101. DWORD dwNewEntryAddr = (DWORD) pNewFunc;
  102. DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;
  103. newJump[ 0 ] = 0xE9;  // JMP absolute
  104. memcpy( &newJump[ 1 ], &dwRelativeAddr, sizeof( pNewFunc ) );
  105. SIZE_T bytesWritten;
  106. BOOL bRet = WriteProcessMemory( GetCurrentProcess(), pOrgEntry, newJump, sizeof( pNewFunc ) + 1, &bytesWritten );
  107. return bRet;
  108. #else
  109. return FALSE;
  110. #endif
  111. }
  112. ////////////////////////////////////////////////////////////////////////////////
  113. // Hook our exception handler and replace the system one
  114. void initExceptionHandler()
  115. {
  116. LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
  117. // save old exception handler in case we need to restore it at the end
  118. prev_filter = SetUnhandledExceptionFilter( myWin32ExceptionHandler );
  119. PreventSetUnhandledExceptionFilter();
  120. }
  121. bool checkExceptionHandler()
  122. {
  123. bool ok = true;
  124. LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
  125. prev_filter = SetUnhandledExceptionFilter(myWin32ExceptionHandler);
  126. PreventSetUnhandledExceptionFilter();
  127. if (prev_filter != myWin32ExceptionHandler)
  128. {
  129. LL_WARNS("AppInit") << "Our exception handler (" << (void *)myWin32ExceptionHandler << ") replaced with " << prev_filter << "!" << LL_ENDL;
  130. ok = false;
  131. }
  132. if (prev_filter == NULL)
  133. {
  134. ok = FALSE;
  135. if (NULL == myWin32ExceptionHandler)
  136. {
  137. LL_WARNS("AppInit") << "Exception handler uninitialized." << LL_ENDL;
  138. }
  139. else
  140. {
  141. LL_WARNS("AppInit") << "Our exception handler (" << (void *)myWin32ExceptionHandler << ") replaced with NULL!" << LL_ENDL;
  142. }
  143. }
  144. return ok;
  145. }
  146. #endif
  147. // If this application on Windows platform is a console application, a console is always
  148. // created which is bad. Making it a Windows "application" via CMake settings but not
  149. // adding any code to explicitly create windows does the right thing.
  150. #if LL_WINDOWS
  151. int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
  152. #else
  153. int main(int argc, char **argv)
  154. #endif
  155. {
  156. ll_init_apr();
  157. // Set up llerror logging
  158. {
  159. LLError::initForApplication(".");
  160. LLError::setDefaultLevel(LLError::LEVEL_INFO);
  161. // LLError::setTagLevel("Plugin", LLError::LEVEL_DEBUG);
  162. // LLError::logToFile("slplugin.log");
  163. }
  164. #if LL_WINDOWS
  165. if( strlen( lpCmdLine ) == 0 )
  166. {
  167. LL_ERRS("slplugin") << "usage: " << "SLPlugin" << " launcher_port" << LL_ENDL;
  168. };
  169. U32 port = 0;
  170. if(!LLStringUtil::convertToU32(lpCmdLine, port))
  171. {
  172. LL_ERRS("slplugin") << "port number must be numeric" << LL_ENDL;
  173. };
  174. // Insert our exception handler into the system so this plugin doesn't
  175. // display a crash message if something bad happens. The host app will
  176. // see the missing heartbeat and log appropriately.
  177. initExceptionHandler();
  178. #elif LL_DARWIN || LL_LINUX
  179. if(argc < 2)
  180. {
  181. LL_ERRS("slplugin") << "usage: " << argv[0] << " launcher_port" << LL_ENDL;
  182. }
  183. U32 port = 0;
  184. if(!LLStringUtil::convertToU32(argv[1], port))
  185. {
  186. LL_ERRS("slplugin") << "port number must be numeric" << LL_ENDL;
  187. }
  188. // Catch signals that most kinds of crashes will generate, and exit cleanly so the system crash dialog isn't shown.
  189. signal(SIGILL, &crash_handler); // illegal instruction
  190. # if LL_DARWIN
  191. signal(SIGEMT, &crash_handler); // emulate instruction executed
  192. # endif // LL_DARWIN
  193. signal(SIGFPE, &crash_handler); // floating-point exception
  194. signal(SIGBUS, &crash_handler); // bus error
  195. signal(SIGSEGV, &crash_handler); // segmentation violation
  196. signal(SIGSYS, &crash_handler); // non-existent system call invoked
  197. #endif
  198. LLPluginProcessChild *plugin = new LLPluginProcessChild();
  199. plugin->init(port);
  200. LLTimer timer;
  201. timer.start();
  202. #if LL_WINDOWS
  203. checkExceptionHandler();
  204. #endif
  205. while(!plugin->isDone())
  206. {
  207. timer.reset();
  208. plugin->idle();
  209. #if LL_DARWIN
  210. {
  211. // Some plugins (webkit at least) will want an event loop.  This qualifies.
  212. EventRecord evt;
  213. WaitNextEvent(0, &evt, 0, NULL);
  214. }
  215. #endif
  216. F64 elapsed = timer.getElapsedTimeF64();
  217. F64 remaining = plugin->getSleepTime() - elapsed;
  218. if(remaining <= 0.0f)
  219. {
  220. // We've already used our full allotment.
  221. // LL_INFOS("slplugin") << "elapsed = " << elapsed * 1000.0f << " ms, remaining = " << remaining * 1000.0f << " ms, not sleeping" << LL_ENDL;
  222. // Still need to service the network...
  223. plugin->pump();
  224. }
  225. else
  226. {
  227. // LL_INFOS("slplugin") << "elapsed = " << elapsed * 1000.0f << " ms, remaining = " << remaining * 1000.0f << " ms, sleeping for " << remaining * 1000.0f << " ms" << LL_ENDL;
  228. // timer.reset();
  229. // This also services the network as needed.
  230. plugin->sleep(remaining);
  231. // LL_INFOS("slplugin") << "slept for "<< timer.getElapsedTimeF64() * 1000.0f << " ms" <<  LL_ENDL;
  232. }
  233. #if LL_WINDOWS
  234. // More agressive checking of interfering exception handlers.
  235. // Doesn't appear to be required so far - even for plugins
  236. // that do crash with a single call to the intercept
  237. // exception handler such as QuickTime.
  238. //checkExceptionHandler();
  239. #endif
  240. }
  241. delete plugin;
  242. ll_cleanup_apr();
  243. return 0;
  244. }