Fix crash in LLTextureFetch::getWorker upon viewer exit.
This is now necessary since the curl thread no longer syncs with the main thread: it is possible that a request finishes after a texture fetch thread was shot down but before curl was stopped, and curl calling BufferedCurlEasyRequest::processOutput while objects that the responder uses were already destructed (most notably LLTextureFetch itself).
This commit is contained in:
@@ -408,6 +408,16 @@ void initCurl(void)
|
||||
}
|
||||
}
|
||||
|
||||
// MAIN-THREAD
|
||||
void shutdownCurl(void)
|
||||
{
|
||||
using namespace AICurlPrivate;
|
||||
|
||||
DoutEntering(dc::curl, "AICurlInterface::shutdownCurl()");
|
||||
|
||||
BufferedCurlEasyRequest::shutdown();
|
||||
}
|
||||
|
||||
// MAIN-THREAD
|
||||
void cleanupCurl(void)
|
||||
{
|
||||
@@ -1293,6 +1303,8 @@ bool CurlEasyRequest::removeFromPerHostQueue(AICurlEasyRequest const& easy_reque
|
||||
static int const HTTP_REDIRECTS_DEFAULT = 10;
|
||||
|
||||
LLChannelDescriptors const BufferedCurlEasyRequest::sChannels;
|
||||
LLMutex BufferedCurlEasyRequest::sResponderCallbackMutex;
|
||||
bool BufferedCurlEasyRequest::sShuttingDown = false;
|
||||
|
||||
BufferedCurlEasyRequest::BufferedCurlEasyRequest() : mRequestTransferedBytes(0), mResponseTransferedBytes(0), mBufferEventsTarget(NULL), mStatus(HTTP_INTERNAL_ERROR_OTHER)
|
||||
{
|
||||
|
||||
@@ -163,8 +163,13 @@ void initCurl(void);
|
||||
// Called once at start of application (from LLAppViewer::initThreads), starts AICurlThread.
|
||||
void startCurlThread(U32 CurlMaxTotalConcurrentConnections, U32 CurlConcurrentConnectionsPerHost, bool NoVerifySSLCert);
|
||||
|
||||
// Called once at end of application (from newview/llappviewer.cpp by main thread),
|
||||
// with purpose to stop curl threads, free curl resources and deinitialize curl.
|
||||
// Called once at the end of application before terminating other threads (most notably the texture thread workers)
|
||||
// with the purpose to stop the curl thread from doing any call backs to running responders: the responders sometimes
|
||||
// access objects that will be shot down when bringing down other threads.
|
||||
void shutdownCurl(void);
|
||||
|
||||
// Called once at end of application (from newview/llappviewer.cpp by main thread) after all other threads have been terminated
|
||||
// with the purpose to stop the curl thread, free curl resources and deinitialize curl.
|
||||
void cleanupCurl(void);
|
||||
|
||||
// Called from indra/newview/llfloaterabout.cpp for the About floater, and
|
||||
|
||||
@@ -386,6 +386,9 @@ class BufferedCurlEasyRequest : public CurlEasyRequest {
|
||||
// Called after removed_from_multi_handle was called.
|
||||
void processOutput(void);
|
||||
|
||||
// Called just before shutting down the texture thread, to prevent responder call backs.
|
||||
static void shutdown(void);
|
||||
|
||||
// Do not write more than this amount.
|
||||
//void setBodyLimit(U32 size) { mBodyLimit = size; }
|
||||
|
||||
@@ -412,6 +415,8 @@ class BufferedCurlEasyRequest : public CurlEasyRequest {
|
||||
|
||||
public:
|
||||
static LLChannelDescriptors const sChannels; // Channel object for mInput (channel out()) and mOutput (channel in()).
|
||||
static LLMutex sResponderCallbackMutex; // Locked while calling back any overridden ResponderBase::finished and/or accessing sShuttingDown.
|
||||
static bool sShuttingDown; // If true, no additional calls to ResponderBase::finished will be made anymore.
|
||||
|
||||
private:
|
||||
// This class may only be created by constructing a ThreadSafeBufferedCurlEasyRequest.
|
||||
|
||||
@@ -1992,20 +1992,33 @@ void BufferedCurlEasyRequest::processOutput(void)
|
||||
{
|
||||
print_diagnostics(code);
|
||||
}
|
||||
if (mBufferEventsTarget)
|
||||
sResponderCallbackMutex.lock();
|
||||
if (!sShuttingDown)
|
||||
{
|
||||
// Only the responder registers for these events.
|
||||
llassert(mBufferEventsTarget == mResponder.get());
|
||||
// Allow clients to parse result codes and headers before we attempt to parse
|
||||
// the body and provide completed/result/error calls.
|
||||
mBufferEventsTarget->completed_headers(responseCode, responseReason, (code == CURLE_FAILED_INIT) ? NULL : &info);
|
||||
if (mBufferEventsTarget)
|
||||
{
|
||||
// Only the responder registers for these events.
|
||||
llassert(mBufferEventsTarget == mResponder.get());
|
||||
// Allow clients to parse result codes and headers before we attempt to parse
|
||||
// the body and provide completed/result/error calls.
|
||||
mBufferEventsTarget->completed_headers(responseCode, responseReason, (code == CURLE_FAILED_INIT) ? NULL : &info);
|
||||
}
|
||||
mResponder->finished(code, responseCode, responseReason, sChannels, mOutput);
|
||||
}
|
||||
mResponder->finished(code, responseCode, responseReason, sChannels, mOutput);
|
||||
sResponderCallbackMutex.unlock();
|
||||
mResponder = NULL;
|
||||
|
||||
resetState();
|
||||
}
|
||||
|
||||
//static
|
||||
void BufferedCurlEasyRequest::shutdown(void)
|
||||
{
|
||||
sResponderCallbackMutex.lock();
|
||||
sShuttingDown = true;
|
||||
sResponderCallbackMutex.unlock();
|
||||
}
|
||||
|
||||
void BufferedCurlEasyRequest::received_HTTP_header(void)
|
||||
{
|
||||
if (mBufferEventsTarget)
|
||||
|
||||
@@ -1758,6 +1758,8 @@ bool LLAppViewer::cleanup()
|
||||
LLViewerMedia::saveCookieFile();
|
||||
// Stop the plugin read thread if it's running.
|
||||
LLPluginProcessParent::setUseReadThread(false);
|
||||
// Stop curl responder call backs.
|
||||
AICurlInterface::shutdownCurl();
|
||||
|
||||
llinfos << "Shutting down Threads" << llendflush;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user