summaryrefslogtreecommitdiff
path: root/indra/llmessage/llcurl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmessage/llcurl.cpp')
-rw-r--r--indra/llmessage/llcurl.cpp156
1 files changed, 143 insertions, 13 deletions
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index 44330cf8ff..1a86a69a04 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -26,6 +26,7 @@
* $/LicenseInfo$
*/
+
#if LL_WINDOWS
#define SAFE_SSL 1
#elif LL_DARWIN
@@ -74,6 +75,7 @@ static const S32 MULTI_PERFORM_CALL_REPEAT = 5;
static const S32 CURL_REQUEST_TIMEOUT = 30; // seconds
static const S32 MAX_ACTIVE_REQUEST_COUNT = 100;
+static
// DEBUG //
S32 gCurlEasyCount = 0;
S32 gCurlMultiCount = 0;
@@ -85,6 +87,9 @@ std::vector<LLMutex*> LLCurl::sSSLMutex;
std::string LLCurl::sCAPath;
std::string LLCurl::sCAFile;
+bool LLCurl::sMultiThreaded = false;
+static U32 sMainThreadID = 0;
+
void check_curl_code(CURLcode code)
{
if (code != CURLE_OK)
@@ -579,11 +584,18 @@ void LLCurl::Easy::prepRequest(const std::string& url,
////////////////////////////////////////////////////////////////////////////
-class LLCurl::Multi
+class LLCurl::Multi : public LLThread
{
LOG_CLASS(Multi);
public:
-
+
+ typedef enum
+ {
+ PERFORM_STATE_READY=0,
+ PERFORM_STATE_PERFORMING=1,
+ PERFORM_STATE_COMPLETED=2
+ } ePerformState;
+
Multi();
~Multi();
@@ -593,13 +605,22 @@ public:
void removeEasy(Easy* easy);
S32 process();
- S32 perform();
+ void perform();
+ void doPerform();
+ virtual void run();
+
CURLMsg* info_read(S32* msgs_in_queue);
S32 mQueued;
S32 mErrorCount;
+ S32 mPerformState;
+
+ LLCondition* mSignal;
+ bool mQuitting;
+ bool mThreaded;
+
private:
void easyFree(Easy*);
@@ -614,9 +635,23 @@ private:
};
LLCurl::Multi::Multi()
- : mQueued(0),
- mErrorCount(0)
+ : LLThread("Curl Multi"),
+ mQueued(0),
+ mErrorCount(0),
+ mPerformState(PERFORM_STATE_READY)
{
+ mQuitting = false;
+
+ mThreaded = LLCurl::sMultiThreaded && LLThread::currentID() == sMainThreadID;
+ if (mThreaded)
+ {
+ mSignal = new LLCondition(NULL);
+ }
+ else
+ {
+ mSignal = NULL;
+ }
+
mCurlMultiHandle = curl_multi_init();
if (!mCurlMultiHandle)
{
@@ -630,6 +665,11 @@ LLCurl::Multi::Multi()
LLCurl::Multi::~Multi()
{
+ llassert(isStopped());
+
+ delete mSignal;
+ mSignal = NULL;
+
// Clean up active
for(easy_active_list_t::iterator iter = mEasyActiveList.begin();
iter != mEasyActiveList.end(); ++iter)
@@ -655,13 +695,42 @@ CURLMsg* LLCurl::Multi::info_read(S32* msgs_in_queue)
return curlmsg;
}
+void LLCurl::Multi::perform()
+{
+ if (mThreaded)
+ {
+ if (mPerformState == PERFORM_STATE_READY)
+ {
+ mSignal->signal();
+ }
+ }
+ else
+ {
+ doPerform();
+ }
+}
+
+void LLCurl::Multi::run()
+{
+ llassert(mThreaded);
+
+ while (!mQuitting)
+ {
+ mSignal->wait();
+ mPerformState = PERFORM_STATE_PERFORMING;
+ if (!mQuitting)
+ {
+ doPerform();
+ }
+ }
+}
-S32 LLCurl::Multi::perform()
+void LLCurl::Multi::doPerform()
{
S32 q = 0;
for (S32 call_count = 0;
- call_count < MULTI_PERFORM_CALL_REPEAT;
- call_count += 1)
+ call_count < MULTI_PERFORM_CALL_REPEAT;
+ call_count += 1)
{
CURLMcode code = curl_multi_perform(mCurlMultiHandle, &q);
if (CURLM_CALL_MULTI_PERFORM != code || q == 0)
@@ -672,13 +741,18 @@ S32 LLCurl::Multi::perform()
}
mQueued = q;
- return q;
+ mPerformState = PERFORM_STATE_COMPLETED;
}
S32 LLCurl::Multi::process()
{
perform();
-
+
+ if (mPerformState != PERFORM_STATE_COMPLETED)
+ {
+ return 0;
+ }
+
CURLMsg* msg;
int msgs_in_queue;
@@ -709,6 +783,8 @@ S32 LLCurl::Multi::process()
}
}
}
+
+ mPerformState = PERFORM_STATE_READY;
return processed;
}
@@ -787,6 +863,21 @@ LLCurlRequest::LLCurlRequest() :
LLCurlRequest::~LLCurlRequest()
{
llassert_always(mThreadID == LLThread::currentID());
+
+ //stop all Multi handle background threads
+ for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ++iter)
+ {
+ LLCurl::Multi* multi = *iter;
+ multi->mQuitting = true;
+ if (multi->mThreaded)
+ {
+ while (!multi->isStopped())
+ {
+ multi->mSignal->signal();
+ apr_sleep(1000);
+ }
+ }
+ }
for_each(mMultiSet.begin(), mMultiSet.end(), DeletePointer());
}
@@ -794,6 +885,10 @@ void LLCurlRequest::addMulti()
{
llassert_always(mThreadID == LLThread::currentID());
LLCurl::Multi* multi = new LLCurl::Multi();
+ if (multi->mThreaded)
+ {
+ multi->start();
+ }
mMultiSet.insert(multi);
mActiveMulti = multi;
mActiveRequestCount = 0;
@@ -923,6 +1018,16 @@ S32 LLCurlRequest::process()
if (multi != mActiveMulti && tres == 0 && multi->mQueued == 0)
{
mMultiSet.erase(curiter);
+ multi->mQuitting = true;
+ if (multi->mThreaded)
+ {
+ while (!multi->isStopped())
+ {
+ multi->mSignal->signal();
+ apr_sleep(1000);
+ }
+ }
+
delete multi;
}
}
@@ -940,6 +1045,10 @@ S32 LLCurlRequest::getQueued()
curlmulti_set_t::iterator curiter = iter++;
LLCurl::Multi* multi = *curiter;
queued += multi->mQueued;
+ if (multi->mPerformState != LLCurl::Multi::PERFORM_STATE_READY)
+ {
+ ++queued;
+ }
}
return queued;
}
@@ -953,6 +1062,10 @@ LLCurlEasyRequest::LLCurlEasyRequest()
mResultReturned(false)
{
mMulti = new LLCurl::Multi();
+ if (mMulti->mThreaded)
+ {
+ mMulti->start();
+ }
mEasy = mMulti->allocEasy();
if (mEasy)
{
@@ -963,6 +1076,15 @@ LLCurlEasyRequest::LLCurlEasyRequest()
LLCurlEasyRequest::~LLCurlEasyRequest()
{
+ mMulti->mQuitting = true;
+ if (mMulti->mThreaded)
+ {
+ while (!mMulti->isStopped())
+ {
+ mMulti->mSignal->signal();
+ apr_sleep(1000);
+ }
+ }
delete mMulti;
}
@@ -1059,14 +1181,20 @@ void LLCurlEasyRequest::requestComplete()
}
}
-S32 LLCurlEasyRequest::perform()
+void LLCurlEasyRequest::perform()
{
- return mMulti->perform();
+ mMulti->perform();
}
// Usage: Call getRestult until it returns false (no more messages)
bool LLCurlEasyRequest::getResult(CURLcode* result, LLCurl::TransferInfo* info)
{
+ if (mMulti->mPerformState != LLCurl::Multi::PERFORM_STATE_COMPLETED)
+ { //we're busy, try again later
+ return false;
+ }
+ mMulti->mPerformState = LLCurl::Multi::PERFORM_STATE_READY;
+
if (!mEasy)
{
// Special case - we failed to initialize a curl_easy (can happen if too many open files)
@@ -1151,8 +1279,10 @@ unsigned long LLCurl::ssl_thread_id(void)
}
#endif
-void LLCurl::initClass()
+void LLCurl::initClass(bool multi_threaded)
{
+ sMainThreadID = LLThread::currentID();
+ sMultiThreaded = multi_threaded;
// Do not change this "unless you are familiar with and mean to control
// internal operations of libcurl"
// - http://curl.haxx.se/libcurl/c/curl_global_init.html