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

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llpluginprocessparent.cpp
  3.  * @brief LLPluginProcessParent handles the parent 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 "llpluginprocessparent.h"
  36. #include "llpluginmessagepipe.h"
  37. #include "llpluginmessageclasses.h"
  38. #include "llapr.h"
  39. //virtual 
  40. LLPluginProcessParentOwner::~LLPluginProcessParentOwner()
  41. {
  42. }
  43. LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner)
  44. {
  45. mOwner = owner;
  46. mBoundPort = 0;
  47. mState = STATE_UNINITIALIZED;
  48. mSleepTime = 0.0;
  49. mCPUUsage = 0.0;
  50. mDisableTimeout = false;
  51. mDebug = false;
  52. mPluginLaunchTimeout = 60.0f;
  53. mPluginLockupTimeout = 15.0f;
  54. // Don't start the timer here -- start it when we actually launch the plugin process.
  55. mHeartbeat.stop();
  56. }
  57. LLPluginProcessParent::~LLPluginProcessParent()
  58. {
  59. LL_DEBUGS("Plugin") << "destructor" << LL_ENDL;
  60. // Destroy any remaining shared memory regions
  61. sharedMemoryRegionsType::iterator iter;
  62. while((iter = mSharedMemoryRegions.begin()) != mSharedMemoryRegions.end())
  63. {
  64. // destroy the shared memory region
  65. iter->second->destroy();
  66. // and remove it from our map
  67. mSharedMemoryRegions.erase(iter);
  68. }
  69. // orphaning the process means it won't be killed when the LLProcessLauncher is destructed.
  70. // This is what we want -- it should exit cleanly once it notices the sockets have been closed.
  71. mProcess.orphan();
  72. killSockets();
  73. }
  74. void LLPluginProcessParent::killSockets(void)
  75. {
  76. killMessagePipe();
  77. mListenSocket.reset();
  78. mSocket.reset();
  79. }
  80. void LLPluginProcessParent::errorState(void)
  81. {
  82. if(mState < STATE_RUNNING)
  83. setState(STATE_LAUNCH_FAILURE);
  84. else
  85. setState(STATE_ERROR);
  86. }
  87. void LLPluginProcessParent::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug, const std::string &user_data_path)
  88. {
  89. mProcess.setExecutable(launcher_filename);
  90. mPluginFile = plugin_filename;
  91. mCPUUsage = 0.0f;
  92. mDebug = debug;
  93. mUserDataPath = user_data_path;
  94. setState(STATE_INITIALIZED);
  95. }
  96. bool LLPluginProcessParent::accept()
  97. {
  98. bool result = false;
  99. apr_status_t status = APR_EGENERAL;
  100. apr_socket_t *new_socket = NULL;
  101. status = apr_socket_accept(
  102. &new_socket,
  103. mListenSocket->getSocket(),
  104. gAPRPoolp);
  105. if(status == APR_SUCCESS)
  106. {
  107. // llinfos << "SUCCESS" << llendl;
  108. // Success.  Create a message pipe on the new socket
  109. // we MUST create a new pool for the LLSocket, since it will take ownership of it and delete it in its destructor!
  110. apr_pool_t* new_pool = NULL;
  111. status = apr_pool_create(&new_pool, gAPRPoolp);
  112. mSocket = LLSocket::create(new_socket, new_pool);
  113. new LLPluginMessagePipe(this, mSocket);
  114. result = true;
  115. }
  116. else if(APR_STATUS_IS_EAGAIN(status))
  117. {
  118. // llinfos << "EAGAIN" << llendl;
  119. // No incoming connections.  This is not an error.
  120. status = APR_SUCCESS;
  121. }
  122. else
  123. {
  124. // llinfos << "Error:" << llendl;
  125. ll_apr_warn_status(status);
  126. // Some other error.
  127. errorState();
  128. }
  129. return result;
  130. }
  131. void LLPluginProcessParent::idle(void)
  132. {
  133. bool idle_again;
  134. do
  135. {
  136. // Give time to network processing
  137. if(mMessagePipe)
  138. {
  139. if(!mMessagePipe->pump())
  140. {
  141. // LL_WARNS("Plugin") << "Message pipe hit an error state" << LL_ENDL;
  142. errorState();
  143. }
  144. }
  145. if((mSocketError != APR_SUCCESS) && (mState <= STATE_RUNNING))
  146. {
  147. // The socket is in an error state -- the plugin is gone.
  148. LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL;
  149. errorState();
  150. }
  151. // If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState().
  152. // 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.
  153. // When in doubt, don't do it.
  154. idle_again = false;
  155. switch(mState)
  156. {
  157. case STATE_UNINITIALIZED:
  158. break;
  159. case STATE_INITIALIZED:
  160. {
  161. apr_status_t status = APR_SUCCESS;
  162. apr_sockaddr_t* addr = NULL;
  163. mListenSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
  164. mBoundPort = 0;
  165. // This code is based on parts of LLSocket::create() in lliosocket.cpp.
  166. status = apr_sockaddr_info_get(
  167. &addr,
  168. "127.0.0.1",
  169. APR_INET,
  170. 0, // port 0 = ephemeral ("find me a port")
  171. 0,
  172. gAPRPoolp);
  173. if(ll_apr_warn_status(status))
  174. {
  175. killSockets();
  176. errorState();
  177. break;
  178. }
  179. // This allows us to reuse the address on quick down/up. This is unlikely to create problems.
  180. ll_apr_warn_status(apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_REUSEADDR, 1));
  181. status = apr_socket_bind(mListenSocket->getSocket(), addr);
  182. if(ll_apr_warn_status(status))
  183. {
  184. killSockets();
  185. errorState();
  186. break;
  187. }
  188. // Get the actual port the socket was bound to
  189. {
  190. apr_sockaddr_t* bound_addr = NULL;
  191. if(ll_apr_warn_status(apr_socket_addr_get(&bound_addr, APR_LOCAL, mListenSocket->getSocket())))
  192. {
  193. killSockets();
  194. errorState();
  195. break;
  196. }
  197. mBoundPort = bound_addr->port;
  198. if(mBoundPort == 0)
  199. {
  200. LL_WARNS("Plugin") << "Bound port number unknown, bailing out." << LL_ENDL;
  201. killSockets();
  202. errorState();
  203. break;
  204. }
  205. }
  206. LL_DEBUGS("Plugin") << "Bound tcp socket to port: " << addr->port << LL_ENDL;
  207. // Make the listen socket non-blocking
  208. status = apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_NONBLOCK, 1);
  209. if(ll_apr_warn_status(status))
  210. {
  211. killSockets();
  212. errorState();
  213. break;
  214. }
  215. apr_socket_timeout_set(mListenSocket->getSocket(), 0);
  216. if(ll_apr_warn_status(status))
  217. {
  218. killSockets();
  219. errorState();
  220. break;
  221. }
  222. // If it's a stream based socket, we need to tell the OS
  223. // to keep a queue of incoming connections for ACCEPT.
  224. status = apr_socket_listen(
  225. mListenSocket->getSocket(),
  226. 10); // FIXME: Magic number for queue size
  227. if(ll_apr_warn_status(status))
  228. {
  229. killSockets();
  230. errorState();
  231. break;
  232. }
  233. // If we got here, we're listening.
  234. setState(STATE_LISTENING);
  235. }
  236. break;
  237. case STATE_LISTENING:
  238. {
  239. // Launch the plugin process.
  240. // Only argument to the launcher is the port number we're listening on
  241. std::stringstream stream;
  242. stream << mBoundPort;
  243. mProcess.addArgument(stream.str());
  244. if(mProcess.launch() != 0)
  245. {
  246. errorState();
  247. }
  248. else
  249. {
  250. if(mDebug)
  251. {
  252. #if LL_DARWIN
  253. // If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue.
  254. // The command we're constructing would look like this on the command line:
  255. // osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell'
  256. std::stringstream cmd;
  257. mDebugger.setExecutable("/usr/bin/osascript");
  258. mDebugger.addArgument("-e");
  259. mDebugger.addArgument("tell application "Terminal"");
  260. mDebugger.addArgument("-e");
  261. cmd << "set win to do script "gdb -pid " << mProcess.getProcessID() << """;
  262. mDebugger.addArgument(cmd.str());
  263. mDebugger.addArgument("-e");
  264. mDebugger.addArgument("do script "continue" in win");
  265. mDebugger.addArgument("-e");
  266. mDebugger.addArgument("end tell");
  267. mDebugger.launch();
  268. #endif
  269. }
  270. // This will allow us to time out if the process never starts.
  271. mHeartbeat.start();
  272. mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout);
  273. setState(STATE_LAUNCHED);
  274. }
  275. }
  276. break;
  277. case STATE_LAUNCHED:
  278. // waiting for the plugin to connect
  279. if(pluginLockedUpOrQuit())
  280. {
  281. errorState();
  282. }
  283. else
  284. {
  285. // Check for the incoming connection.
  286. if(accept())
  287. {
  288. // Stop listening on the server port
  289. mListenSocket.reset();
  290. setState(STATE_CONNECTED);
  291. }
  292. }
  293. break;
  294. case STATE_CONNECTED:
  295. // waiting for hello message from the plugin
  296. if(pluginLockedUpOrQuit())
  297. {
  298. errorState();
  299. }
  300. break;
  301. case STATE_HELLO:
  302. LL_DEBUGS("Plugin") << "received hello message" << llendl;
  303. // Send the message to load the plugin
  304. {
  305. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin");
  306. message.setValue("file", mPluginFile);
  307. message.setValue("user_data_path", mUserDataPath);
  308. sendMessage(message);
  309. }
  310. setState(STATE_LOADING);
  311. break;
  312. case STATE_LOADING:
  313. // The load_plugin_response message will kick us from here into STATE_RUNNING
  314. if(pluginLockedUpOrQuit())
  315. {
  316. errorState();
  317. }
  318. break;
  319. case STATE_RUNNING:
  320. if(pluginLockedUpOrQuit())
  321. {
  322. errorState();
  323. }
  324. break;
  325. case STATE_EXITING:
  326. if(!mProcess.isRunning())
  327. {
  328. setState(STATE_CLEANUP);
  329. }
  330. else if(pluginLockedUp())
  331. {
  332. LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << llendl;
  333. errorState();
  334. }
  335. break;
  336. case STATE_LAUNCH_FAILURE:
  337. if(mOwner != NULL)
  338. {
  339. mOwner->pluginLaunchFailed();
  340. }
  341. setState(STATE_CLEANUP);
  342. break;
  343. case STATE_ERROR:
  344. if(mOwner != NULL)
  345. {
  346. mOwner->pluginDied();
  347. }
  348. setState(STATE_CLEANUP);
  349. break;
  350. case STATE_CLEANUP:
  351. // Don't do a kill here anymore -- closing the sockets is the new 'kill'.
  352. mProcess.orphan();
  353. killSockets();
  354. setState(STATE_DONE);
  355. break;
  356. case STATE_DONE:
  357. // just sit here.
  358. break;
  359. }
  360. } while (idle_again);
  361. }
  362. bool LLPluginProcessParent::isLoading(void)
  363. {
  364. bool result = false;
  365. if(mState <= STATE_LOADING)
  366. result = true;
  367. return result;
  368. }
  369. bool LLPluginProcessParent::isRunning(void)
  370. {
  371. bool result = false;
  372. if(mState == STATE_RUNNING)
  373. result = true;
  374. return result;
  375. }
  376. bool LLPluginProcessParent::isDone(void)
  377. {
  378. bool result = false;
  379. if(mState == STATE_DONE)
  380. result = true;
  381. return result;
  382. }
  383. void LLPluginProcessParent::setSleepTime(F64 sleep_time, bool force_send)
  384. {
  385. if(force_send || (sleep_time != mSleepTime))
  386. {
  387. // Cache the time locally
  388. mSleepTime = sleep_time;
  389. if(canSendMessage())
  390. {
  391. // and send to the plugin.
  392. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "sleep_time");
  393. message.setValueReal("time", mSleepTime);
  394. sendMessage(message);
  395. }
  396. else
  397. {
  398. // Too early to send -- the load_plugin_response message will trigger us to send mSleepTime later.
  399. }
  400. }
  401. }
  402. void LLPluginProcessParent::sendMessage(const LLPluginMessage &message)
  403. {
  404. std::string buffer = message.generate();
  405. LL_DEBUGS("Plugin") << "Sending: " << buffer << LL_ENDL;
  406. writeMessageRaw(buffer);
  407. }
  408. void LLPluginProcessParent::receiveMessageRaw(const std::string &message)
  409. {
  410. LL_DEBUGS("Plugin") << "Received: " << message << LL_ENDL;
  411. // FIXME: should this go into a queue instead?
  412. LLPluginMessage parsed;
  413. if(parsed.parse(message) != -1)
  414. {
  415. receiveMessage(parsed);
  416. }
  417. }
  418. void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message)
  419. {
  420. std::string message_class = message.getClass();
  421. if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL)
  422. {
  423. // internal messages should be handled here
  424. std::string message_name = message.getName();
  425. if(message_name == "hello")
  426. {
  427. if(mState == STATE_CONNECTED)
  428. {
  429. // Plugin host has launched.  Tell it which plugin to load.
  430. setState(STATE_HELLO);
  431. }
  432. else
  433. {
  434. LL_WARNS("Plugin") << "received hello message in wrong state -- bailing out" << LL_ENDL;
  435. errorState();
  436. }
  437. }
  438. else if(message_name == "load_plugin_response")
  439. {
  440. if(mState == STATE_LOADING)
  441. {
  442. // Plugin has been loaded. 
  443. mPluginVersionString = message.getValue("plugin_version");
  444. LL_INFOS("Plugin") << "plugin version string: " << mPluginVersionString << LL_ENDL;
  445. // Check which message classes/versions the plugin supports.
  446. // TODO: check against current versions
  447. // TODO: kill plugin on major mismatches?
  448. mMessageClassVersions = message.getValueLLSD("versions");
  449. LLSD::map_iterator iter;
  450. for(iter = mMessageClassVersions.beginMap(); iter != mMessageClassVersions.endMap(); iter++)
  451. {
  452. LL_INFOS("Plugin") << "message class: " << iter->first << " -> version: " << iter->second.asString() << LL_ENDL;
  453. }
  454. // Send initial sleep time
  455. setSleepTime(mSleepTime, true);
  456. setState(STATE_RUNNING);
  457. }
  458. else
  459. {
  460. LL_WARNS("Plugin") << "received load_plugin_response message in wrong state -- bailing out" << LL_ENDL;
  461. errorState();
  462. }
  463. }
  464. else if(message_name == "heartbeat")
  465. {
  466. // this resets our timer.
  467. mHeartbeat.setTimerExpirySec(mPluginLockupTimeout);
  468. mCPUUsage = message.getValueReal("cpu_usage");
  469. LL_DEBUGS("Plugin") << "cpu usage reported as " << mCPUUsage << LL_ENDL;
  470. }
  471. else if(message_name == "shm_add_response")
  472. {
  473. // Nothing to do here.
  474. }
  475. else if(message_name == "shm_remove_response")
  476. {
  477. std::string name = message.getValue("name");
  478. sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
  479. if(iter != mSharedMemoryRegions.end())
  480. {
  481. // destroy the shared memory region
  482. iter->second->destroy();
  483. // and remove it from our map
  484. mSharedMemoryRegions.erase(iter);
  485. }
  486. }
  487. else
  488. {
  489. LL_WARNS("Plugin") << "Unknown internal message from child: " << message_name << LL_ENDL;
  490. }
  491. }
  492. else
  493. {
  494. if(mOwner != NULL)
  495. {
  496. mOwner->receivePluginMessage(message);
  497. }
  498. }
  499. }
  500. std::string LLPluginProcessParent::addSharedMemory(size_t size)
  501. {
  502. std::string name;
  503. LLPluginSharedMemory *region = new LLPluginSharedMemory;
  504. // This is a new region
  505. if(region->create(size))
  506. {
  507. name = region->getName();
  508. mSharedMemoryRegions.insert(sharedMemoryRegionsType::value_type(name, region));
  509. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_add");
  510. message.setValue("name", name);
  511. message.setValueS32("size", (S32)size);
  512. sendMessage(message);
  513. }
  514. else
  515. {
  516. LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL;
  517. // Don't leak
  518. delete region;
  519. }
  520. return name;
  521. }
  522. void LLPluginProcessParent::removeSharedMemory(const std::string &name)
  523. {
  524. sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
  525. if(iter != mSharedMemoryRegions.end())
  526. {
  527. // This segment exists.  Send the message to the child to unmap it.  The response will cause the parent to unmap our end.
  528. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_remove");
  529. message.setValue("name", name);
  530. sendMessage(message);
  531. }
  532. else
  533. {
  534. LL_WARNS("Plugin") << "Request to remove an unknown shared memory segment." << LL_ENDL;
  535. }
  536. }
  537. size_t LLPluginProcessParent::getSharedMemorySize(const std::string &name)
  538. {
  539. size_t result = 0;
  540. sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
  541. if(iter != mSharedMemoryRegions.end())
  542. {
  543. result = iter->second->getSize();
  544. }
  545. return result;
  546. }
  547. void *LLPluginProcessParent::getSharedMemoryAddress(const std::string &name)
  548. {
  549. void *result = NULL;
  550. sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
  551. if(iter != mSharedMemoryRegions.end())
  552. {
  553. result = iter->second->getMappedAddress();
  554. }
  555. return result;
  556. }
  557. std::string LLPluginProcessParent::getMessageClassVersion(const std::string &message_class)
  558. {
  559. std::string result;
  560. if(mMessageClassVersions.has(message_class))
  561. {
  562. result = mMessageClassVersions[message_class].asString();
  563. }
  564. return result;
  565. }
  566. std::string LLPluginProcessParent::getPluginVersion(void)
  567. {
  568. return mPluginVersionString;
  569. }
  570. void LLPluginProcessParent::setState(EState state)
  571. {
  572. LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL;
  573. mState = state; 
  574. };
  575. bool LLPluginProcessParent::pluginLockedUpOrQuit()
  576. {
  577. bool result = false;
  578. if(!mDisableTimeout && !mDebug)
  579. {
  580. if(!mProcess.isRunning())
  581. {
  582. LL_WARNS("Plugin") << "child exited" << llendl;
  583. result = true;
  584. }
  585. else if(pluginLockedUp())
  586. {
  587. LL_WARNS("Plugin") << "timeout" << llendl;
  588. result = true;
  589. }
  590. }
  591. return result;
  592. }
  593. bool LLPluginProcessParent::pluginLockedUp()
  594. {
  595. // If the timer is running and has expired, the plugin has locked up.
  596. return (mHeartbeat.getStarted() && mHeartbeat.hasExpired());
  597. }