From fa26f5eaa2cb1a0152fe681e9baa292626564caf Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 21 May 2021 19:06:11 +0300 Subject: SL-14988 Viewer freezes when opening any CEF based window Don't block main thread if possible --- indra/llplugin/llpluginprocessparent.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'indra/llplugin') diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 7d18bae947..f4bd944387 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -320,8 +320,9 @@ void LLPluginProcessParent::idle(void) do { // process queued messages - mIncomingQueueMutex.lock(); - while(!mIncomingQueue.empty()) + // Inside main thread, it is preferable not to block it on mutex. + bool locked = mIncomingQueueMutex.trylock(); + while(locked && !mIncomingQueue.empty()) { LLPluginMessage message = mIncomingQueue.front(); mIncomingQueue.pop(); @@ -329,10 +330,13 @@ void LLPluginProcessParent::idle(void) receiveMessage(message); - mIncomingQueueMutex.lock(); + locked = mIncomingQueueMutex.trylock(); } - mIncomingQueueMutex.unlock(); + if (locked) + { + mIncomingQueueMutex.unlock(); + } // Give time to network processing if(mMessagePipe) -- cgit v1.2.3 From d875f809002706e284e6a5da30fd911723e88c44 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 21 May 2021 20:08:26 +0300 Subject: SL-14988 Plugin process creation can cause a notiecable delay --- indra/llplugin/llpluginprocessparent.cpp | 104 ++++++++++++++++++++++++++++--- indra/llplugin/llpluginprocessparent.h | 8 +++ 2 files changed, 104 insertions(+), 8 deletions(-) (limited to 'indra/llplugin') diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index f4bd944387..a2827e2eed 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -79,8 +79,29 @@ protected: }; + +class LLPluginProcessCreationThread : public LLThread +{ +public: + LLPluginProcessCreationThread(LLPluginProcessParent *parent) : + LLThread("LLPluginProcessCreationThread", gAPRPoolp), + pParent(parent) + { + } +protected: + // Inherited from LLThread, should run once + /*virtual*/ void run(void) + { + pParent->createPluginProcess(); + } +private: + LLPluginProcessParent *pParent; + +}; + LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner): - mIncomingQueueMutex() + mIncomingQueueMutex(), + pProcessCreationThread(NULL) { if(!sInstancesMutex) { @@ -109,6 +130,18 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner): LLPluginProcessParent::~LLPluginProcessParent() { LL_DEBUGS("Plugin") << "destructor" << LL_ENDL; + if (pProcessCreationThread) + { + if (!pProcessCreationThread->isStopped()) + { + // Shouldn't happen at this stage + LL_WARNS("Plugin") << "Shutting down active pProcessCreationThread" << LL_ENDL; + pProcessCreationThread->shutdown(); + ms_sleep(20); + } + delete pProcessCreationThread; + pProcessCreationThread = NULL; + } // Destroy any remaining shared memory regions sharedMemoryRegionsType::iterator iter; @@ -313,6 +346,35 @@ bool LLPluginProcessParent::accept() return result; } +bool LLPluginProcessParent::createPluginProcess() +{ + if (!mProcess) + { + // Only argument to the launcher is the port number we're listening on + mProcessParams.args.add(stringize(mBoundPort)); + mProcess = LLProcess::create(mProcessParams); + return mProcess != NULL; + } + + return false; +} + +void LLPluginProcessParent::clearProcessCreationThread() +{ + if (pProcessCreationThread) + { + if (!pProcessCreationThread->isStopped()) + { + pProcessCreationThread->shutdown(); + } + else + { + delete pProcessCreationThread; + pProcessCreationThread = NULL; + } + } +} + void LLPluginProcessParent::idle(void) { bool idle_again; @@ -472,14 +534,30 @@ void LLPluginProcessParent::idle(void) case STATE_LISTENING: { // Launch the plugin process. + if (mDebug && !pProcessCreationThread) + { + createPluginProcess(); + if (!mProcess) + { + errorState(); + } + } + else if (pProcessCreationThread == NULL) + { + // exe plugin process allocation can be hindered by a number + // of factors, don't hold whole viewer because of it, use thread + pProcessCreationThread = new LLPluginProcessCreationThread(this); + pProcessCreationThread->start(); + } + else if (!mProcess && pProcessCreationThread->isStopped()) + { + delete pProcessCreationThread; + pProcessCreationThread = NULL; + errorState(); + } + - // Only argument to the launcher is the port number we're listening on - mProcessParams.args.add(stringize(mBoundPort)); - if (! (mProcess = LLProcess::create(mProcessParams))) - { - errorState(); - } - else + if (mProcess) { if(mDebug) { @@ -508,6 +586,15 @@ void LLPluginProcessParent::idle(void) // This will allow us to time out if the process never starts. mHeartbeat.start(); mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout); + + // pProcessCreationThread should have stopped by this point, + // but check just in case it paused on statistics sync + if (pProcessCreationThread && pProcessCreationThread->isStopped()) + { + delete pProcessCreationThread; + pProcessCreationThread = NULL; + } + setState(STATE_LAUNCHED); } } @@ -610,6 +697,7 @@ void LLPluginProcessParent::idle(void) killSockets(); setState(STATE_DONE); dirtyPollSet(); + clearProcessCreationThread(); break; case STATE_DONE: diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h index df1630255c..1893c9e657 100644 --- a/indra/llplugin/llpluginprocessparent.h +++ b/indra/llplugin/llpluginprocessparent.h @@ -69,6 +69,11 @@ public: const std::string &plugin_filename, bool debug); + // Creates a process + // returns true if process already exists or if created, + // false if failed to create + bool createPluginProcess(); + void idle(void); // returns true if the plugin is on its way to steady state @@ -163,12 +168,15 @@ private: bool accept(); + void clearProcessCreationThread(); + LLSocket::ptr_t mListenSocket; LLSocket::ptr_t mSocket; U32 mBoundPort; LLProcess::Params mProcessParams; LLProcessPtr mProcess; + LLThread *pProcessCreationThread; std::string mPluginFile; std::string mPluginDir; -- cgit v1.2.3 From c1943e5efb18a0786a538237eee4bee8a7330e56 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 8 Oct 2021 23:56:43 +0300 Subject: SL-16161 Don't process new plugin messages on shutdown Some pending messages might try to update non-existing view or cause a pop up, neither should be avaliable by this point, so just don't process them --- indra/llplugin/llpluginprocessparent.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'indra/llplugin') diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 73327ce2ee..7a704b71f3 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -192,6 +192,7 @@ void LLPluginProcessParent::shutdown() && state != STATE_ERROR) { (*it).second->setState(STATE_GOODBYE); + (*it).second->mOwner = NULL; } if (state != STATE_DONE) { @@ -407,7 +408,10 @@ void LLPluginProcessParent::idle(void) mMessagePipe->pumpOutput(); // Only do input processing here if this instance isn't in a pollset. - if(!mPolledInput) + // If we are shutting down plugin, owner is null and we can't process + // input, we are here only to send shutdown_plugin message + if(!mPolledInput + && mState != STATE_GOODBYE) { mMessagePipe->pumpInput(); } -- cgit v1.2.3 From 66b5e49a7950962a1d1793c21f2714b125f8c47d Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 11 Oct 2021 19:26:45 +0300 Subject: SL-16161 Don't process new plugin messages on shutdown #2 --- indra/llplugin/llpluginprocessparent.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/llplugin') diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 7a704b71f3..c39ac815c0 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -408,10 +408,10 @@ void LLPluginProcessParent::idle(void) mMessagePipe->pumpOutput(); // Only do input processing here if this instance isn't in a pollset. - // If we are shutting down plugin, owner is null and we can't process - // input, we are here only to send shutdown_plugin message + // If viewer and plugin are both shutting down, don't process further + // input, viewer won't be able to handle it. if(!mPolledInput - && mState != STATE_GOODBYE) + && !(mState >= STATE_GOODBYE && LLApp::isExiting())) { mMessagePipe->pumpInput(); } -- cgit v1.2.3