llpluginprocessparent.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /**
  2. * @file llpluginprocessparent.h
  3. * @brief LLPluginProcessParent handles the parent side of the external-process plugin API.
  4. *
  5. * $LicenseInfo:firstyear=2008&license=viewergpl$
  6. *
  7. * Copyright (c) 2008-2009, Linden Research, Inc.
  8. * Copyright (c) 2009-2024, Henri Beauchamp.
  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. */
  33. #ifndef LL_LLPLUGINPROCESSPARENT_H
  34. #define LL_LLPLUGINPROCESSPARENT_H
  35. #include <memory>
  36. #include <queue>
  37. #include "llapr.h"
  38. #include "llatomic.h"
  39. #include "llevents.h"
  40. #include "llpreprocessor.h"
  41. #include "llprocesslauncher.h"
  42. #include "llpluginmessage.h"
  43. #include "llpluginmessagepipe.h"
  44. #include "llpluginsharedmemory.h"
  45. #include "lliosocket.h"
  46. #include "lltimer.h"
  47. class LLThread;
  48. class LLPluginProcessParentOwner
  49. : public std::enable_shared_from_this<LLPluginProcessParentOwner>
  50. {
  51. public:
  52. virtual ~LLPluginProcessParentOwner() = default;
  53. virtual void receivePluginMessage(const LLPluginMessage& message) = 0;
  54. LL_INLINE virtual bool receivePluginMessageEarly(const LLPluginMessage& msg)
  55. {
  56. return false;
  57. }
  58. // This will only be called when the plugin has died unexpectedly
  59. LL_INLINE virtual void pluginLaunchFailed() {}
  60. LL_INLINE virtual void pluginDied() {}
  61. };
  62. class LLPluginProcessParent final : public LLPluginMessagePipeOwner
  63. {
  64. protected:
  65. LOG_CLASS(LLPluginProcessParent);
  66. LLPluginProcessParent(LLPluginProcessParentOwner* ownerp);
  67. public:
  68. ~LLPluginProcessParent() override;
  69. typedef std::shared_ptr<LLPluginProcessParent> ptr_t;
  70. void init(const std::string& launcher_filename,
  71. const std::string& plugin_dir,
  72. const std::string& plugin_filename, bool debug);
  73. // Launches the process. Returns true is successful.
  74. bool createPluginProcess();
  75. void idle();
  76. // Returns true if the plugin is on its way to steady state
  77. LL_INLINE bool isLoading()
  78. {
  79. return mState.get() <= STATE_LOADING;
  80. }
  81. // Returns true if the plugin is in the steady state (processing messages)
  82. LL_INLINE bool isRunning()
  83. {
  84. return mState.get() == STATE_RUNNING;
  85. }
  86. // Returns true if the process has exited or we have had a fatal error
  87. LL_INLINE bool isDone()
  88. {
  89. return !mProcessStartRequested && mState.get() == STATE_DONE;
  90. }
  91. // Returns true if the process is currently waiting on a blocking request
  92. LL_INLINE bool isBlocked() { return mBlocked; }
  93. void killSockets();
  94. // Goes to the proper error state
  95. void errorState();
  96. void setSleepTime(F64 sleep_time, bool force_send = false);
  97. LL_INLINE F64 getSleepTime() const { return mSleepTime; }
  98. void sendMessage(const LLPluginMessage& message);
  99. void receiveMessage(const LLPluginMessage& message);
  100. // Inherited from LLPluginMessagePipeOwner
  101. void setMessagePipe(LLPluginMessagePipe* message_pipe) override;
  102. void receiveMessageRaw(const std::string& message) override;
  103. void receiveMessageEarly(const LLPluginMessage& message);
  104. // This adds a memory segment shared with the client, generating a name for
  105. // the segment. The name generated is guaranteed to be unique on the host.
  106. // The caller must call removeSharedMemory first (and wait until
  107. // getSharedMemorySize returns 0 for the indicated name) before re-adding a
  108. // segment with the same name.
  109. std::string addSharedMemory(size_t size);
  110. // Negotiates for the removal of a shared memory segment. It is the
  111. // caller's responsibility to ensure that nothing touches the memory after
  112. // this has been called, since the segment will be unmapped shortly
  113. // thereafter.
  114. void removeSharedMemory(const std::string& name);
  115. size_t getSharedMemorySize(const std::string& name);
  116. void* getSharedMemoryAddress(const std::string& name);
  117. // Returns the version string the plugin indicated for the message class,
  118. // or an empty string if that class wasn't in the list.
  119. std::string getMessageClassVersion(const std::string& message_class);
  120. LL_INLINE std::string getPluginVersion() { return mPluginVersionString; }
  121. LL_INLINE bool getDisableTimeout() { return mDisableTimeout; }
  122. LL_INLINE void setDisableTimeout(bool b) { mDisableTimeout = b; }
  123. LL_INLINE void setLaunchTimeout(F32 t) { mPluginLaunchTimeout = t; }
  124. LL_INLINE void setLockupTimeout(F32 t) { mPluginLockupTimeout = t; }
  125. LL_INLINE F64 getCPUUsage() { return mCPUUsage; }
  126. void requestShutdown();
  127. static ptr_t create(LLPluginProcessParentOwner* ownerp);
  128. static void requestExit();
  129. static void shutdown();
  130. static bool poll(F64 timeout);
  131. LL_INLINE static bool canPollThreadRun()
  132. {
  133. return sPollSet || sPollsetNeedsRebuild || sUseReadThread;
  134. }
  135. static void setUseReadThread(bool use_read_thread);
  136. LL_INLINE static bool getUseReadThread() { return sUseReadThread; }
  137. LL_INLINE static const std::string& getMediaBrowserVersion()
  138. {
  139. return sMediaBrowserVersion;
  140. }
  141. private:
  142. enum EState : U32
  143. {
  144. STATE_UNINITIALIZED,
  145. STATE_INITIALIZED, // init() has been called
  146. STATE_LISTENING, // listening for incoming connection
  147. STATE_LAUNCHED, // process has been launched
  148. STATE_CONNECTED, // process has connected
  149. STATE_HELLO, // first message from the plugin process has been received
  150. STATE_LOADING, // process has been asked to load the plugin
  151. STATE_RUNNING,
  152. STATE_GOODBYE,
  153. STATE_LAUNCH_FAILURE, // Failure before plugin loaded
  154. STATE_ERROR, // generic bailout state
  155. STATE_CLEANUP, // clean everything up
  156. STATE_EXITING, // Tried to kill process, waiting for it to exit
  157. STATE_DONE
  158. };
  159. std::string state2string(U32 state);
  160. void setState(U32 state);
  161. bool wantsPolling() const;
  162. void removeFromProcessing();
  163. bool pluginLockedUp();
  164. bool pluginLockedUpOrQuit();
  165. bool accept();
  166. void servicePoll();
  167. bool pollTick();
  168. static void dirtyPollSet();
  169. static void updatePollset();
  170. private:
  171. LLPluginProcessParentOwner* mOwner;
  172. LLTimer mHeartbeat;
  173. F64 mSleepTime;
  174. F64 mCPUUsage;
  175. LLSocket::ptr_t mListenSocket;
  176. LLSocket::ptr_t mSocket;
  177. LLProcessLauncher mProcess;
  178. LLProcessLauncher mDebugger;
  179. U32 mBoundPort;
  180. // Somewhat longer timeout for initial launch:
  181. F32 mPluginLaunchTimeout;
  182. // If we do not receive a heartbeat in this many seconds, we declare the
  183. // plugin locked up:
  184. F32 mPluginLockupTimeout;
  185. apr_pollfd_t mPollFD;
  186. LLMutex mIncomingQueueMutex;
  187. std::queue<LLPluginMessage> mIncomingQueue;
  188. typedef std::map<std::string, LLPluginSharedMemory*> shared_mem_regions_t;
  189. shared_mem_regions_t mSharedMemoryRegions;
  190. LLTempBoundListener mPolling;
  191. LLSD mMessageClassVersions;
  192. std::string mPluginVersionString;
  193. std::string mPluginFile;
  194. std::string mPluginDir;
  195. // Used to distinguish plugins in log messages. HB
  196. std::string mPluginName;
  197. // These variables need to be atomic, since set and tested in different
  198. // threads. HB
  199. LLAtomicU32 mState;
  200. LLAtomicBool mProcessStartRequested;
  201. bool mProcessStarted;
  202. bool mDisableTimeout;
  203. bool mBlocked;
  204. bool mPolledInput;
  205. bool mDebug;
  206. static std::string sMediaBrowserVersion;
  207. static apr_pollset_t* sPollSet;
  208. static LLMutex sInstancesMutex;
  209. typedef std::map<void*, ptr_t> instances_map_t;
  210. static instances_map_t sInstances;
  211. static LLThread* sReadThread;
  212. static bool sUseReadThread;
  213. static bool sPollsetNeedsRebuild;
  214. };
  215. #endif // LL_LLPLUGINPROCESSPARENT_H