Use thread pool to create plugin processes to reduce created/destroyed threads and fix various crashes (#2079)

master
Rye Mutt 2024-07-22 09:10:19 -04:00 committed by GitHub
parent 3c7fc595fa
commit ac2f20fc03
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 62 additions and 96 deletions

View File

@ -34,6 +34,9 @@
#include "llpluginmessageclasses.h"
#include "llsdserialize.h"
#include "stringize.h"
#include "threadpool.h"
#include "workqueue.h"
#include "llapr.h"
//virtual
@ -79,29 +82,8 @@ 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(),
pProcessCreationThread(NULL)
mIncomingQueueMutex()
{
if(!sInstancesMutex)
{
@ -130,18 +112,6 @@ 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;
@ -352,35 +322,6 @@ 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;
@ -542,29 +483,71 @@ void LLPluginProcessParent::idle(void)
case STATE_LISTENING:
{
// Only argument to the launcher is the port number we're listening on
mProcessParams.args.add(stringize(mBoundPort));
// Launch the plugin process.
if (mDebug && !pProcessCreationThread)
if (mDebug && !mProcess)
{
createPluginProcess();
if (!mProcess)
if (!(mProcess = LLProcess::create(mProcessParams)))
{
errorState();
}
}
else if (pProcessCreationThread == NULL)
else if (!mProcess && !mProcessCreationRequested)
{
// 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();
}
mProcessCreationRequested = true;
LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop");
// *NOTE: main_queue->postTo casts this refcounted smart pointer to a weak
// pointer
LL::WorkQueue::ptr_t general_queue = LL::WorkQueue::getInstance("General");
llassert_always(main_queue);
llassert_always(general_queue);
auto process_params = mProcessParams;
bool posted = main_queue->postTo(
general_queue,
[process_params]() // Work done on general queue
{
return LLProcess::create(process_params);
},
[this](LLProcessPtr new_process) // Callback to main thread
mutable {
ptr_t that;
{
// this grabs a copy of the smart pointer to ourselves to ensure that we do not
// get destroyed until after this method returns.
LLCoros::LockType lock(*sInstancesMutex);
mapInstances_t::iterator it = sInstances.find(this);
if (it != sInstances.end())
that = (*it).second;
}
if (that)
{
if (new_process)
{
that->mProcess = new_process;
}
else
{
that->mProcessCreationRequested = false;
that->errorState();
}
}
});
if (!posted)
{
LL_WARNS("Plugin") << "Failed to dispath process creation to threadpool" << LL_ENDL;
if (!(mProcess = LLProcess::create(mProcessParams)))
{
mProcessCreationRequested = false;
errorState();
}
}
}
if (mProcess)
{
@ -595,15 +578,6 @@ 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);
}
}
@ -706,7 +680,6 @@ void LLPluginProcessParent::idle(void)
killSockets();
setState(STATE_DONE);
dirtyPollSet();
clearProcessCreationThread();
break;
case STATE_DONE:

View File

@ -69,11 +69,6 @@ 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
@ -168,15 +163,13 @@ private:
bool accept();
void clearProcessCreationThread();
LLSocket::ptr_t mListenSocket;
LLSocket::ptr_t mSocket;
U32 mBoundPort;
LLProcess::Params mProcessParams;
LLProcessPtr mProcess;
LLThread *pProcessCreationThread;
bool mProcessCreationRequested = false;
std::string mPluginFile;
std::string mPluginDir;