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

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llpluginprocesschild.cpp
  3.  * @brief LLPluginProcessChild handles the child side of the external-process plugin API. 
  4.  *
  5.  * @cond
  6.  * $LicenseInfo:firstyear=2008&license=viewergpl$
  7.  * 
  8.  * Copyright (c) 2008-2010, Linden Research, Inc.
  9.  * 
  10.  * Second Life Viewer Source Code
  11.  * The source code in this file ("Source Code") is provided by Linden Lab
  12.  * to you under the terms of the GNU General Public License, version 2.0
  13.  * ("GPL"), unless you have obtained a separate licensing agreement
  14.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  15.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  16.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  17.  * 
  18.  * There are special exceptions to the terms and conditions of the GPL as
  19.  * it is applied to this Source Code. View the full text of the exception
  20.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  21.  * online at
  22.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  23.  * 
  24.  * By copying, modifying or distributing this software, you acknowledge
  25.  * that you have read and understood your obligations described above,
  26.  * and agree to abide by those obligations.
  27.  * 
  28.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  29.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  30.  * COMPLETENESS OR PERFORMANCE.
  31.  * $/LicenseInfo$
  32.  * @endcond
  33.  */
  34. #include "linden_common.h"
  35. #include "llpluginprocesschild.h"
  36. #include "llplugininstance.h"
  37. #include "llpluginmessagepipe.h"
  38. #include "llpluginmessageclasses.h"
  39. static const F32 HEARTBEAT_SECONDS = 1.0f;
  40. static const F32 PLUGIN_IDLE_SECONDS = 1.0f / 100.0f;  // Each call to idle will give the plugin this much time.
  41. LLPluginProcessChild::LLPluginProcessChild()
  42. {
  43. mState = STATE_UNINITIALIZED;
  44. mInstance = NULL;
  45. mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
  46. mSleepTime = PLUGIN_IDLE_SECONDS; // default: send idle messages at 100Hz
  47. mCPUElapsed = 0.0f;
  48. }
  49. LLPluginProcessChild::~LLPluginProcessChild()
  50. {
  51. if(mInstance != NULL)
  52. {
  53. sendMessageToPlugin(LLPluginMessage("base", "cleanup"));
  54. // IMPORTANT: under some (unknown) circumstances the apr_dso_unload() triggered when mInstance is deleted 
  55. // appears to fail and lock up which means that a given instance of the slplugin process never exits. 
  56. // This is bad, especially when users try to update their version of SL - it fails because the slplugin 
  57. // process as well as a bunch of plugin specific files are locked and cannot be overwritten.
  58. exit( 0 );
  59. //delete mInstance;
  60. //mInstance = NULL;
  61. }
  62. }
  63. void LLPluginProcessChild::killSockets(void)
  64. {
  65. killMessagePipe();
  66. mSocket.reset();
  67. }
  68. void LLPluginProcessChild::init(U32 launcher_port)
  69. {
  70. mLauncherHost = LLHost("127.0.0.1", launcher_port);
  71. setState(STATE_INITIALIZED);
  72. }
  73. void LLPluginProcessChild::idle(void)
  74. {
  75. bool idle_again;
  76. do
  77. {
  78. if(mSocketError != APR_SUCCESS)
  79. {
  80. LL_INFOS("Plugin") << "message pipe is in error state, moving to STATE_ERROR"<< LL_ENDL;
  81. setState(STATE_ERROR);
  82. }
  83. if((mState > STATE_INITIALIZED) && (mMessagePipe == NULL))
  84. {
  85. // The pipe has been closed -- we're done.
  86. // TODO: This could be slightly more subtle, but I'm not sure it needs to be.
  87. LL_INFOS("Plugin") << "message pipe went away, moving to STATE_ERROR"<< LL_ENDL;
  88. setState(STATE_ERROR);
  89. }
  90. // If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState().
  91. // USE THIS CAREFULLY, since it can starve other code.  Specifically make sure there's no way to get into a closed cycle and never return.
  92. // When in doubt, don't do it.
  93. idle_again = false;
  94. if(mInstance != NULL)
  95. {
  96. // Provide some time to the plugin
  97. mInstance->idle();
  98. }
  99. switch(mState)
  100. {
  101. case STATE_UNINITIALIZED:
  102. break;
  103. case STATE_INITIALIZED:
  104. if(mSocket->blockingConnect(mLauncherHost))
  105. {
  106. // This automatically sets mMessagePipe
  107. new LLPluginMessagePipe(this, mSocket);
  108. setState(STATE_CONNECTED);
  109. }
  110. else
  111. {
  112. // connect failed
  113. setState(STATE_ERROR);
  114. }
  115. break;
  116. case STATE_CONNECTED:
  117. sendMessageToParent(LLPluginMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hello"));
  118. setState(STATE_PLUGIN_LOADING);
  119. break;
  120. case STATE_PLUGIN_LOADING:
  121. if(!mPluginFile.empty())
  122. {
  123. mInstance = new LLPluginInstance(this);
  124. if(mInstance->load(mPluginFile) == 0)
  125. {
  126. mHeartbeat.start();
  127. mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS);
  128. mCPUElapsed = 0.0f;
  129. setState(STATE_PLUGIN_LOADED);
  130. }
  131. else
  132. {
  133. setState(STATE_ERROR);
  134. }
  135. }
  136. break;
  137. case STATE_PLUGIN_LOADED:
  138. {
  139. setState(STATE_PLUGIN_INITIALIZING);
  140. LLPluginMessage message("base", "init");
  141. message.setValue("user_data_path", mUserDataPath);
  142. sendMessageToPlugin(message);
  143. }
  144. break;
  145. case STATE_PLUGIN_INITIALIZING:
  146. // waiting for init_response...
  147. break;
  148. case STATE_RUNNING:
  149. if(mInstance != NULL)
  150. {
  151. // Provide some time to the plugin
  152. LLPluginMessage message("base", "idle");
  153. message.setValueReal("time", PLUGIN_IDLE_SECONDS);
  154. sendMessageToPlugin(message);
  155. mInstance->idle();
  156. if(mHeartbeat.hasExpired())
  157. {
  158. // This just proves that we're not stuck down inside the plugin code.
  159. LLPluginMessage heartbeat(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "heartbeat");
  160. // Calculate the approximage CPU usage fraction (floating point value between 0 and 1) used by the plugin this heartbeat cycle.
  161. // Note that this will not take into account any threads or additional processes the plugin spawns, but it's a first approximation.
  162. // If we could write OS-specific functions to query the actual CPU usage of this process, that would be a better approximation.
  163. heartbeat.setValueReal("cpu_usage", mCPUElapsed / mHeartbeat.getElapsedTimeF64());
  164. sendMessageToParent(heartbeat);
  165. mHeartbeat.reset();
  166. mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS);
  167. mCPUElapsed = 0.0f;
  168. }
  169. }
  170. // receivePluginMessage will transition to STATE_UNLOADING
  171. break;
  172. case STATE_UNLOADING:
  173. if(mInstance != NULL)
  174. {
  175. sendMessageToPlugin(LLPluginMessage("base", "cleanup"));
  176. delete mInstance;
  177. mInstance = NULL;
  178. }
  179. setState(STATE_UNLOADED);
  180. break;
  181. case STATE_UNLOADED:
  182. killSockets();
  183. setState(STATE_DONE);
  184. break;
  185. case STATE_ERROR:
  186. // Close the socket to the launcher
  187. killSockets();
  188. // TODO: Where do we go from here?  Just exit()?
  189. setState(STATE_DONE);
  190. break;
  191. case STATE_DONE:
  192. // just sit here.
  193. break;
  194. }
  195. } while (idle_again);
  196. }
  197. void LLPluginProcessChild::sleep(F64 seconds)
  198. {
  199. if(mMessagePipe)
  200. {
  201. mMessagePipe->pump(seconds);
  202. }
  203. else
  204. {
  205. ms_sleep((int)(seconds * 1000.0f));
  206. }
  207. }
  208. void LLPluginProcessChild::pump(void)
  209. {
  210. if(mMessagePipe)
  211. {
  212. mMessagePipe->pump(0.0f);
  213. }
  214. else
  215. {
  216. // Should we warn here?
  217. }
  218. }
  219. bool LLPluginProcessChild::isRunning(void)
  220. {
  221. bool result = false;
  222. if(mState == STATE_RUNNING)
  223. result = true;
  224. return result;
  225. }
  226. bool LLPluginProcessChild::isDone(void)
  227. {
  228. bool result = false;
  229. switch(mState)
  230. {
  231. case STATE_DONE:
  232. result = true;
  233. break;
  234. default:
  235. break;
  236. }
  237. return result;
  238. }
  239. void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message)
  240. {
  241. if (mInstance)
  242. {
  243. std::string buffer = message.generate();
  244. LL_DEBUGS("Plugin") << "Sending to plugin: " << buffer << LL_ENDL;
  245. LLTimer elapsed;
  246. mInstance->sendMessage(buffer);
  247. mCPUElapsed += elapsed.getElapsedTimeF64();
  248. }
  249. else
  250. {
  251. LL_WARNS("Plugin") << "mInstance == NULL" << LL_ENDL;
  252. }
  253. }
  254. void LLPluginProcessChild::sendMessageToParent(const LLPluginMessage &message)
  255. {
  256. std::string buffer = message.generate();
  257. LL_DEBUGS("Plugin") << "Sending to parent: " << buffer << LL_ENDL;
  258. writeMessageRaw(buffer);
  259. }
  260. void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
  261. {
  262. // Incoming message from the TCP Socket
  263. LL_DEBUGS("Plugin") << "Received from parent: " << message << LL_ENDL;
  264. bool passMessage = true;
  265. // FIXME: how should we handle queueing here?
  266. {
  267. // Decode this message
  268. LLPluginMessage parsed;
  269. parsed.parse(message);
  270. std::string message_class = parsed.getClass();
  271. if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL)
  272. {
  273. passMessage = false;
  274. std::string message_name = parsed.getName();
  275. if(message_name == "load_plugin")
  276. {
  277. mPluginFile = parsed.getValue("file");
  278. mUserDataPath = parsed.getValue("user_data_path");
  279. }
  280. else if(message_name == "shm_add")
  281. {
  282. std::string name = parsed.getValue("name");
  283. size_t size = (size_t)parsed.getValueS32("size");
  284. sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
  285. if(iter != mSharedMemoryRegions.end())
  286. {
  287. // Need to remove the old region first
  288. LL_WARNS("Plugin") << "Adding a duplicate shared memory segment!" << LL_ENDL;
  289. }
  290. else
  291. {
  292. // This is a new region
  293. LLPluginSharedMemory *region = new LLPluginSharedMemory;
  294. if(region->attach(name, size))
  295. {
  296. mSharedMemoryRegions.insert(sharedMemoryRegionsType::value_type(name, region));
  297. std::stringstream addr;
  298. addr << region->getMappedAddress();
  299. // Send the add notification to the plugin
  300. LLPluginMessage message("base", "shm_added");
  301. message.setValue("name", name);
  302. message.setValueS32("size", (S32)size);
  303. message.setValuePointer("address", region->getMappedAddress());
  304. sendMessageToPlugin(message);
  305. // and send the response to the parent
  306. message.setMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_add_response");
  307. message.setValue("name", name);
  308. sendMessageToParent(message);
  309. }
  310. else
  311. {
  312. LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL;
  313. delete region;
  314. }
  315. }
  316. }
  317. else if(message_name == "shm_remove")
  318. {
  319. std::string name = parsed.getValue("name");
  320. sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
  321. if(iter != mSharedMemoryRegions.end())
  322. {
  323. // forward the remove request to the plugin -- its response will trigger us to detach the segment.
  324. LLPluginMessage message("base", "shm_remove");
  325. message.setValue("name", name);
  326. sendMessageToPlugin(message);
  327. }
  328. else
  329. {
  330. LL_WARNS("Plugin") << "shm_remove for unknown memory segment!" << LL_ENDL;
  331. }
  332. }
  333. else if(message_name == "sleep_time")
  334. {
  335. mSleepTime = parsed.getValueReal("time");
  336. }
  337. else if(message_name == "crash")
  338. {
  339. // Crash the plugin
  340. LL_ERRS("Plugin") << "Plugin crash requested." << LL_ENDL;
  341. }
  342. else if(message_name == "hang")
  343. {
  344. // Hang the plugin
  345. LL_WARNS("Plugin") << "Plugin hang requested." << LL_ENDL;
  346. while(1)
  347. {
  348. // wheeeeeeeee......
  349. }
  350. }
  351. else
  352. {
  353. LL_WARNS("Plugin") << "Unknown internal message from parent: " << message_name << LL_ENDL;
  354. }
  355. }
  356. }
  357. if(passMessage && mInstance != NULL)
  358. {
  359. LLTimer elapsed;
  360. mInstance->sendMessage(message);
  361. mCPUElapsed += elapsed.getElapsedTimeF64();
  362. }
  363. }
  364. /* virtual */ 
  365. void LLPluginProcessChild::receivePluginMessage(const std::string &message)
  366. {
  367. LL_DEBUGS("Plugin") << "Received from plugin: " << message << LL_ENDL;
  368. // Incoming message from the plugin instance
  369. bool passMessage = true;
  370. // FIXME: how should we handle queueing here?
  371. // Intercept certain base messages (responses to ones sent by this class)
  372. {
  373. // Decode this message
  374. LLPluginMessage parsed;
  375. parsed.parse(message);
  376. std::string message_class = parsed.getClass();
  377. if(message_class == "base")
  378. {
  379. std::string message_name = parsed.getName();
  380. if(message_name == "init_response")
  381. {
  382. // The plugin has finished initializing.
  383. setState(STATE_RUNNING);
  384. // Don't pass this message up to the parent
  385. passMessage = false;
  386. LLPluginMessage new_message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin_response");
  387. LLSD versions = parsed.getValueLLSD("versions");
  388. new_message.setValueLLSD("versions", versions);
  389. if(parsed.hasValue("plugin_version"))
  390. {
  391. std::string plugin_version = parsed.getValue("plugin_version");
  392. new_message.setValueLLSD("plugin_version", plugin_version);
  393. }
  394. // Let the parent know it's loaded and initialized.
  395. sendMessageToParent(new_message);
  396. }
  397. else if(message_name == "shm_remove_response")
  398. {
  399. // Don't pass this message up to the parent
  400. passMessage = false;
  401. std::string name = parsed.getValue("name");
  402. sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
  403. if(iter != mSharedMemoryRegions.end())
  404. {
  405. // detach the shared memory region
  406. iter->second->detach();
  407. // and remove it from our map
  408. mSharedMemoryRegions.erase(iter);
  409. // Finally, send the response to the parent.
  410. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_remove_response");
  411. message.setValue("name", name);
  412. sendMessageToParent(message);
  413. }
  414. else
  415. {
  416. LL_WARNS("Plugin") << "shm_remove_response for unknown memory segment!" << LL_ENDL;
  417. }
  418. }
  419. }
  420. }
  421. if(passMessage)
  422. {
  423. LL_DEBUGS("Plugin") << "Passing through to parent: " << message << LL_ENDL;
  424. writeMessageRaw(message);
  425. }
  426. }
  427. void LLPluginProcessChild::setState(EState state)
  428. {
  429. LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL;
  430. mState = state; 
  431. };