WIP: Make curl thread code robust and flexible.
Conflicts: indra/llmessage/llcurl.cpp indra/llmessage/llcurl.h indra/newview/app_settings/settings.xml indra/newview/llappviewer.cpp indra/newview/llmeshrepository.cpp Resolved: indra/llmessage/llcurl.cpp: Basically removed (not used anyway) indra/llmessage/llcurl.h: Basically removed (just includes aiculr.h now) indra/newview/app_settings/settings.xml: CurlUseMultipleThreads was remvoved. CurlMaximumNumberOfHandles and CurlRequestTimeOut are still in there, but unused at the moment. indra/newview/llappviewer.cpp: CurlMaximumNumberOfHandles and CurlRequestTimeOut are unused at the moment. indra/newview/llmeshrepository.cpp: Lock mSignal always (is unlocked inside wait()). Use mSignal lock to see if we are waiting; remove mWaiting. Return false from the MeshFetch functions iff we have to retry a HTTP fetch. Catch the error exception thrown by getByteRange instead of using it's return value (always returns true anyway).
This commit is contained in:
@@ -5,7 +5,7 @@ project(statemachine)
|
||||
include(00-Common)
|
||||
include(LLCommon)
|
||||
include(LLPlugin)
|
||||
include(LLMessage) # This is needed by LLPlugin.
|
||||
include(LLMessage)
|
||||
include(LLMath)
|
||||
include(LLVFS)
|
||||
include(LLXML)
|
||||
@@ -38,6 +38,7 @@ include_directories(
|
||||
|
||||
set(statemachine_SOURCE_FILES
|
||||
aistatemachine.cpp
|
||||
aicurleasyrequeststatemachine.cpp
|
||||
aifilepicker.cpp
|
||||
aifetchinventoryfolder.cpp
|
||||
aievent.cpp
|
||||
@@ -47,6 +48,7 @@ set(statemachine_SOURCE_FILES
|
||||
set(statemachine_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
aistatemachine.h
|
||||
aicurleasyrequeststatemachine.h
|
||||
aifilepicker.h
|
||||
aidirpicker.h
|
||||
aifetchinventoryfolder.h
|
||||
|
||||
152
indra/newview/statemachine/aicurleasyrequeststatemachine.cpp
Normal file
152
indra/newview/statemachine/aicurleasyrequeststatemachine.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* @file aicurleasyrequeststatemachine.cpp
|
||||
* @brief Implementation of AICurlEasyRequestStateMachine
|
||||
*
|
||||
* Copyright (c) 2012, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 06/05/2012
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "aicurleasyrequeststatemachine.h"
|
||||
|
||||
enum curleasyrequeststatemachine_state_type {
|
||||
AICurlEasyRequestStateMachine_addRequest = AIStateMachine::max_state,
|
||||
AICurlEasyRequestStateMachine_waitAdded,
|
||||
AICurlEasyRequestStateMachine_waitFinished,
|
||||
AICurlEasyRequestStateMachine_finished
|
||||
};
|
||||
|
||||
char const* AICurlEasyRequestStateMachine::state_str_impl(state_type run_state) const
|
||||
{
|
||||
switch(run_state)
|
||||
{
|
||||
AI_CASE_RETURN(AICurlEasyRequestStateMachine_addRequest);
|
||||
AI_CASE_RETURN(AICurlEasyRequestStateMachine_waitAdded);
|
||||
AI_CASE_RETURN(AICurlEasyRequestStateMachine_waitFinished);
|
||||
AI_CASE_RETURN(AICurlEasyRequestStateMachine_finished);
|
||||
}
|
||||
return "UNKNOWN STATE";
|
||||
}
|
||||
|
||||
void AICurlEasyRequestStateMachine::initialize_impl(void)
|
||||
{
|
||||
{
|
||||
AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest);
|
||||
llassert(curlEasyRequest_w->is_finalized()); // Call finalizeRequest(url) before calling run().
|
||||
curlEasyRequest_w->send_events_to(this);
|
||||
}
|
||||
set_state(AICurlEasyRequestStateMachine_addRequest);
|
||||
}
|
||||
|
||||
// CURL-THREAD
|
||||
void AICurlEasyRequestStateMachine::added_to_multi_handle(AICurlEasyRequest_wat&)
|
||||
{
|
||||
set_state(AICurlEasyRequestStateMachine_waitFinished);
|
||||
}
|
||||
|
||||
// CURL-THREAD
|
||||
void AICurlEasyRequestStateMachine::finished(AICurlEasyRequest_wat&)
|
||||
{
|
||||
}
|
||||
|
||||
// CURL-THREAD
|
||||
void AICurlEasyRequestStateMachine::removed_from_multi_handle(AICurlEasyRequest_wat&)
|
||||
{
|
||||
set_state(AICurlEasyRequestStateMachine_finished);
|
||||
}
|
||||
|
||||
void AICurlEasyRequestStateMachine::multiplex_impl(void)
|
||||
{
|
||||
switch (mRunState)
|
||||
{
|
||||
case AICurlEasyRequestStateMachine_addRequest:
|
||||
{
|
||||
mCurlEasyRequest.addRequest();
|
||||
set_state(AICurlEasyRequestStateMachine_waitAdded);
|
||||
}
|
||||
case AICurlEasyRequestStateMachine_waitAdded:
|
||||
{
|
||||
idle(); // Wait till AICurlEasyRequestStateMachine::added_to_multi_handle() is called.
|
||||
break;
|
||||
}
|
||||
case AICurlEasyRequestStateMachine_waitFinished:
|
||||
{
|
||||
idle(); // Wait till AICurlEasyRequestStateMachine::finished() is called.
|
||||
break;
|
||||
}
|
||||
case AICurlEasyRequestStateMachine_finished:
|
||||
{
|
||||
if (mBuffered)
|
||||
{
|
||||
AICurlEasyRequest_wat easy_request_w(*mCurlEasyRequest);
|
||||
AICurlResponderBuffer_wat buffered_easy_request_w(*mCurlEasyRequest);
|
||||
buffered_easy_request_w->processOutput(easy_request_w);
|
||||
}
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AICurlEasyRequestStateMachine::abort_impl(void)
|
||||
{
|
||||
Dout(dc::curl, "AICurlEasyRequestStateMachine::abort_impl called for = " << (void*)mCurlEasyRequest.get());
|
||||
// We must first revoke the events, or the curl thread might change mRunState still.
|
||||
{
|
||||
AICurlEasyRequest_wat curl_easy_request_w(*mCurlEasyRequest);
|
||||
curl_easy_request_w->send_events_to(NULL);
|
||||
curl_easy_request_w->revokeCallbacks();
|
||||
}
|
||||
if (mRunState >= AICurlEasyRequestStateMachine_waitAdded && mRunState < AICurlEasyRequestStateMachine_finished)
|
||||
{
|
||||
// Revert call to addRequest().
|
||||
// Note that it's safe to call this even if the curl thread already removed it, or will removes it
|
||||
// after we called this, before processing the remove command; only the curl thread calls
|
||||
// MultiHandle::remove_easy_request, which is a no-op when called twice for the same easy request.
|
||||
mCurlEasyRequest.removeRequest();
|
||||
}
|
||||
}
|
||||
|
||||
void AICurlEasyRequestStateMachine::finish_impl(void)
|
||||
{
|
||||
Dout(dc::curl, "AICurlEasyRequestStateMachine::finish_impl called for = " << (void*)mCurlEasyRequest.get());
|
||||
if (!aborted())
|
||||
{
|
||||
AICurlEasyRequest_wat curl_easy_request_w(*mCurlEasyRequest);
|
||||
curl_easy_request_w->send_events_to(NULL);
|
||||
curl_easy_request_w->revokeCallbacks();
|
||||
}
|
||||
}
|
||||
|
||||
AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(bool buffered) : mBuffered(buffered), mCurlEasyRequest(buffered)
|
||||
{
|
||||
Dout(dc::statemachine, "Calling AICurlEasyRequestStateMachine(" << (buffered ? "true" : "false") << ") [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]");
|
||||
}
|
||||
|
||||
AICurlEasyRequestStateMachine::~AICurlEasyRequestStateMachine()
|
||||
{
|
||||
Dout(dc::statemachine, "Calling ~AICurlEasyRequestStateMachine() [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]");
|
||||
}
|
||||
|
||||
96
indra/newview/statemachine/aicurleasyrequeststatemachine.h
Normal file
96
indra/newview/statemachine/aicurleasyrequeststatemachine.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* @file aicurleasyrequest.h
|
||||
* @brief Perform a curl easy request.
|
||||
*
|
||||
* Copyright (c) 2012, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 06/05/2012
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AICURLEASYREQUEST_H
|
||||
#define AICURLEASYREQUEST_H
|
||||
|
||||
#include "aistatemachine.h"
|
||||
#include "aicurl.h"
|
||||
|
||||
// A curl easy request state machine.
|
||||
//
|
||||
// Before calling cersm.run() initialize the object (cersm) as follows:
|
||||
//
|
||||
// AICurlEasyRequest_wat cersm_w(cersm);
|
||||
// cersm_w->setopt(...); // etc, see the interface of AICurlPrivate::CurlEasyRequest and it's base class AICurlPrivate::CurlEasyHandle.
|
||||
//
|
||||
// When the state machine finishes, call aborted() to check
|
||||
// whether or not the statemachine succeeded in fetching
|
||||
// the URL or not.
|
||||
//
|
||||
// Objects of this type can be reused multiple times, see
|
||||
// also the documentation of AIStateMachine.
|
||||
//
|
||||
// Construction of a AICurlEasyRequestStateMachine might throw AICurlNoEasyHandle.
|
||||
class AICurlEasyRequestStateMachine : public AIStateMachine, public AICurlEasyHandleEvents {
|
||||
public:
|
||||
AICurlEasyRequestStateMachine(bool buffered);
|
||||
|
||||
// Transparent access.
|
||||
AICurlEasyRequest mCurlEasyRequest;
|
||||
|
||||
private:
|
||||
bool mBuffered; // Argument used for construction of mCurlEasyRequest.
|
||||
|
||||
protected:
|
||||
// AICurlEasyRequest Events.
|
||||
|
||||
// Called when this curl easy handle was added to a multi handle.
|
||||
/*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat&);
|
||||
|
||||
// Called when this curl easy handle finished processing (right before it is removed from the multi handle).
|
||||
/*virtual*/ void finished(AICurlEasyRequest_wat&);
|
||||
|
||||
// Called after this curl easy handle was removed from a multi handle.
|
||||
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat&);
|
||||
|
||||
protected:
|
||||
// AIStateMachine implementations.
|
||||
|
||||
// Call finish() (or abort()), not delete.
|
||||
/*virtual*/ ~AICurlEasyRequestStateMachine();
|
||||
|
||||
// Handle initializing the object.
|
||||
/*virtual*/ void initialize_impl(void);
|
||||
|
||||
// Handle mRunState.
|
||||
/*virtual*/ void multiplex_impl(void);
|
||||
|
||||
// Handle aborting from current bs_run state.
|
||||
/*virtual*/ void abort_impl(void);
|
||||
|
||||
// Handle cleaning up from initialization (or post abort) state.
|
||||
/*virtual*/ void finish_impl(void);
|
||||
|
||||
// Implemenation of state_str for run states.
|
||||
/*virtual*/ char const* state_str_impl(state_type run_state) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -237,7 +237,7 @@ class AIStateMachine {
|
||||
|
||||
protected:
|
||||
//! The user should call 'kill()', not delete a AIStateMachine (derived) directly.
|
||||
virtual ~AIStateMachine() { llassert(mState == bs_killed && mActive == as_idle); }
|
||||
virtual ~AIStateMachine() { llassert((mState == bs_killed && mActive == as_idle) || mState == bs_initialize); }
|
||||
|
||||
public:
|
||||
//! Halt the state machine until cont() is called.
|
||||
|
||||
Reference in New Issue
Block a user