Merge branch 'master' of https://bitbucket.org/SingularityViewer/singularityviewer into Frosting
Conflicts: indra/newview/linux_tools/wrapper.sh
This commit is contained in:
@@ -30,8 +30,6 @@ include(BuildVersion)
|
|||||||
|
|
||||||
include(UnixInstall)
|
include(UnixInstall)
|
||||||
|
|
||||||
set (DISABLE_FATAL_WARNINGS CACHE BOOL TRUE)
|
|
||||||
|
|
||||||
if (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
|
if (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
|
||||||
set(CMAKE_BUILD_TYPE Release CACHE STRING
|
set(CMAKE_BUILD_TYPE Release CACHE STRING
|
||||||
"Build type. One of: Debug Release RelWithDebInfo" FORCE)
|
"Build type. One of: Debug Release RelWithDebInfo" FORCE)
|
||||||
|
|||||||
@@ -146,12 +146,15 @@ class AIStateMachine : public LLThreadSafeRefCount
|
|||||||
typedef AIAccessConst<multiplex_state_type> multiplex_state_type_crat;
|
typedef AIAccessConst<multiplex_state_type> multiplex_state_type_crat;
|
||||||
typedef AIAccess<multiplex_state_type> multiplex_state_type_rat;
|
typedef AIAccess<multiplex_state_type> multiplex_state_type_rat;
|
||||||
typedef AIAccess<multiplex_state_type> multiplex_state_type_wat;
|
typedef AIAccess<multiplex_state_type> multiplex_state_type_wat;
|
||||||
|
|
||||||
|
protected:
|
||||||
// Sub state.
|
// Sub state.
|
||||||
AIThreadSafeSimpleDC<sub_state_type> mSubState;
|
AIThreadSafeSimpleDC<sub_state_type> mSubState;
|
||||||
typedef AIAccessConst<sub_state_type> sub_state_type_crat;
|
typedef AIAccessConst<sub_state_type> sub_state_type_crat;
|
||||||
typedef AIAccess<sub_state_type> sub_state_type_rat;
|
typedef AIAccess<sub_state_type> sub_state_type_rat;
|
||||||
typedef AIAccess<sub_state_type> sub_state_type_wat;
|
typedef AIAccess<sub_state_type> sub_state_type_wat;
|
||||||
|
|
||||||
|
private:
|
||||||
// Mutex protecting everything below and making sure only one thread runs the state machine at a time.
|
// Mutex protecting everything below and making sure only one thread runs the state machine at a time.
|
||||||
LLMutex mMultiplexMutex;
|
LLMutex mMultiplexMutex;
|
||||||
// Mutex that is locked while calling *_impl() functions and the call back.
|
// Mutex that is locked while calling *_impl() functions and the call back.
|
||||||
|
|||||||
@@ -33,12 +33,12 @@
|
|||||||
|
|
||||||
class AIStateMachineThreadBase::Thread : public LLThread {
|
class AIStateMachineThreadBase::Thread : public LLThread {
|
||||||
private:
|
private:
|
||||||
LLPointer<AIThreadImpl> mImpl;
|
LLPointer<AIStateMachineThreadBase> mImpl;
|
||||||
bool mNeedCleanup;
|
bool mNeedCleanup;
|
||||||
public:
|
public:
|
||||||
Thread(AIThreadImpl* impl) :
|
Thread(AIStateMachineThreadBase* impl) :
|
||||||
#ifdef LL_DEBUG
|
#ifdef LL_DEBUG
|
||||||
LLThread(impl->getName()),
|
LLThread(impl->impl().getName()),
|
||||||
#else
|
#else
|
||||||
LLThread("AIStateMachineThreadBase::Thread"),
|
LLThread("AIStateMachineThreadBase::Thread"),
|
||||||
#endif
|
#endif
|
||||||
@@ -46,7 +46,7 @@ class AIStateMachineThreadBase::Thread : public LLThread {
|
|||||||
protected:
|
protected:
|
||||||
/*virtual*/ void run(void)
|
/*virtual*/ void run(void)
|
||||||
{
|
{
|
||||||
mNeedCleanup = mImpl->thread_done(mImpl->run());
|
mNeedCleanup = mImpl->impl().thread_done(mImpl->impl().run());
|
||||||
}
|
}
|
||||||
/*virtual*/ void terminated(void)
|
/*virtual*/ void terminated(void)
|
||||||
{
|
{
|
||||||
@@ -65,7 +65,7 @@ class AIStateMachineThreadBase::Thread : public LLThread {
|
|||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
// TODO: Implement a thread pool. For now, just create a new one every time.
|
// TODO: Implement a thread pool. For now, just create a new one every time.
|
||||||
static Thread* allocate(AIThreadImpl* impl) { return new Thread(impl); }
|
static Thread* allocate(AIStateMachineThreadBase* impl) { return new Thread(impl); }
|
||||||
static void completed(Thread* threadp) { delete threadp; }
|
static void completed(Thread* threadp) { delete threadp; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ void AIStateMachineThreadBase::multiplex_impl(state_type run_state)
|
|||||||
switch(run_state)
|
switch(run_state)
|
||||||
{
|
{
|
||||||
case start_thread:
|
case start_thread:
|
||||||
mThread = Thread::allocate(mImpl);
|
mThread = Thread::allocate(this);
|
||||||
// Set next state.
|
// Set next state.
|
||||||
set_state(wait_stopped);
|
set_state(wait_stopped);
|
||||||
idle(); // Wait till the thread returns.
|
idle(); // Wait till the thread returns.
|
||||||
@@ -124,10 +124,10 @@ void AIStateMachineThreadBase::abort_impl(void)
|
|||||||
{
|
{
|
||||||
if (mThread)
|
if (mThread)
|
||||||
{
|
{
|
||||||
// If this AIStateMachineThreadBase still exists then the first base class of
|
// If this AIStateMachineThreadBase still exists then the AIStateMachineThread<THREAD_IMPL>
|
||||||
// AIStateMachineThread<THREAD_IMPL>, LLPointer<THREAD_IMPL>, also still exists
|
// that is derived from it still exists and therefore its member THREAD_IMPL also still exists
|
||||||
// and therefore mImpl is valid.
|
// and therefore impl() is valid.
|
||||||
bool need_cleanup = mImpl->state_machine_done(mThread); // Signal the fact that we aborted.
|
bool need_cleanup = impl().state_machine_done(mThread); // Signal the fact that we aborted.
|
||||||
if (need_cleanup)
|
if (need_cleanup)
|
||||||
{
|
{
|
||||||
// This is an unlikely race condition. We have been aborted by our parent,
|
// This is an unlikely race condition. We have been aborted by our parent,
|
||||||
|
|||||||
@@ -73,11 +73,11 @@ enum hello_world_state_type {
|
|||||||
// The statemachine class (this is almost a template).
|
// The statemachine class (this is almost a template).
|
||||||
class HelloWorld : public AIStateMachine {
|
class HelloWorld : public AIStateMachine {
|
||||||
private:
|
private:
|
||||||
AIStateMachineThread<HelloWorldThread> mHelloWorld;
|
LLPointer<AIStateMachineThread<HelloWorldThread> > mHelloWorld;
|
||||||
bool mErr;
|
bool mErr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HelloWorld() : mErr(false) { }
|
HelloWorld() : mHelloWorld(new AIStateMachineThread<HelloWorldThread>), mErr(false) { }
|
||||||
|
|
||||||
// Print to stderr or stdout?
|
// Print to stderr or stdout?
|
||||||
void init(bool err) { mErr = err; }
|
void init(bool err) { mErr = err; }
|
||||||
@@ -108,7 +108,7 @@ class HelloWorld : public AIStateMachine {
|
|||||||
|
|
||||||
void HelloWorld::initialize_impl(void)
|
void HelloWorld::initialize_impl(void)
|
||||||
{
|
{
|
||||||
mHelloWorld->init(mErr); // Initialize the thread object.
|
mHelloWorld->thread_impl().init(mErr); // Initialize the thread object.
|
||||||
set_state(HelloWorld_start);
|
set_state(HelloWorld_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,14 +118,14 @@ void HelloWorld::multiplex_impl(state_type run_state)
|
|||||||
{
|
{
|
||||||
case HelloWorld_start:
|
case HelloWorld_start:
|
||||||
{
|
{
|
||||||
mHelloWorld.run(this, HelloWorld_done); // Run HelloWorldThread and set the state of 'this' to HelloWorld_done when finished.
|
mHelloWorld->run(this, HelloWorld_done); // Run HelloWorldThread and set the state of 'this' to HelloWorld_done when finished.
|
||||||
idle(HelloWorld_start); // Always go idle after starting a thread!
|
idle(HelloWorld_start); // Always go idle after starting a thread!
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HelloWorld_done:
|
case HelloWorld_done:
|
||||||
{
|
{
|
||||||
// We're done. Lets also abort when the thread reported no success.
|
// We're done. Lets also abort when the thread reported no success.
|
||||||
if (mHelloWorld->successful()) // Read output/result of thread object.
|
if (mHelloWorld->thread_impl().successful()) // Read output/result of thread object.
|
||||||
finish();
|
finish();
|
||||||
else
|
else
|
||||||
abort();
|
abort();
|
||||||
@@ -139,9 +139,9 @@ void HelloWorld::multiplex_impl(state_type run_state)
|
|||||||
class AIStateMachineThreadBase;
|
class AIStateMachineThreadBase;
|
||||||
|
|
||||||
// Derive from this to implement the code that must run in another thread.
|
// Derive from this to implement the code that must run in another thread.
|
||||||
class AIThreadImpl : public LLThreadSafeRefCount {
|
class AIThreadImpl {
|
||||||
private:
|
private:
|
||||||
template<typename THREAD_IMPL> friend struct AIStateMachineThread;
|
template<typename THREAD_IMPL> friend class AIStateMachineThread;
|
||||||
typedef AIAccess<AIStateMachineThreadBase*> StateMachineThread_wat;
|
typedef AIAccess<AIStateMachineThreadBase*> StateMachineThread_wat;
|
||||||
AIThreadSafeSimpleDC<AIStateMachineThreadBase*> mStateMachineThread;
|
AIThreadSafeSimpleDC<AIStateMachineThreadBase*> mStateMachineThread;
|
||||||
|
|
||||||
@@ -158,6 +158,9 @@ class AIThreadImpl : public LLThreadSafeRefCount {
|
|||||||
public:
|
public:
|
||||||
char const* getName(void) const { return mName; }
|
char const* getName(void) const { return mName; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~AIThreadImpl() { }
|
||||||
};
|
};
|
||||||
|
|
||||||
// The base class for statemachine threads.
|
// The base class for statemachine threads.
|
||||||
@@ -178,7 +181,7 @@ class AIStateMachineThreadBase : public AIStateMachine {
|
|||||||
static state_type const max_state = wait_stopped + 1;
|
static state_type const max_state = wait_stopped + 1;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AIStateMachineThreadBase(AIThreadImpl* impl) : mImpl(impl) { ref(); /* Never call delete */ }
|
AIStateMachineThreadBase(void) { }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Handle initializing the object.
|
// Handle initializing the object.
|
||||||
@@ -193,9 +196,11 @@ class AIStateMachineThreadBase : public AIStateMachine {
|
|||||||
// Implemenation of state_str for run states.
|
// Implemenation of state_str for run states.
|
||||||
/*virtual*/ char const* state_str_impl(state_type run_state) const;
|
/*virtual*/ char const* state_str_impl(state_type run_state) const;
|
||||||
|
|
||||||
|
// Returns a reference to the implementation code that needs to be run in the thread.
|
||||||
|
virtual AIThreadImpl& impl(void) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Thread* mThread; // The thread that the code is run in.
|
Thread* mThread; // The thread that the code is run in.
|
||||||
AIThreadImpl* mImpl; // Pointer to the implementation code that needs to be run in the thread.
|
|
||||||
bool mAbort; // (Inverse of) return value of AIThreadImpl::run(). Only valid in state wait_stopped.
|
bool mAbort; // (Inverse of) return value of AIThreadImpl::run(). Only valid in state wait_stopped.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -206,14 +211,22 @@ class AIStateMachineThreadBase : public AIStateMachine {
|
|||||||
// The state machine that runs T::run() in a thread.
|
// The state machine that runs T::run() in a thread.
|
||||||
// THREAD_IMPL Must be derived from AIThreadImpl.
|
// THREAD_IMPL Must be derived from AIThreadImpl.
|
||||||
template<typename THREAD_IMPL>
|
template<typename THREAD_IMPL>
|
||||||
struct AIStateMachineThread : public LLPointer<THREAD_IMPL>, public AIStateMachineThreadBase {
|
class AIStateMachineThread : public AIStateMachineThreadBase {
|
||||||
// Constructor.
|
private:
|
||||||
AIStateMachineThread(void) :
|
THREAD_IMPL mThreadImpl;
|
||||||
LLPointer<THREAD_IMPL>(new THREAD_IMPL),
|
|
||||||
AIStateMachineThreadBase(LLPointer<THREAD_IMPL>::get())
|
public:
|
||||||
{
|
// Constructor.
|
||||||
*AIThreadImpl::StateMachineThread_wat(static_cast<AIThreadImpl*>(LLPointer<THREAD_IMPL>::get())->mStateMachineThread) = this;
|
AIStateMachineThread(void)
|
||||||
}
|
{
|
||||||
|
*AIThreadImpl::StateMachineThread_wat(mThreadImpl.mStateMachineThread) = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accessor.
|
||||||
|
THREAD_IMPL& thread_impl(void) { return mThreadImpl; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*virtual*/ AIThreadImpl& impl(void) { return mThreadImpl; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -270,10 +270,10 @@ endif (DARWIN)
|
|||||||
|
|
||||||
if (LINUX OR DARWIN)
|
if (LINUX OR DARWIN)
|
||||||
if(${CMAKE_C_COMPILER} MATCHES "gcc*")
|
if(${CMAKE_C_COMPILER} MATCHES "gcc*")
|
||||||
set(UNIX_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs")
|
set(UNIX_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs")
|
||||||
set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual")
|
set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual")
|
||||||
elseif(${CMAKE_C_COMPILER} MATCHES "clang*")
|
elseif(${CMAKE_C_COMPILER} MATCHES "clang*")
|
||||||
set(UNIX_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-tautological-compare -Wno-char-subscripts -Wno-gnu -Wno-logical-op-parentheses -Wno-non-virtual-dtor ")
|
set(UNIX_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-tautological-compare -Wno-char-subscripts -Wno-gnu -Wno-logical-op-parentheses -Wno-non-virtual-dtor")
|
||||||
set(UNIX_WARNINGS "${UNIX_WARNINGS} -Woverloaded-virtual -Wno-parentheses-equality -Wno-reorder -Wno-unused-function -Wno-unused-value -Wno-unused-variable")
|
set(UNIX_WARNINGS "${UNIX_WARNINGS} -Woverloaded-virtual -Wno-parentheses-equality -Wno-reorder -Wno-unused-function -Wno-unused-value -Wno-unused-variable")
|
||||||
set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS}")
|
set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS}")
|
||||||
elseif(${CMAKE_C_COMPILER} MATCHES "icc")
|
elseif(${CMAKE_C_COMPILER} MATCHES "icc")
|
||||||
@@ -281,8 +281,11 @@ if (LINUX OR DARWIN)
|
|||||||
set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS}")
|
set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Use -DDISABLE_FATAL_WARNINGS:BOOL=FALSE during configuration to enable fatal warnings.
|
||||||
|
set(DISABLE_FATAL_WARNINGS TRUE CACHE BOOL "Set this to FALSE to enable fatal warnings.")
|
||||||
if (NOT DISABLE_FATAL_WARNINGS)
|
if (NOT DISABLE_FATAL_WARNINGS)
|
||||||
set(UNIX_WARNINGS "${UNIX_WARNINGS} -Werror")
|
set(UNIX_WARNINGS "${UNIX_WARNINGS} -Werror")
|
||||||
|
set(UNIX_CXX_WARNINGS "${UNIX_CXX_WARNINGS} -Werror")
|
||||||
endif (NOT DISABLE_FATAL_WARNINGS)
|
endif (NOT DISABLE_FATAL_WARNINGS)
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS "${UNIX_WARNINGS} ${CMAKE_C_FLAGS}")
|
set(CMAKE_C_FLAGS "${UNIX_WARNINGS} ${CMAKE_C_FLAGS}")
|
||||||
@@ -333,4 +336,6 @@ MARK_AS_ADVANCED(
|
|||||||
CMAKE_SHARED_LINKER_FLAGS_RELEASE
|
CMAKE_SHARED_LINKER_FLAGS_RELEASE
|
||||||
)
|
)
|
||||||
|
|
||||||
|
include(GooglePerfTools)
|
||||||
|
|
||||||
endif(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED)
|
endif(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# -*- cmake -*-
|
# -*- cmake -*-
|
||||||
|
|
||||||
include(Prebuilt)
|
include(Prebuilt)
|
||||||
|
|
||||||
if(WORD_SIZE EQUAL 64)
|
if(WORD_SIZE EQUAL 64)
|
||||||
@@ -47,9 +48,14 @@ else (USE_GOOGLE_PERFTOOLS)
|
|||||||
endif (USE_GOOGLE_PERFTOOLS)
|
endif (USE_GOOGLE_PERFTOOLS)
|
||||||
|
|
||||||
if (NOT(DISABLE_TCMALLOC OR USE_GOOGLE_PERFTOOLS OR STANDALONE))
|
if (NOT(DISABLE_TCMALLOC OR USE_GOOGLE_PERFTOOLS OR STANDALONE))
|
||||||
message(STATUS "Building with Google TCMalloc")
|
if (NOT STATUS_Building_with_Google_TCMalloc)
|
||||||
set(TCMALLOC_FLAG -DLL_USE_TCMALLOC=1)
|
message(STATUS "Building with Google TCMalloc")
|
||||||
include_directories(${GOOGLE_PERFTOOLS_INCLUDE_DIR})
|
set(STATUS_Building_with_Google_TCMalloc true PARENT_SCOPE)
|
||||||
set(GOOGLE_PERFTOOLS_LIBRARIES ${TCMALLOC_LIBRARIES})
|
endif (NOT STATUS_Building_with_Google_TCMalloc)
|
||||||
|
set(TCMALLOC_FLAG -DLL_USE_TCMALLOC=1)
|
||||||
|
include_directories(${GOOGLE_PERFTOOLS_INCLUDE_DIR})
|
||||||
|
set(GOOGLE_PERFTOOLS_LIBRARIES ${TCMALLOC_LIBRARIES})
|
||||||
set(GOOGLE_PERFTOOLS_LINKER_FLAGS ${TCMALLOC_LINKER_FLAGS})
|
set(GOOGLE_PERFTOOLS_LINKER_FLAGS ${TCMALLOC_LINKER_FLAGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_definitions(${TCMALLOC_FLAG})
|
||||||
@@ -45,7 +45,6 @@ import commands
|
|||||||
class CommandError(Exception):
|
class CommandError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def mkdir(path):
|
def mkdir(path):
|
||||||
try:
|
try:
|
||||||
os.mkdir(path)
|
os.mkdir(path)
|
||||||
@@ -54,15 +53,19 @@ def mkdir(path):
|
|||||||
if err.errno != errno.EEXIST or not os.path.isdir(path):
|
if err.errno != errno.EEXIST or not os.path.isdir(path):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def getcwd():
|
def prettyprint_path_for_cmake(path):
|
||||||
cwd = os.getcwd()
|
if 'a' <= path[0] <= 'z' and path[1] == ':':
|
||||||
if 'a' <= cwd[0] <= 'z' and cwd[1] == ':':
|
|
||||||
# CMake wants DOS drive letters to be in uppercase. The above
|
# CMake wants DOS drive letters to be in uppercase. The above
|
||||||
# condition never asserts on platforms whose full path names
|
# condition never asserts on platforms whose full path names
|
||||||
# always begin with a slash, so we don't need to test whether
|
# always begin with a slash, so we don't need to test whether
|
||||||
# we are running on Windows.
|
# we are running on Windows.
|
||||||
cwd = cwd[0].upper() + cwd[1:]
|
path = path[0].upper() + path[1:]
|
||||||
return cwd
|
return path
|
||||||
|
|
||||||
|
def getcwd():
|
||||||
|
return prettyprint_path_for_cmake(os.getcwd())
|
||||||
|
|
||||||
|
source_indra = prettyprint_path_for_cmake(os.path.dirname(os.path.realpath(__file__)))
|
||||||
|
|
||||||
def quote(opts):
|
def quote(opts):
|
||||||
return '"' + '" "'.join([ opt.replace('"', '') for opt in opts ]) + '"'
|
return '"' + '" "'.join([ opt.replace('"', '') for opt in opts ]) + '"'
|
||||||
@@ -150,7 +153,7 @@ class PlatformSetup(object):
|
|||||||
simple = False
|
simple = False
|
||||||
try:
|
try:
|
||||||
os.chdir(d)
|
os.chdir(d)
|
||||||
cmd = self.cmake_commandline(cwd, d, args, simple)
|
cmd = self.cmake_commandline(source_indra, d, args, simple)
|
||||||
print 'Running %r in %r' % (cmd, d)
|
print 'Running %r in %r' % (cmd, d)
|
||||||
self.run(cmd, 'cmake')
|
self.run(cmd, 'cmake')
|
||||||
finally:
|
finally:
|
||||||
@@ -270,18 +273,9 @@ class LinuxSetup(UnixSetup):
|
|||||||
return 'linux'
|
return 'linux'
|
||||||
|
|
||||||
def build_dirs(self):
|
def build_dirs(self):
|
||||||
# Only build the server code if we have it.
|
|
||||||
platform_build = '%s-%s' % (self.platform(), self.build_type.lower())
|
platform_build = '%s-%s' % (self.platform(), self.build_type.lower())
|
||||||
|
|
||||||
if self.arch() == 'i686' and self.is_internal_tree():
|
return ['viewer-' + platform_build]
|
||||||
return ['viewer-' + platform_build, 'server-' + platform_build]
|
|
||||||
elif self.arch() == 'x86_64' and self.is_internal_tree():
|
|
||||||
# the viewer does not build in 64bit -- kdu5 issues
|
|
||||||
# we can either use openjpeg, or overhaul our viewer to handle kdu5 or higher
|
|
||||||
# doug knows about kdu issues
|
|
||||||
return ['server-' + platform_build]
|
|
||||||
else:
|
|
||||||
return ['viewer-' + platform_build]
|
|
||||||
|
|
||||||
def cmake_commandline(self, src_dir, build_dir, opts, simple):
|
def cmake_commandline(self, src_dir, build_dir, opts, simple):
|
||||||
args = dict(
|
args = dict(
|
||||||
@@ -293,31 +287,11 @@ class LinuxSetup(UnixSetup):
|
|||||||
type=self.build_type.upper(),
|
type=self.build_type.upper(),
|
||||||
project_name=self.project_name,
|
project_name=self.project_name,
|
||||||
word_size=self.word_size,
|
word_size=self.word_size,
|
||||||
|
cxx="g++"
|
||||||
)
|
)
|
||||||
if not self.is_internal_tree():
|
|
||||||
args.update({'cxx':'g++', 'server':'OFF', 'viewer':'ON'})
|
|
||||||
else:
|
|
||||||
if self.distcc:
|
|
||||||
distcc = self.find_in_path('distcc')
|
|
||||||
baseonly = True
|
|
||||||
else:
|
|
||||||
distcc = []
|
|
||||||
baseonly = False
|
|
||||||
if 'server' in build_dir:
|
|
||||||
gcc = distcc + self.find_in_path(
|
|
||||||
self.debian_sarge and 'g++-3.3' or 'g++-4.1',
|
|
||||||
'g++', baseonly)
|
|
||||||
args.update({'cxx': ' '.join(gcc), 'server': 'ON',
|
|
||||||
'viewer': 'OFF'})
|
|
||||||
else:
|
|
||||||
gcc41 = distcc + self.find_in_path('g++-4.1', 'g++', baseonly)
|
|
||||||
args.update({'cxx': ' '.join(gcc41),
|
|
||||||
'server': 'OFF',
|
|
||||||
'viewer': 'ON'})
|
|
||||||
cmd = (('cmake -DCMAKE_BUILD_TYPE:STRING=%(type)s '
|
cmd = (('cmake -DCMAKE_BUILD_TYPE:STRING=%(type)s '
|
||||||
'-G %(generator)r -DSERVER:BOOL=%(server)s '
|
'-G %(generator)r -DSTANDALONE:BOOL=%(standalone)s '
|
||||||
'-DVIEWER:BOOL=%(viewer)s -DSTANDALONE:BOOL=%(standalone)s '
|
|
||||||
'-DUNATTENDED:BOOL=%(unattended)s '
|
|
||||||
'-DWORD_SIZE:STRING=%(word_size)s '
|
'-DWORD_SIZE:STRING=%(word_size)s '
|
||||||
'-DROOT_PROJECT_NAME:STRING=%(project_name)s '
|
'-DROOT_PROJECT_NAME:STRING=%(project_name)s '
|
||||||
'%(opts)s %(dir)r')
|
'%(opts)s %(dir)r')
|
||||||
|
|||||||
@@ -1,13 +1,39 @@
|
|||||||
cmake_minimum_required(VERSION 2.6.4)
|
# -*- cmake -*-
|
||||||
|
|
||||||
project(libhacd CXX C)
|
project(libhacd)
|
||||||
include(00-Common)
|
include(00-Common)
|
||||||
|
|
||||||
file (GLOB SOURCE_FILES *.cpp )
|
set(libhacd_SOURCE_FILES
|
||||||
file (GLOB INCLUDE_FILES *.h )
|
hacdGraph.cpp
|
||||||
|
hacdHACD.cpp
|
||||||
|
hacdICHull.cpp
|
||||||
|
hacdManifoldMesh.cpp
|
||||||
|
hacdMeshDecimator.cpp
|
||||||
|
hacdMicroAllocator.cpp
|
||||||
|
hacdRaycastMesh.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(libhacd_HEADER_FILES
|
||||||
|
hacdCircularList.h
|
||||||
|
hacdCircularList.inl
|
||||||
|
hacdGraph.h
|
||||||
|
hacdHACD.h
|
||||||
|
hacdICHull.h
|
||||||
|
hacdManifoldMesh.h
|
||||||
|
hacdMeshDecimator.h
|
||||||
|
hacdMicroAllocator.h
|
||||||
|
hacdRaycastMesh.h
|
||||||
|
hacdSArray.h
|
||||||
|
hacdVector.h
|
||||||
|
hacdVector.inl
|
||||||
|
hacdVersion.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set_source_files_properties(${libhacd_HEADER_FILES}
|
||||||
|
PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||||
|
|
||||||
IF(WINDOWS)
|
IF(WINDOWS)
|
||||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||||
ENDIF(WINDOWS)
|
ENDIF(WINDOWS)
|
||||||
|
|
||||||
add_library(hacd ${SOURCE_FILES} ${INCLUDE_FILES})
|
add_library(hacd ${libhacd_SOURCE_FILES} ${libhacd_INCLUDE_FILES})
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ namespace HACD
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void operator()( char const *aMsg, double aProgress, double aConcavity, size_t aVertices) = 0;
|
virtual void operator()( char const *aMsg, double aProgress, double aConcavity, size_t aVertices) = 0;
|
||||||
|
virtual ~ICallback() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ICallback* CallBackFunction;
|
typedef ICallback* CallBackFunction;
|
||||||
|
|||||||
@@ -1,9 +1,35 @@
|
|||||||
|
# -*- cmake -*-
|
||||||
|
|
||||||
project(libndhacd)
|
project(libndhacd)
|
||||||
|
|
||||||
|
include(00-Common)
|
||||||
|
|
||||||
include_directories(${LIBS_OPEN_DIR}/libhacd)
|
include_directories(${LIBS_OPEN_DIR}/libhacd)
|
||||||
|
|
||||||
set (SOURCE_FILES LLConvexDecomposition.cpp nd_hacdConvexDecomposition.cpp nd_hacdStructs.cpp nd_hacdUtils.cpp nd_EnterExitTracer.cpp nd_StructTracer.cpp )
|
set (libndhacd_SOURCE_FILES
|
||||||
file(GLOB HEADER_FILES *.h)
|
LLConvexDecomposition.cpp
|
||||||
|
nd_hacdConvexDecomposition.cpp
|
||||||
|
nd_hacdStructs.cpp
|
||||||
|
nd_hacdUtils.cpp
|
||||||
|
nd_EnterExitTracer.cpp
|
||||||
|
nd_StructTracer.cpp
|
||||||
|
)
|
||||||
|
|
||||||
add_library( nd_hacdConvexDecomposition STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
set (libndhacd_HEADER_FILES
|
||||||
|
LLConvexDecomposition.h
|
||||||
|
ndConvexDecomposition.h
|
||||||
|
nd_hacdConvexDecomposition.h
|
||||||
|
nd_hacdStructs.h
|
||||||
|
nd_StructTracer.h
|
||||||
|
LLConvexDecompositionStubImpl.h
|
||||||
|
nd_EnterExitTracer.h
|
||||||
|
nd_hacdDefines.h
|
||||||
|
nd_hacdUtils.h
|
||||||
|
windowsincludes.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set_source_files_properties(${libndhacd_HEADER_FILES}
|
||||||
|
PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||||
|
|
||||||
|
add_library( nd_hacdConvexDecomposition STATIC ${libndhacd_SOURCE_FILES} ${libndhacd_HEADER_FILES})
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,24 @@
|
|||||||
cmake_minimum_required(VERSION 2.6.4)
|
# -*- cmake -*-
|
||||||
|
|
||||||
project(ndPathingLib CXX C)
|
project(libpathing)
|
||||||
|
include(00-Common)
|
||||||
|
|
||||||
if( MSVC )
|
if( MSVC )
|
||||||
add_definitions(-D_SECURE_SCL=0 -D_CRT_SECURE_NO_WARNINGS=1)
|
add_definitions(-D_SECURE_SCL=0 -D_CRT_SECURE_NO_WARNINGS=1)
|
||||||
endif( MSVC )
|
endif( MSVC )
|
||||||
|
|
||||||
file (GLOB SOURCE_FILES *.cpp )
|
set(libpathing_SOURCE_FILES
|
||||||
file (GLOB INCLUDE_FILES *.h )
|
llpathinglib.cpp
|
||||||
|
llphysicsextensions.cpp
|
||||||
|
)
|
||||||
|
|
||||||
add_library(nd_Pathing STATIC ${SOURCE_FILES} ${INCLUDE_FILES} )
|
set(libpathing_HEADER_FILES
|
||||||
|
llpathinglib.h
|
||||||
|
llphysicsextensions.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set_source_files_properties(${libpathing_HEADER_FILES}
|
||||||
|
PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||||
|
|
||||||
|
add_library(nd_Pathing STATIC ${libpathing_SOURCE_FILES} ${libpathing_HEADER_FILES} )
|
||||||
|
|
||||||
|
|||||||
@@ -152,8 +152,8 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata)
|
|||||||
<< ")! You should be using FMOD Ex" << FMOD_VERSION << LL_ENDL;
|
<< ")! You should be using FMOD Ex" << FMOD_VERSION << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = mSystem->setSoftwareFormat(44100, FMOD_SOUND_FORMAT_PCM16, 0, 0, FMOD_DSP_RESAMPLER_LINEAR);
|
// result = mSystem->setSoftwareFormat(44100, FMOD_SOUND_FORMAT_PCM16, 0, 0, FMOD_DSP_RESAMPLER_LINEAR);
|
||||||
Check_FMOD_Error(result,"FMOD::System::setSoftwareFormat");
|
// Check_FMOD_Error(result,"FMOD::System::setSoftwareFormat");
|
||||||
|
|
||||||
// In this case, all sounds, PLUS wind and stream will be software.
|
// In this case, all sounds, PLUS wind and stream will be software.
|
||||||
result = mSystem->setSoftwareChannels(num_channels + 2);
|
result = mSystem->setSoftwareChannels(num_channels + 2);
|
||||||
|
|||||||
@@ -405,7 +405,7 @@ LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(FMOD::System *system, con
|
|||||||
exinfo.cbsize = sizeof(exinfo);
|
exinfo.cbsize = sizeof(exinfo);
|
||||||
exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_OGGVORBIS; //Hint to speed up loading.*/
|
exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_OGGVORBIS; //Hint to speed up loading.*/
|
||||||
|
|
||||||
FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_MPEGSEARCH | FMOD_IGNORETAGS, 0, &mInternetStream);
|
FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_IGNORETAGS, 0, &mInternetStream);
|
||||||
|
|
||||||
if (result!= FMOD_OK)
|
if (result!= FMOD_OK)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,7 +40,6 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
#include "lluuidhashmap.h"
|
|
||||||
#include "llmotion.h"
|
#include "llmotion.h"
|
||||||
#include "llpose.h"
|
#include "llpose.h"
|
||||||
#include "llframetimer.h"
|
#include "llframetimer.h"
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ set(llcommon_HEADER_FILES
|
|||||||
lltypeinfolookup.h
|
lltypeinfolookup.h
|
||||||
lluri.h
|
lluri.h
|
||||||
lluuid.h
|
lluuid.h
|
||||||
lluuidhashmap.h
|
sguuidhash.h
|
||||||
llversionviewer.h.in
|
llversionviewer.h.in
|
||||||
llworkerthread.h
|
llworkerthread.h
|
||||||
metaclass.h
|
metaclass.h
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class LL_COMMON_API AIFrameTimer
|
|||||||
mutable Signal* mCallback; // Pointer to callback struct, or NULL when the object wasn't added to sTimerList yet.
|
mutable Signal* mCallback; // Pointer to callback struct, or NULL when the object wasn't added to sTimerList yet.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AIRunningFrameTimer(F64 expiration, AIFrameTimer* timer) : mExpire(LLFrameTimer::getElapsedSeconds() + expiration), mCallback(NULL), mTimer(timer) { }
|
AIRunningFrameTimer(F64 expiration, AIFrameTimer* timer) : mExpire(LLFrameTimer::getElapsedSeconds() + expiration), mTimer(timer), mCallback(NULL) { }
|
||||||
~AIRunningFrameTimer() { delete mCallback; }
|
~AIRunningFrameTimer() { delete mCallback; }
|
||||||
|
|
||||||
// This function is called after the final object was added to sTimerList (where it is initialized in-place).
|
// This function is called after the final object was added to sTimerList (where it is initialized in-place).
|
||||||
@@ -89,7 +89,7 @@ class LL_COMMON_API AIFrameTimer
|
|||||||
#if LL_DEBUG
|
#if LL_DEBUG
|
||||||
// May not copy this object after it was initialized.
|
// May not copy this object after it was initialized.
|
||||||
AIRunningFrameTimer(AIRunningFrameTimer const& running_frame_timer) :
|
AIRunningFrameTimer(AIRunningFrameTimer const& running_frame_timer) :
|
||||||
mExpire(running_frame_timer.mExpire), mCallback(running_frame_timer.mCallback), mTimer(running_frame_timer.mTimer)
|
mExpire(running_frame_timer.mExpire), mTimer(running_frame_timer.mTimer), mCallback(running_frame_timer.mCallback)
|
||||||
{ llassert(!mCallback); }
|
{ llassert(!mCallback); }
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
#include <apr_portable.h> // apr_os_thread_t, apr_os_thread_current(), apr_os_thread_equal().
|
#include <apr_portable.h> // apr_os_thread_t, apr_os_thread_current(), apr_os_thread_equal().
|
||||||
#include <iosfwd> // std::ostream.
|
#include <iosfwd> // std::ostream.
|
||||||
#include "llpreprocessor.h" // LL_COMMON_API, LL_COMMON_API_TLS
|
#include "llpreprocessor.h" // LL_COMMON_API, LL_COMMON_API_TLS, LL_UNLIKELY
|
||||||
|
|
||||||
// Lightweight wrapper around apr_os_thread_t.
|
// Lightweight wrapper around apr_os_thread_t.
|
||||||
// This class introduces no extra assembly code after optimization; it's only intend is to provide type-safety.
|
// This class introduces no extra assembly code after optimization; it's only intend is to provide type-safety.
|
||||||
@@ -87,6 +87,16 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Debugging function.
|
||||||
|
inline bool is_single_threaded(AIThreadID& thread_id)
|
||||||
|
{
|
||||||
|
if (LL_UNLIKELY(thread_id.is_no_thread()))
|
||||||
|
{
|
||||||
|
thread_id.reset();
|
||||||
|
}
|
||||||
|
return thread_id.equals_current_thread();
|
||||||
|
}
|
||||||
|
|
||||||
// Legacy function.
|
// Legacy function.
|
||||||
inline bool is_main_thread(void)
|
inline bool is_main_thread(void)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -95,7 +95,19 @@ public:
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
#if LL_WINDOWS
|
#if LL_WINDOWS
|
||||||
typedef std::filebuf _Myfb;
|
//typedef std::filebuf _Myfb;
|
||||||
|
//Singu note: Wrap around std::filebuf to override the open procedure.
|
||||||
|
// The client encodes filepaths in UTF-8, however Windows uses UTF-16 encoding natively.
|
||||||
|
// Need to convert paths to UTF-16 before calling std::filebuf::open.
|
||||||
|
struct _Myfb : public std::filebuf
|
||||||
|
{
|
||||||
|
_Myfb() : std::filebuf() {}
|
||||||
|
_Myfb(_Filet* file) : std::filebuf(file) {}
|
||||||
|
_Myt *open(const char *filename, std::ios_base::openmode mode, int prot = (int)std::ios_base::_Openprot)
|
||||||
|
{
|
||||||
|
return std::filebuf::open(utf8str_to_utf16str(filename).c_str(),mode,prot);
|
||||||
|
}
|
||||||
|
};
|
||||||
#else
|
#else
|
||||||
typedef __gnu_cxx::stdio_filebuf< char > _Myfb;
|
typedef __gnu_cxx::stdio_filebuf< char > _Myfb;
|
||||||
typedef std::__c_file _Filet;
|
typedef std::__c_file _Filet;
|
||||||
|
|||||||
@@ -57,13 +57,12 @@ inline void ll_aligned_free( void* ptr )
|
|||||||
free( ((void**)ptr)[-1] );
|
free( ((void**)ptr)[-1] );
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !LL_USE_TCMALLOC
|
|
||||||
inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
|
inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
|
||||||
{
|
{
|
||||||
#if defined(LL_WINDOWS)
|
#if (LL_DARWIN || LL_USE_TCMALLOC)
|
||||||
return _aligned_malloc(size, 16);
|
|
||||||
#elif defined(LL_DARWIN)
|
|
||||||
return malloc(size); // default osx malloc is 16 byte aligned.
|
return malloc(size); // default osx malloc is 16 byte aligned.
|
||||||
|
#elif LL_WINDOWS
|
||||||
|
return _aligned_malloc(size, 16);
|
||||||
#else
|
#else
|
||||||
void *rtn;
|
void *rtn;
|
||||||
if (LL_LIKELY(0 == posix_memalign(&rtn, 16, size)))
|
if (LL_LIKELY(0 == posix_memalign(&rtn, 16, size)))
|
||||||
@@ -75,10 +74,10 @@ inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed wi
|
|||||||
|
|
||||||
inline void ll_aligned_free_16(void *p)
|
inline void ll_aligned_free_16(void *p)
|
||||||
{
|
{
|
||||||
#if defined(LL_WINDOWS)
|
#if (LL_DARWIN || LL_USE_TCMALLOC)
|
||||||
|
free(p);
|
||||||
|
#elif LL_WINDOWS
|
||||||
_aligned_free(p);
|
_aligned_free(p);
|
||||||
#elif defined(LL_DARWIN)
|
|
||||||
return free(p);
|
|
||||||
#else
|
#else
|
||||||
free(p); // posix_memalign() is compatible with heap deallocator
|
free(p); // posix_memalign() is compatible with heap deallocator
|
||||||
#endif
|
#endif
|
||||||
@@ -86,10 +85,10 @@ inline void ll_aligned_free_16(void *p)
|
|||||||
|
|
||||||
inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // returned hunk MUST be freed with ll_aligned_free_16().
|
inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // returned hunk MUST be freed with ll_aligned_free_16().
|
||||||
{
|
{
|
||||||
#if defined(LL_WINDOWS)
|
#if (LL_DARWIN || LL_USE_TCMALLOC)
|
||||||
return _aligned_realloc(ptr, size, 16);
|
|
||||||
#elif defined(LL_DARWIN)
|
|
||||||
return realloc(ptr,size); // default osx malloc is 16 byte aligned.
|
return realloc(ptr,size); // default osx malloc is 16 byte aligned.
|
||||||
|
#elif LL_WINDOWS
|
||||||
|
return _aligned_realloc(ptr, size, 16);
|
||||||
#else
|
#else
|
||||||
//FIXME: memcpy is SLOW
|
//FIXME: memcpy is SLOW
|
||||||
void* ret = ll_aligned_malloc_16(size);
|
void* ret = ll_aligned_malloc_16(size);
|
||||||
@@ -106,18 +105,11 @@ inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // r
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // USE_TCMALLOC
|
|
||||||
// ll_aligned_foo_16 are not needed with tcmalloc
|
|
||||||
#define ll_aligned_malloc_16 malloc
|
|
||||||
#define ll_aligned_realloc_16(a,b,c) realloc(a,b)
|
|
||||||
#define ll_aligned_free_16 free
|
|
||||||
#endif // USE_TCMALLOC
|
|
||||||
|
|
||||||
inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
|
inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
|
||||||
{
|
{
|
||||||
#if defined(LL_WINDOWS)
|
#if LL_WINDOWS
|
||||||
return _aligned_malloc(size, 32);
|
return _aligned_malloc(size, 32);
|
||||||
#elif defined(LL_DARWIN)
|
#elif LL_DARWIN
|
||||||
return ll_aligned_malloc( size, 32 );
|
return ll_aligned_malloc( size, 32 );
|
||||||
#else
|
#else
|
||||||
void *rtn;
|
void *rtn;
|
||||||
@@ -130,9 +122,9 @@ inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed wi
|
|||||||
|
|
||||||
inline void ll_aligned_free_32(void *p)
|
inline void ll_aligned_free_32(void *p)
|
||||||
{
|
{
|
||||||
#if defined(LL_WINDOWS)
|
#if LL_WINDOWS
|
||||||
_aligned_free(p);
|
_aligned_free(p);
|
||||||
#elif defined(LL_DARWIN)
|
#elif LL_DARWIN
|
||||||
ll_aligned_free( p );
|
ll_aligned_free( p );
|
||||||
#else
|
#else
|
||||||
free(p); // posix_memalign() is compatible with heap deallocator
|
free(p); // posix_memalign() is compatible with heap deallocator
|
||||||
|
|||||||
@@ -203,7 +203,6 @@ inline T* get_ptr_in_map(const std::map<K,T*>& inmap, const K& key)
|
|||||||
template <typename K, typename T>
|
template <typename K, typename T>
|
||||||
inline bool is_in_map(const std::map<K,T>& inmap, const K& key)
|
inline bool is_in_map(const std::map<K,T>& inmap, const K& key)
|
||||||
{
|
{
|
||||||
typedef typename std::map<K,T>::const_iterator map_iter;
|
|
||||||
if(inmap.find(key) == inmap.end())
|
if(inmap.find(key) == inmap.end())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -403,8 +403,8 @@ void LLCondition::broadcast()
|
|||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
LLMutexBase::LLMutexBase() :
|
LLMutexBase::LLMutexBase() :
|
||||||
mLockingThread(AIThreadID::sNone),
|
mCount(0),
|
||||||
mCount(0)
|
mLockingThread(AIThreadID::sNone)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ U64 totalTime()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (current_clock_count >= gLastTotalTimeClockCount)
|
if (LL_LIKELY(current_clock_count >= gLastTotalTimeClockCount))
|
||||||
{
|
{
|
||||||
// No wrapping, we're all okay.
|
// No wrapping, we're all okay.
|
||||||
gTotalTimeClockCount += current_clock_count - gLastTotalTimeClockCount;
|
gTotalTimeClockCount += current_clock_count - gLastTotalTimeClockCount;
|
||||||
|
|||||||
@@ -1,589 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file lluuidhashmap.h
|
|
||||||
* @brief A uuid based hash map.
|
|
||||||
*
|
|
||||||
* $LicenseInfo:firstyear=2003&license=viewergpl$
|
|
||||||
*
|
|
||||||
* Copyright (c) 2003-2009, Linden Research, Inc.
|
|
||||||
*
|
|
||||||
* Second Life Viewer Source Code
|
|
||||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
|
||||||
* to you under the terms of the GNU General Public License, version 2.0
|
|
||||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
|
||||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
|
||||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
|
||||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
|
||||||
*
|
|
||||||
* 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, or
|
|
||||||
* online at
|
|
||||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
|
||||||
*
|
|
||||||
* By copying, modifying or distributing this software, you acknowledge
|
|
||||||
* that you have read and understood your obligations described above,
|
|
||||||
* and agree to abide by those obligations.
|
|
||||||
*
|
|
||||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
|
||||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
|
||||||
* COMPLETENESS OR PERFORMANCE.
|
|
||||||
* $/LicenseInfo$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LL_LLUUIDHASHMAP_H
|
|
||||||
#define LL_LLUUIDHASHMAP_H
|
|
||||||
|
|
||||||
#include "stdtypes.h"
|
|
||||||
#include "llerror.h"
|
|
||||||
#include "lluuid.h"
|
|
||||||
|
|
||||||
// UUID hash map
|
|
||||||
|
|
||||||
/*
|
|
||||||
LLUUIDHashMap<uuid_pair, 32> foo(test_equals);
|
|
||||||
LLUUIDHashMapIter<uuid_pair, 32> bar(&foo);
|
|
||||||
|
|
||||||
LLDynamicArray<LLUUID> source_ids;
|
|
||||||
const S32 COUNT = 100000;
|
|
||||||
S32 q;
|
|
||||||
for (q = 0; q < COUNT; q++)
|
|
||||||
{
|
|
||||||
llinfos << "Creating" << llendl;
|
|
||||||
LLUUID id;
|
|
||||||
id.generate();
|
|
||||||
//llinfos << q << ":" << id << llendl;
|
|
||||||
uuid_pair pair;
|
|
||||||
pair.mUUID = id;
|
|
||||||
pair.mValue = q;
|
|
||||||
foo.set(id, pair);
|
|
||||||
source_ids.put(id);
|
|
||||||
//ms_sleep(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
uuid_pair cur;
|
|
||||||
llinfos << "Iterating" << llendl;
|
|
||||||
for (cur = bar.first(); !bar.done(); cur = bar.next())
|
|
||||||
{
|
|
||||||
if (source_ids[cur.mValue] != cur.mUUID)
|
|
||||||
{
|
|
||||||
llerrs << "Incorrect value iterated!" << llendl;
|
|
||||||
}
|
|
||||||
//llinfos << cur.mValue << ":" << cur.mUUID << llendl;
|
|
||||||
//ms_sleep(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
llinfos << "Finding" << llendl;
|
|
||||||
for (q = 0; q < COUNT; q++)
|
|
||||||
{
|
|
||||||
cur = foo.get(source_ids[q]);
|
|
||||||
if (source_ids[cur.mValue] != cur.mUUID)
|
|
||||||
{
|
|
||||||
llerrs << "Incorrect value found!" << llendl;
|
|
||||||
}
|
|
||||||
//llinfos << res.mValue << ":" << res.mUUID << llendl;
|
|
||||||
//ms_sleep(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
llinfos << "Removing" << llendl;
|
|
||||||
for (q = 0; q < COUNT/2; q++)
|
|
||||||
{
|
|
||||||
if (!foo.remove(source_ids[q]))
|
|
||||||
{
|
|
||||||
llerrs << "Remove failed!" << llendl;
|
|
||||||
}
|
|
||||||
//ms_sleep(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
llinfos << "Iterating" << llendl;
|
|
||||||
for (cur = bar.first(); !bar.done(); cur = bar.next())
|
|
||||||
{
|
|
||||||
if (source_ids[cur.mValue] != cur.mUUID)
|
|
||||||
{
|
|
||||||
llerrs << "Incorrect value found!" << llendl;
|
|
||||||
}
|
|
||||||
//llinfos << cur.mValue << ":" << cur.mUUID << llendl;
|
|
||||||
//ms_sleep(1);
|
|
||||||
}
|
|
||||||
llinfos << "Done with UUID map test" << llendl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// LLUUIDHashNode
|
|
||||||
//
|
|
||||||
|
|
||||||
template <class DATA, int SIZE>
|
|
||||||
class LLUUIDHashNode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LLUUIDHashNode();
|
|
||||||
|
|
||||||
public:
|
|
||||||
S32 mCount;
|
|
||||||
U8 mKey[SIZE];
|
|
||||||
DATA mData[SIZE];
|
|
||||||
LLUUIDHashNode<DATA, SIZE> *mNextNodep;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// LLUUIDHashNode implementation
|
|
||||||
//
|
|
||||||
template <class DATA, int SIZE>
|
|
||||||
LLUUIDHashNode<DATA, SIZE>::LLUUIDHashNode()
|
|
||||||
{
|
|
||||||
mCount = 0;
|
|
||||||
mNextNodep = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <class DATA_TYPE, int SIZE>
|
|
||||||
class LLUUIDHashMap
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// basic constructor including sorter
|
|
||||||
LLUUIDHashMap(BOOL (*equals)(const LLUUID &uuid, const DATA_TYPE &data),
|
|
||||||
const DATA_TYPE &null_data);
|
|
||||||
~LLUUIDHashMap();
|
|
||||||
|
|
||||||
inline DATA_TYPE &get(const LLUUID &uuid);
|
|
||||||
inline BOOL check(const LLUUID &uuid) const;
|
|
||||||
inline DATA_TYPE &set(const LLUUID &uuid, const DATA_TYPE &type);
|
|
||||||
inline BOOL remove(const LLUUID &uuid);
|
|
||||||
void removeAll();
|
|
||||||
|
|
||||||
inline S32 getLength() const; // Warning, NOT O(1!)
|
|
||||||
public:
|
|
||||||
BOOL (*mEquals)(const LLUUID &uuid, const DATA_TYPE &data);
|
|
||||||
LLUUIDHashNode<DATA_TYPE, SIZE> mNodes[256];
|
|
||||||
|
|
||||||
S32 mIterCount;
|
|
||||||
protected:
|
|
||||||
DATA_TYPE mNull;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// LLUUIDHashMap implementation
|
|
||||||
//
|
|
||||||
|
|
||||||
template <class DATA_TYPE, int SIZE>
|
|
||||||
LLUUIDHashMap<DATA_TYPE, SIZE>::LLUUIDHashMap(BOOL (*equals)(const LLUUID &uuid, const DATA_TYPE &data),
|
|
||||||
const DATA_TYPE &null_data)
|
|
||||||
: mEquals(equals),
|
|
||||||
mIterCount(0),
|
|
||||||
mNull(null_data)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
template <class DATA_TYPE, int SIZE>
|
|
||||||
LLUUIDHashMap<DATA_TYPE, SIZE>::~LLUUIDHashMap()
|
|
||||||
{
|
|
||||||
removeAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class DATA_TYPE, int SIZE>
|
|
||||||
void LLUUIDHashMap<DATA_TYPE, SIZE>::removeAll()
|
|
||||||
{
|
|
||||||
S32 bin;
|
|
||||||
for (bin = 0; bin < 256; bin++)
|
|
||||||
{
|
|
||||||
LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin];
|
|
||||||
|
|
||||||
BOOL first = TRUE;
|
|
||||||
while (nodep)
|
|
||||||
{
|
|
||||||
S32 i;
|
|
||||||
const S32 count = nodep->mCount;
|
|
||||||
|
|
||||||
// Iterate through all members of this node
|
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
nodep->mData[i] = mNull;
|
|
||||||
}
|
|
||||||
|
|
||||||
nodep->mCount = 0;
|
|
||||||
// Done with all objects in this node, go to the next.
|
|
||||||
|
|
||||||
LLUUIDHashNode<DATA_TYPE, SIZE>* curp = nodep;
|
|
||||||
nodep = nodep->mNextNodep;
|
|
||||||
|
|
||||||
// Delete the node if it's not the first node
|
|
||||||
if (first)
|
|
||||||
{
|
|
||||||
first = FALSE;
|
|
||||||
curp->mNextNodep = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
delete curp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class DATA_TYPE, int SIZE>
|
|
||||||
inline S32 LLUUIDHashMap<DATA_TYPE, SIZE>::getLength() const
|
|
||||||
{
|
|
||||||
S32 count = 0;
|
|
||||||
S32 bin;
|
|
||||||
for (bin = 0; bin < 256; bin++)
|
|
||||||
{
|
|
||||||
LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = (LLUUIDHashNode<DATA_TYPE, SIZE>*) &mNodes[bin];
|
|
||||||
while (nodep)
|
|
||||||
{
|
|
||||||
count += nodep->mCount;
|
|
||||||
nodep = nodep->mNextNodep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class DATA_TYPE, int SIZE>
|
|
||||||
inline DATA_TYPE &LLUUIDHashMap<DATA_TYPE, SIZE>::get(const LLUUID &uuid)
|
|
||||||
{
|
|
||||||
LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[uuid.mData[0]];
|
|
||||||
|
|
||||||
// Grab the second byte of the UUID, which is the key for the node data
|
|
||||||
const S32 second_byte = uuid.mData[1];
|
|
||||||
while (nodep)
|
|
||||||
{
|
|
||||||
S32 i;
|
|
||||||
const S32 count = nodep->mCount;
|
|
||||||
|
|
||||||
// Iterate through all members of this node
|
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i]))
|
|
||||||
{
|
|
||||||
// The second byte matched, and our equality test passed.
|
|
||||||
// We found it.
|
|
||||||
return nodep->mData[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Done with all objects in this node, go to the next.
|
|
||||||
nodep = nodep->mNextNodep;
|
|
||||||
}
|
|
||||||
return mNull;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <class DATA_TYPE, int SIZE>
|
|
||||||
inline BOOL LLUUIDHashMap<DATA_TYPE, SIZE>::check(const LLUUID &uuid) const
|
|
||||||
{
|
|
||||||
const LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[uuid.mData[0]];
|
|
||||||
|
|
||||||
// Grab the second byte of the UUID, which is the key for the node data
|
|
||||||
const S32 second_byte = uuid.mData[1];
|
|
||||||
while (nodep)
|
|
||||||
{
|
|
||||||
S32 i;
|
|
||||||
const S32 count = nodep->mCount;
|
|
||||||
|
|
||||||
// Iterate through all members of this node
|
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i]))
|
|
||||||
{
|
|
||||||
// The second byte matched, and our equality test passed.
|
|
||||||
// We found it.
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Done with all objects in this node, go to the next.
|
|
||||||
nodep = nodep->mNextNodep;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Didn't find anything
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <class DATA_TYPE, int SIZE>
|
|
||||||
inline DATA_TYPE &LLUUIDHashMap<DATA_TYPE, SIZE>::set(const LLUUID &uuid, const DATA_TYPE &data)
|
|
||||||
{
|
|
||||||
// Set is just like a normal find, except that if we find a match
|
|
||||||
// we replace it with the input value.
|
|
||||||
// If we don't find a match, we append to the end of the list.
|
|
||||||
|
|
||||||
LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[uuid.mData[0]];
|
|
||||||
|
|
||||||
const S32 second_byte = uuid.mData[1];
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
const S32 count = nodep->mCount;
|
|
||||||
|
|
||||||
S32 i;
|
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i]))
|
|
||||||
{
|
|
||||||
// We found a match for this key, replace the data with
|
|
||||||
// the incoming data.
|
|
||||||
nodep->mData[i] = data;
|
|
||||||
return nodep->mData[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!nodep->mNextNodep)
|
|
||||||
{
|
|
||||||
// We've iterated through all of the keys without finding a match
|
|
||||||
if (i < SIZE)
|
|
||||||
{
|
|
||||||
// There's still some space on this node, append
|
|
||||||
// the key and data to it.
|
|
||||||
nodep->mKey[i] = second_byte;
|
|
||||||
nodep->mData[i] = data;
|
|
||||||
nodep->mCount++;
|
|
||||||
|
|
||||||
return nodep->mData[i];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// This node is full, append a new node to the end.
|
|
||||||
nodep->mNextNodep = new LLUUIDHashNode<DATA_TYPE, SIZE>;
|
|
||||||
nodep->mNextNodep->mKey[0] = second_byte;
|
|
||||||
nodep->mNextNodep->mData[0] = data;
|
|
||||||
nodep->mNextNodep->mCount = 1;
|
|
||||||
|
|
||||||
return nodep->mNextNodep->mData[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No match on this node, go to the next
|
|
||||||
nodep = nodep->mNextNodep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <class DATA_TYPE, int SIZE>
|
|
||||||
inline BOOL LLUUIDHashMap<DATA_TYPE, SIZE>::remove(const LLUUID &uuid)
|
|
||||||
{
|
|
||||||
if (mIterCount)
|
|
||||||
{
|
|
||||||
// We don't allow remove when we're iterating, it's bad karma!
|
|
||||||
llerrs << "Attempted remove while an outstanding iterator in LLUUIDHashMap!" << llendl;
|
|
||||||
}
|
|
||||||
// Remove is the trickiest operation.
|
|
||||||
// What we want to do is swap the last element of the last
|
|
||||||
// node if we find the one that we want to remove, but we have
|
|
||||||
// to deal with deleting the node from the tail if it's empty, but
|
|
||||||
// NOT if it's the only node left.
|
|
||||||
|
|
||||||
LLUUIDHashNode<DATA_TYPE, SIZE> *nodep = &mNodes[uuid.mData[0]];
|
|
||||||
|
|
||||||
// Not empty, we need to search through the nodes
|
|
||||||
const S32 second_byte = uuid.mData[1];
|
|
||||||
|
|
||||||
// A modification of the standard search algorithm.
|
|
||||||
while (nodep)
|
|
||||||
{
|
|
||||||
const S32 count = nodep->mCount;
|
|
||||||
|
|
||||||
S32 i;
|
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i]))
|
|
||||||
{
|
|
||||||
// We found the node that we want to remove.
|
|
||||||
// Find the last (and next-to-last) node, and the index of the last
|
|
||||||
// element. We could conceviably start from the node we're on,
|
|
||||||
// but that makes it more complicated, this is easier.
|
|
||||||
|
|
||||||
LLUUIDHashNode<DATA_TYPE, SIZE> *prevp = &mNodes[uuid.mData[0]];
|
|
||||||
LLUUIDHashNode<DATA_TYPE, SIZE> *lastp = prevp;
|
|
||||||
|
|
||||||
// Find the last and next-to-last
|
|
||||||
while (lastp->mNextNodep)
|
|
||||||
{
|
|
||||||
prevp = lastp;
|
|
||||||
lastp = lastp->mNextNodep;
|
|
||||||
}
|
|
||||||
|
|
||||||
// First, swap in the last to the current location.
|
|
||||||
nodep->mKey[i] = lastp->mKey[lastp->mCount - 1];
|
|
||||||
nodep->mData[i] = lastp->mData[lastp->mCount - 1];
|
|
||||||
|
|
||||||
// Now, we delete the entry
|
|
||||||
lastp->mCount--;
|
|
||||||
lastp->mData[lastp->mCount] = mNull;
|
|
||||||
|
|
||||||
if (!lastp->mCount)
|
|
||||||
{
|
|
||||||
// We deleted the last element!
|
|
||||||
if (lastp != &mNodes[uuid.mData[0]])
|
|
||||||
{
|
|
||||||
// Only blitz the node if it's not the head
|
|
||||||
// Set the previous node to point to NULL, then
|
|
||||||
// blitz the empty last node
|
|
||||||
prevp->mNextNodep = NULL;
|
|
||||||
delete lastp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate to the next node, we've scanned all the entries in this one.
|
|
||||||
nodep = nodep->mNextNodep;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// LLUUIDHashMapIter
|
|
||||||
//
|
|
||||||
|
|
||||||
template <class DATA_TYPE, int SIZE>
|
|
||||||
class LLUUIDHashMapIter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LLUUIDHashMapIter(LLUUIDHashMap<DATA_TYPE, SIZE> *hash_mapp);
|
|
||||||
~LLUUIDHashMapIter();
|
|
||||||
|
|
||||||
|
|
||||||
inline void reset();
|
|
||||||
inline void first();
|
|
||||||
inline void next();
|
|
||||||
inline BOOL done() const;
|
|
||||||
|
|
||||||
DATA_TYPE& operator*() const
|
|
||||||
{
|
|
||||||
return mCurHashNodep->mData[mCurHashNodeKey];
|
|
||||||
}
|
|
||||||
DATA_TYPE* operator->() const
|
|
||||||
{
|
|
||||||
return &(operator*());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
LLUUIDHashMap<DATA_TYPE, SIZE> *mHashMapp;
|
|
||||||
LLUUIDHashNode<DATA_TYPE, SIZE> *mCurHashNodep;
|
|
||||||
|
|
||||||
S32 mCurHashMapNodeNum;
|
|
||||||
S32 mCurHashNodeKey;
|
|
||||||
|
|
||||||
DATA_TYPE mNull;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// LLUUIDHashMapIter Implementation
|
|
||||||
//
|
|
||||||
template <class DATA_TYPE, int SIZE>
|
|
||||||
LLUUIDHashMapIter<DATA_TYPE, SIZE>::LLUUIDHashMapIter(LLUUIDHashMap<DATA_TYPE, SIZE> *hash_mapp)
|
|
||||||
{
|
|
||||||
mHashMapp = hash_mapp;
|
|
||||||
mCurHashNodep = NULL;
|
|
||||||
mCurHashMapNodeNum = 0;
|
|
||||||
mCurHashNodeKey = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class DATA_TYPE, int SIZE>
|
|
||||||
LLUUIDHashMapIter<DATA_TYPE, SIZE>::~LLUUIDHashMapIter()
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class DATA_TYPE, int SIZE>
|
|
||||||
inline void LLUUIDHashMapIter<DATA_TYPE, SIZE>::reset()
|
|
||||||
{
|
|
||||||
if (mCurHashNodep)
|
|
||||||
{
|
|
||||||
// We're partway through an iteration, we can clean up now
|
|
||||||
mHashMapp->mIterCount--;
|
|
||||||
mCurHashNodep = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class DATA_TYPE, int SIZE>
|
|
||||||
inline void LLUUIDHashMapIter<DATA_TYPE, SIZE>::first()
|
|
||||||
{
|
|
||||||
// Iterate through until we find the first non-empty node;
|
|
||||||
S32 i;
|
|
||||||
for (i = 0; i < 256; i++)
|
|
||||||
{
|
|
||||||
if (mHashMapp->mNodes[i].mCount)
|
|
||||||
{
|
|
||||||
if (!mCurHashNodep)
|
|
||||||
{
|
|
||||||
// Increment, since it's no longer safe for us to do a remove
|
|
||||||
mHashMapp->mIterCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
mCurHashNodep = &mHashMapp->mNodes[i];
|
|
||||||
mCurHashMapNodeNum = i;
|
|
||||||
mCurHashNodeKey = 0;
|
|
||||||
//return mCurHashNodep->mData[0];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Completely empty!
|
|
||||||
mCurHashNodep = NULL;
|
|
||||||
//return mNull;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class DATA_TYPE, int SIZE>
|
|
||||||
inline BOOL LLUUIDHashMapIter<DATA_TYPE, SIZE>::done() const
|
|
||||||
{
|
|
||||||
return mCurHashNodep ? FALSE : TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class DATA_TYPE, int SIZE>
|
|
||||||
inline void LLUUIDHashMapIter<DATA_TYPE, SIZE>::next()
|
|
||||||
{
|
|
||||||
// No current entry, this iterator is done
|
|
||||||
if (!mCurHashNodep)
|
|
||||||
{
|
|
||||||
//return mNull;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go to the next element
|
|
||||||
mCurHashNodeKey++;
|
|
||||||
if (mCurHashNodeKey < mCurHashNodep->mCount)
|
|
||||||
{
|
|
||||||
// We're not done with this node, return the current element
|
|
||||||
//return mCurHashNodep->mData[mCurHashNodeKey];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Done with this node, move to the next
|
|
||||||
mCurHashNodep = mCurHashNodep->mNextNodep;
|
|
||||||
if (mCurHashNodep)
|
|
||||||
{
|
|
||||||
// Return the first element
|
|
||||||
mCurHashNodeKey = 0;
|
|
||||||
//return mCurHashNodep->mData[0];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the next non-empty node (keyed on the first byte)
|
|
||||||
mCurHashMapNodeNum++;
|
|
||||||
|
|
||||||
S32 i;
|
|
||||||
for (i = mCurHashMapNodeNum; i < 256; i++)
|
|
||||||
{
|
|
||||||
if (mHashMapp->mNodes[i].mCount)
|
|
||||||
{
|
|
||||||
// We found one that wasn't empty
|
|
||||||
mCurHashNodep = &mHashMapp->mNodes[i];
|
|
||||||
mCurHashMapNodeNum = i;
|
|
||||||
mCurHashNodeKey = 0;
|
|
||||||
//return mCurHashNodep->mData[0];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// OK, we're done, nothing else to iterate
|
|
||||||
mCurHashNodep = NULL;
|
|
||||||
mHashMapp->mIterCount--; // Decrement since we're safe to do removes now
|
|
||||||
//return mNull;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // LL_LLUUIDHASHMAP_H
|
|
||||||
@@ -34,8 +34,8 @@
|
|||||||
#define LL_LLVERSIONVIEWER_H
|
#define LL_LLVERSIONVIEWER_H
|
||||||
|
|
||||||
const S32 LL_VERSION_MAJOR = 1;
|
const S32 LL_VERSION_MAJOR = 1;
|
||||||
const S32 LL_VERSION_MINOR = 7;
|
const S32 LL_VERSION_MINOR = 8;
|
||||||
const S32 LL_VERSION_PATCH = 3;
|
const S32 LL_VERSION_PATCH = 0;
|
||||||
const S32 LL_VERSION_BUILD = ${vBUILD};
|
const S32 LL_VERSION_BUILD = ${vBUILD};
|
||||||
|
|
||||||
const char * const LL_CHANNEL = "${VIEWER_CHANNEL}";
|
const char * const LL_CHANNEL = "${VIEWER_CHANNEL}";
|
||||||
|
|||||||
36
indra/llcommon/sguuidhash.h
Normal file
36
indra/llcommon/sguuidhash.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/* Copyright (C) 2013 Siana Gearz
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General
|
||||||
|
* Public License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301 USA */
|
||||||
|
|
||||||
|
#ifndef SGUUIDHASH_H
|
||||||
|
#define SGUUIDHASH_H
|
||||||
|
|
||||||
|
#include "lluuid.h"
|
||||||
|
#include <boost/functional/hash.hpp>
|
||||||
|
#include <boost/unordered_map.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
template<> class hash<LLUUID> {
|
||||||
|
public:
|
||||||
|
size_t operator()(const LLUUID& id ) const
|
||||||
|
{
|
||||||
|
return *reinterpret_cast<const size_t*>(id.mData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -390,11 +390,6 @@ bool LLCrashLogger::init()
|
|||||||
// Start state machine thread.
|
// Start state machine thread.
|
||||||
startEngineThread();
|
startEngineThread();
|
||||||
|
|
||||||
// Start curl thread.
|
|
||||||
AICurlInterface::startCurlThread(64, // CurlMaxTotalConcurrentConnections
|
|
||||||
8, // CurlConcurrentConnectionsPerHost
|
|
||||||
true); // NoVerifySSLCert
|
|
||||||
|
|
||||||
// We assume that all the logs we're looking for reside on the current drive
|
// We assume that all the logs we're looking for reside on the current drive
|
||||||
gDirUtilp->initAppDirs("SecondLife");
|
gDirUtilp->initAppDirs("SecondLife");
|
||||||
|
|
||||||
@@ -414,6 +409,9 @@ bool LLCrashLogger::init()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start curl thread.
|
||||||
|
AICurlInterface::startCurlThread(&mCrashSettings);
|
||||||
|
|
||||||
gServicePump = new LLPumpIO;
|
gServicePump = new LLPumpIO;
|
||||||
|
|
||||||
//If we've opened the crash logger, assume we can delete the marker file if it exists
|
//If we've opened the crash logger, assume we can delete the marker file if it exists
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ namespace expression {
|
|||||||
|
|
||||||
|
|
||||||
//TODO: If we can find a better way to do this with boost::pheonix::bind lets do it
|
//TODO: If we can find a better way to do this with boost::pheonix::bind lets do it
|
||||||
namespace { // anonymous
|
//namespace { // anonymous
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T min_glue(T a, T b)
|
T min_glue(T a, T b)
|
||||||
@@ -91,7 +91,7 @@ struct lazy_bfunc_
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace anonymous
|
//} // end namespace anonymous
|
||||||
|
|
||||||
template <typename FPT, typename Iterator>
|
template <typename FPT, typename Iterator>
|
||||||
struct grammar
|
struct grammar
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "sys.h"
|
||||||
#include "llmath.h"
|
#include "llmath.h"
|
||||||
|
|
||||||
static LL_ALIGN_16(const F32 M_IDENT_3A[12]) =
|
static LL_ALIGN_16(const F32 M_IDENT_3A[12]) =
|
||||||
|
|||||||
@@ -22,9 +22,10 @@ include_directories(
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(llmessage_SOURCE_FILES
|
set(llmessage_SOURCE_FILES
|
||||||
|
aiaverage.cpp
|
||||||
aicurl.cpp
|
aicurl.cpp
|
||||||
aicurleasyrequeststatemachine.cpp
|
aicurleasyrequeststatemachine.cpp
|
||||||
aicurlperhost.cpp
|
aicurlperservice.cpp
|
||||||
aicurlthread.cpp
|
aicurlthread.cpp
|
||||||
aihttpheaders.cpp
|
aihttpheaders.cpp
|
||||||
aihttptimeout.cpp
|
aihttptimeout.cpp
|
||||||
@@ -109,9 +110,10 @@ set(llmessage_SOURCE_FILES
|
|||||||
set(llmessage_HEADER_FILES
|
set(llmessage_HEADER_FILES
|
||||||
CMakeLists.txt
|
CMakeLists.txt
|
||||||
|
|
||||||
|
aiaverage.h
|
||||||
aicurl.h
|
aicurl.h
|
||||||
aicurleasyrequeststatemachine.h
|
aicurleasyrequeststatemachine.h
|
||||||
aicurlperhost.h
|
aicurlperservice.h
|
||||||
aicurlprivate.h
|
aicurlprivate.h
|
||||||
aicurlthread.h
|
aicurlthread.h
|
||||||
aihttpheaders.h
|
aihttpheaders.h
|
||||||
|
|||||||
81
indra/llmessage/aiaverage.cpp
Normal file
81
indra/llmessage/aiaverage.cpp
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* @file aiaverage.cpp
|
||||||
|
* @brief Implementation of AIAverage
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, 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.
|
||||||
|
*
|
||||||
|
* 11/04/2013
|
||||||
|
* Initial version, written by Aleric Inglewood @ SL
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sys.h"
|
||||||
|
#include "aiaverage.h"
|
||||||
|
#include "llerror.h" // llassert
|
||||||
|
|
||||||
|
void AIAverage::cleanup(U64 clock_tick)
|
||||||
|
{
|
||||||
|
// This expression can fail because the curl thread caches the time in
|
||||||
|
// sTime_10ms for the duration of an entire loop. Therefore, the time can
|
||||||
|
// go into the next 40ms and a texture fetch worker thread might call
|
||||||
|
// cleanup() with that time, setting mCurrentClock to a value (one)
|
||||||
|
// larger than sTime_10ms / 4. Next, the curl thread can continue to call
|
||||||
|
// this function with the smaller value; in that case just add the new
|
||||||
|
// data to the current bucket.
|
||||||
|
//
|
||||||
|
// Or, this is just the one-time initialization that happens the first
|
||||||
|
// time this is called. In that case initialize just mCurrentClock:
|
||||||
|
// the rest is already initialized upon construction.
|
||||||
|
if (LL_LIKELY(clock_tick > mCurrentClock))
|
||||||
|
{
|
||||||
|
// Advance to the next bucket.
|
||||||
|
++mCurrentBucket;
|
||||||
|
mCurrentBucket %= mNrOfBuckets;
|
||||||
|
// Initialize the new bucket.
|
||||||
|
mData[mCurrentBucket].time = clock_tick;
|
||||||
|
// Clean up old buckets.
|
||||||
|
U64 old_time = clock_tick - mNrOfBuckets;
|
||||||
|
if (LL_UNLIKELY(mTail == mCurrentBucket) || // Extremely unlikely: only happens when data was added EVERY clock tick for the past mNrOfBuckets clock ticks.
|
||||||
|
mData[mTail].time <= old_time)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
mSum -= mData[mTail].sum;
|
||||||
|
mN -= mData[mTail].n;
|
||||||
|
mData[mTail].sum = 0;
|
||||||
|
mData[mTail].n = 0;
|
||||||
|
++mTail;
|
||||||
|
if (LL_UNLIKELY(mTail == mNrOfBuckets))
|
||||||
|
{
|
||||||
|
mTail = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (mData[mTail].time <= old_time);
|
||||||
|
}
|
||||||
|
// This was set to zero when mTail passed this point (likely not this call, but a few calls ago).
|
||||||
|
llassert(mData[mCurrentBucket].sum == 0 &&
|
||||||
|
mData[mCurrentBucket].n == 0);
|
||||||
|
}
|
||||||
|
mCurrentClock = clock_tick;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
109
indra/llmessage/aiaverage.h
Normal file
109
indra/llmessage/aiaverage.h
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/**
|
||||||
|
* @file aiaverage.h
|
||||||
|
* @brief Definition of class AIAverage
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, 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.
|
||||||
|
*
|
||||||
|
* 11/04/2013
|
||||||
|
* Initial version, written by Aleric Inglewood @ SL
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AIAVERAGE_H
|
||||||
|
#define AIAVERAGE_H
|
||||||
|
|
||||||
|
#include "llpreprocessor.h"
|
||||||
|
#include "stdtypes.h" // U32, U64
|
||||||
|
#include "llthread.h" // LLMutex
|
||||||
|
#include <cstddef> // size_t
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class AIAverage {
|
||||||
|
private:
|
||||||
|
struct Data {
|
||||||
|
U32 sum; // Accumulated sum of the 'n' passed to operator()(size_t n, U64 clock_tick) with clock_tick == time.
|
||||||
|
U32 n; // The number of calls to operator().
|
||||||
|
U64 time; // The clock_tick as passed to operator()(size_t n, U64 clock_tick) that sum corresponds to.
|
||||||
|
};
|
||||||
|
|
||||||
|
U64 mCurrentClock; // The current (last) time that operator() was called with, or -1 when not initialized.
|
||||||
|
int mTail; // The oldest bucket with still valid data.
|
||||||
|
int mCurrentBucket; // The bucket that corresponds to mCurrentClock.
|
||||||
|
size_t mSum; // The sum of all the 'n' passed to operator()(size_t n, U64 clock_tick) for all passed mNrOfBuckets time units.
|
||||||
|
U32 mN; // The number of calls to operator().
|
||||||
|
int const mNrOfBuckets; // Size of mData.
|
||||||
|
std::vector<Data> mData; // The buckets.
|
||||||
|
|
||||||
|
mutable LLMutex mLock; // Mutex for all of the above data.
|
||||||
|
|
||||||
|
public:
|
||||||
|
AIAverage(int number_of_buckets) : mCurrentClock(~(U64)0), mTail(0), mCurrentBucket(0), mSum(0), mN(0), mNrOfBuckets(number_of_buckets), mData(number_of_buckets)
|
||||||
|
{
|
||||||
|
// Fill mData with all zeroes (much faster than adding a constructor to Data).
|
||||||
|
std::memset(&*mData.begin(), 0, number_of_buckets * sizeof(Data));
|
||||||
|
}
|
||||||
|
size_t addData(U32 n, U64 clock_tick)
|
||||||
|
{
|
||||||
|
DoutEntering(dc::curl, "AIAverage::addData(" << n << ", " << clock_tick << ")");
|
||||||
|
mLock.lock();
|
||||||
|
if (LL_UNLIKELY(clock_tick != mCurrentClock))
|
||||||
|
{
|
||||||
|
cleanup(clock_tick);
|
||||||
|
}
|
||||||
|
mSum += n;
|
||||||
|
mN += 1;
|
||||||
|
mData[mCurrentBucket].sum += n;
|
||||||
|
mData[mCurrentBucket].n += 1;
|
||||||
|
size_t sum = mSum;
|
||||||
|
mLock.unlock();
|
||||||
|
Dout(dc::curl, "Current sum: " << sum << ", average: " << (sum / mN));
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
size_t truncateData(U64 clock_tick)
|
||||||
|
{
|
||||||
|
mLock.lock();
|
||||||
|
if (clock_tick != mCurrentClock)
|
||||||
|
{
|
||||||
|
cleanup(clock_tick);
|
||||||
|
}
|
||||||
|
size_t sum = mSum;
|
||||||
|
mLock.unlock();
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
double getAverage(double avg_no_data) const
|
||||||
|
{
|
||||||
|
mLock.lock();
|
||||||
|
double avg = mSum;
|
||||||
|
llassert(mN != 0 || mSum == 0);
|
||||||
|
if (LL_UNLIKELY(mN == 0))
|
||||||
|
avg = avg_no_data;
|
||||||
|
else
|
||||||
|
avg /= mN;
|
||||||
|
mLock.unlock();
|
||||||
|
return avg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void cleanup(U64 clock_tick);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // AIAVERAGE
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
#include "aihttpheaders.h"
|
#include "aihttpheaders.h"
|
||||||
#include "aihttptimeoutpolicy.h"
|
#include "aihttptimeoutpolicy.h"
|
||||||
#include "aicurleasyrequeststatemachine.h"
|
#include "aicurleasyrequeststatemachine.h"
|
||||||
#include "aicurlperhost.h"
|
#include "aicurlperservice.h"
|
||||||
|
|
||||||
//==================================================================================
|
//==================================================================================
|
||||||
// Debug Settings
|
// Debug Settings
|
||||||
@@ -298,6 +298,7 @@ LLAtomicU32 Stats::easy_init_errors;
|
|||||||
LLAtomicU32 Stats::easy_cleanup_calls;
|
LLAtomicU32 Stats::easy_cleanup_calls;
|
||||||
LLAtomicU32 Stats::multi_calls;
|
LLAtomicU32 Stats::multi_calls;
|
||||||
LLAtomicU32 Stats::multi_errors;
|
LLAtomicU32 Stats::multi_errors;
|
||||||
|
LLAtomicU32 Stats::running_handles;
|
||||||
LLAtomicU32 Stats::AICurlEasyRequest_count;
|
LLAtomicU32 Stats::AICurlEasyRequest_count;
|
||||||
LLAtomicU32 Stats::AICurlEasyRequestStateMachine_count;
|
LLAtomicU32 Stats::AICurlEasyRequestStateMachine_count;
|
||||||
LLAtomicU32 Stats::BufferedCurlEasyRequest_count;
|
LLAtomicU32 Stats::BufferedCurlEasyRequest_count;
|
||||||
@@ -460,6 +461,12 @@ void setCAPath(std::string const& path)
|
|||||||
CertificateAuthority_w->path = path;
|
CertificateAuthority_w->path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// THREAD-SAFE
|
||||||
|
U32 getNumHTTPRunning(void)
|
||||||
|
{
|
||||||
|
return Stats::running_handles;
|
||||||
|
}
|
||||||
|
|
||||||
//static
|
//static
|
||||||
void Stats::print(void)
|
void Stats::print(void)
|
||||||
{
|
{
|
||||||
@@ -952,9 +959,9 @@ CurlEasyRequest::~CurlEasyRequest()
|
|||||||
// be available anymore.
|
// be available anymore.
|
||||||
send_handle_events_to(NULL);
|
send_handle_events_to(NULL);
|
||||||
revokeCallbacks();
|
revokeCallbacks();
|
||||||
if (mPerHostPtr)
|
if (mPerServicePtr)
|
||||||
{
|
{
|
||||||
PerHostRequestQueue::release(mPerHostPtr);
|
AIPerService::release(mPerServicePtr);
|
||||||
}
|
}
|
||||||
// This wasn't freed yet if the request never finished.
|
// This wasn't freed yet if the request never finished.
|
||||||
curl_slist_free_all(mHeaders);
|
curl_slist_free_all(mHeaders);
|
||||||
@@ -1084,56 +1091,6 @@ void CurlEasyRequest::applyDefaultOptions(void)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// url must be of the form
|
|
||||||
// (see http://www.ietf.org/rfc/rfc3986.txt Appendix A for definitions not given here):
|
|
||||||
//
|
|
||||||
// url = sheme ":" hier-part [ "?" query ] [ "#" fragment ]
|
|
||||||
// hier-part = "//" authority path-abempty
|
|
||||||
// authority = [ userinfo "@" ] host [ ":" port ]
|
|
||||||
// path-abempty = *( "/" segment )
|
|
||||||
//
|
|
||||||
// That is, a hier-part of the form '/ path-absolute', '/ path-rootless' or
|
|
||||||
// '/ path-empty' is NOT allowed here. This should be safe because we only
|
|
||||||
// call this function for curl access, any file access would use APR.
|
|
||||||
//
|
|
||||||
// However, as a special exception, this function allows:
|
|
||||||
//
|
|
||||||
// url = authority path-abempty
|
|
||||||
//
|
|
||||||
// without the 'sheme ":" "//"' parts.
|
|
||||||
//
|
|
||||||
// As follows from the ABNF (see RFC, Appendix A):
|
|
||||||
// - authority is either terminated by a '/' or by the end of the string because
|
|
||||||
// neither userinfo, host nor port may contain a '/'.
|
|
||||||
// - userinfo does not contain a '@', and if it exists, is always terminated by a '@'.
|
|
||||||
// - port does not contain a ':', and if it exists is always prepended by a ':'.
|
|
||||||
//
|
|
||||||
// Only called by CurlEasyRequest::finalizeRequest.
|
|
||||||
static std::string extract_canonical_hostname(std::string const& url)
|
|
||||||
{
|
|
||||||
std::string::size_type pos;
|
|
||||||
std::string::size_type authority = 0; // Default if there is no sheme.
|
|
||||||
if ((pos = url.find("://")) != url.npos && pos < url.find('/')) authority = pos + 3; // Skip the "sheme://" if any, the second find is to avoid finding a "://" as part of path-abempty.
|
|
||||||
std::string::size_type host = authority; // Default if there is no userinfo.
|
|
||||||
if ((pos = url.find('@', authority)) != url.npos) host = pos + 1; // Skip the "userinfo@" if any.
|
|
||||||
authority = url.length() - 1; // Default last character of host if there is no path-abempty.
|
|
||||||
if ((pos = url.find('/', host)) != url.npos) authority = pos - 1; // Point to last character of host.
|
|
||||||
std::string::size_type len = url.find_last_not_of(":0123456789", authority) - host + 1; // Skip trailing ":port", if any.
|
|
||||||
std::string hostname(url, host, len);
|
|
||||||
#if APR_CHARSET_EBCDIC
|
|
||||||
#error Not implemented
|
|
||||||
#else
|
|
||||||
// Convert hostname to lowercase in a way that we compare two hostnames equal iff libcurl does.
|
|
||||||
for (std::string::iterator iter = hostname.begin(); iter != hostname.end(); ++iter)
|
|
||||||
{
|
|
||||||
int c = *iter;
|
|
||||||
if (c >= 'A' && c <= 'Z')
|
|
||||||
*iter = c + ('a' - 'A');
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return hostname;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolicy const& policy, AICurlEasyRequestStateMachine* state_machine)
|
void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolicy const& policy, AICurlEasyRequestStateMachine* state_machine)
|
||||||
{
|
{
|
||||||
DoutCurlEntering("CurlEasyRequest::finalizeRequest(\"" << url << "\", " << policy.name() << ", " << (void*)state_machine << ")");
|
DoutCurlEntering("CurlEasyRequest::finalizeRequest(\"" << url << "\", " << policy.name() << ", " << (void*)state_machine << ")");
|
||||||
@@ -1156,8 +1113,8 @@ void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolic
|
|||||||
#endif
|
#endif
|
||||||
setopt(CURLOPT_HTTPHEADER, mHeaders);
|
setopt(CURLOPT_HTTPHEADER, mHeaders);
|
||||||
setoptString(CURLOPT_URL, url);
|
setoptString(CURLOPT_URL, url);
|
||||||
llassert(!mPerHostPtr);
|
llassert(!mPerServicePtr);
|
||||||
mLowercaseHostname = extract_canonical_hostname(url);
|
mLowercaseServicename = AIPerService::extract_canonical_servicename(url);
|
||||||
mTimeoutPolicy = &policy;
|
mTimeoutPolicy = &policy;
|
||||||
state_machine->setTotalDelayTimeout(policy.getTotalDelay());
|
state_machine->setTotalDelayTimeout(policy.getTotalDelay());
|
||||||
// The following line is a bit tricky: we store a pointer to the object without increasing its reference count.
|
// The following line is a bit tricky: we store a pointer to the object without increasing its reference count.
|
||||||
@@ -1183,7 +1140,7 @@ void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolic
|
|||||||
// // get less connect time, while it still (also) has to wait for this DNS lookup.
|
// // get less connect time, while it still (also) has to wait for this DNS lookup.
|
||||||
void CurlEasyRequest::set_timeout_opts(void)
|
void CurlEasyRequest::set_timeout_opts(void)
|
||||||
{
|
{
|
||||||
setopt(CURLOPT_CONNECTTIMEOUT, mTimeoutPolicy->getConnectTimeout(mLowercaseHostname));
|
setopt(CURLOPT_CONNECTTIMEOUT, mTimeoutPolicy->getConnectTimeout(getLowercaseHostname()));
|
||||||
setopt(CURLOPT_TIMEOUT, mTimeoutPolicy->getCurlTransaction());
|
setopt(CURLOPT_TIMEOUT, mTimeoutPolicy->getCurlTransaction());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1279,22 +1236,27 @@ void CurlEasyRequest::queued_for_removal(AICurlEasyRequest_wat& curl_easy_reques
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PerHostRequestQueuePtr CurlEasyRequest::getPerHostPtr(void)
|
AIPerServicePtr CurlEasyRequest::getPerServicePtr(void)
|
||||||
{
|
{
|
||||||
if (!mPerHostPtr)
|
if (!mPerServicePtr)
|
||||||
{
|
{
|
||||||
// mPerHostPtr is really just a speed-up cache.
|
// mPerServicePtr is really just a speed-up cache.
|
||||||
// The reason we can cache it is because mLowercaseHostname is only set
|
// The reason we can cache it is because mLowercaseServicename is only set
|
||||||
// in finalizeRequest which may only be called once: it never changes.
|
// in finalizeRequest which may only be called once: it never changes.
|
||||||
mPerHostPtr = PerHostRequestQueue::instance(mLowercaseHostname);
|
mPerServicePtr = AIPerService::instance(mLowercaseServicename);
|
||||||
}
|
}
|
||||||
return mPerHostPtr;
|
return mPerServicePtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CurlEasyRequest::removeFromPerHostQueue(AICurlEasyRequest const& easy_request) const
|
bool CurlEasyRequest::removeFromPerServiceQueue(AICurlEasyRequest const& easy_request) const
|
||||||
{
|
{
|
||||||
// Note that easy_request (must) represent(s) this object; it's just passed for convenience.
|
// Note that easy_request (must) represent(s) this object; it's just passed for convenience.
|
||||||
return mPerHostPtr && PerHostRequestQueue_wat(*mPerHostPtr)->cancel(easy_request);
|
return mPerServicePtr && PerService_wat(*mPerServicePtr)->cancel(easy_request);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CurlEasyRequest::getLowercaseHostname(void) const
|
||||||
|
{
|
||||||
|
return mLowercaseServicename.substr(0, mLowercaseServicename.find_last_of(':'));
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@@ -1305,8 +1267,10 @@ static int const HTTP_REDIRECTS_DEFAULT = 10;
|
|||||||
LLChannelDescriptors const BufferedCurlEasyRequest::sChannels;
|
LLChannelDescriptors const BufferedCurlEasyRequest::sChannels;
|
||||||
LLMutex BufferedCurlEasyRequest::sResponderCallbackMutex;
|
LLMutex BufferedCurlEasyRequest::sResponderCallbackMutex;
|
||||||
bool BufferedCurlEasyRequest::sShuttingDown = false;
|
bool BufferedCurlEasyRequest::sShuttingDown = false;
|
||||||
|
AIAverage BufferedCurlEasyRequest::sHTTPBandwidth(25);
|
||||||
|
|
||||||
BufferedCurlEasyRequest::BufferedCurlEasyRequest() : mRequestTransferedBytes(0), mResponseTransferedBytes(0), mBufferEventsTarget(NULL), mStatus(HTTP_INTERNAL_ERROR_OTHER)
|
BufferedCurlEasyRequest::BufferedCurlEasyRequest() :
|
||||||
|
mRequestTransferedBytes(0), mTotalRawBytes(0), mStatus(HTTP_INTERNAL_ERROR_OTHER), mBufferEventsTarget(NULL), mQueueIfTooMuchBandwidthUsage(false)
|
||||||
{
|
{
|
||||||
AICurlInterface::Stats::BufferedCurlEasyRequest_count++;
|
AICurlInterface::Stats::BufferedCurlEasyRequest_count++;
|
||||||
}
|
}
|
||||||
@@ -1370,7 +1334,7 @@ void BufferedCurlEasyRequest::resetState(void)
|
|||||||
mOutput.reset();
|
mOutput.reset();
|
||||||
mInput.reset();
|
mInput.reset();
|
||||||
mRequestTransferedBytes = 0;
|
mRequestTransferedBytes = 0;
|
||||||
mResponseTransferedBytes = 0;
|
mTotalRawBytes = 0;
|
||||||
mBufferEventsTarget = NULL;
|
mBufferEventsTarget = NULL;
|
||||||
mStatus = HTTP_INTERNAL_ERROR_OTHER;
|
mStatus = HTTP_INTERNAL_ERROR_OTHER;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@
|
|||||||
#include "stdtypes.h" // U16, S32, U32, F64
|
#include "stdtypes.h" // U16, S32, U32, F64
|
||||||
#include "llatomic.h" // LLAtomicU32
|
#include "llatomic.h" // LLAtomicU32
|
||||||
#include "aithreadsafe.h"
|
#include "aithreadsafe.h"
|
||||||
|
#include "aicurlperservice.h" // AIPerServicePtr
|
||||||
|
|
||||||
// Debug Settings.
|
// Debug Settings.
|
||||||
extern bool gNoVerifySSLCert;
|
extern bool gNoVerifySSLCert;
|
||||||
@@ -60,6 +61,7 @@ class LLSD;
|
|||||||
class LLBufferArray;
|
class LLBufferArray;
|
||||||
class LLChannelDescriptors;
|
class LLChannelDescriptors;
|
||||||
class AIHTTPTimeoutPolicy;
|
class AIHTTPTimeoutPolicy;
|
||||||
|
class LLControlGroup;
|
||||||
|
|
||||||
// Some pretty printing for curl easy handle related things:
|
// Some pretty printing for curl easy handle related things:
|
||||||
// Print the lock object related to the current easy handle in every debug output.
|
// Print the lock object related to the current easy handle in every debug output.
|
||||||
@@ -133,6 +135,7 @@ struct Stats {
|
|||||||
static LLAtomicU32 easy_cleanup_calls;
|
static LLAtomicU32 easy_cleanup_calls;
|
||||||
static LLAtomicU32 multi_calls;
|
static LLAtomicU32 multi_calls;
|
||||||
static LLAtomicU32 multi_errors;
|
static LLAtomicU32 multi_errors;
|
||||||
|
static LLAtomicU32 running_handles;
|
||||||
static LLAtomicU32 AICurlEasyRequest_count;
|
static LLAtomicU32 AICurlEasyRequest_count;
|
||||||
static LLAtomicU32 AICurlEasyRequestStateMachine_count;
|
static LLAtomicU32 AICurlEasyRequestStateMachine_count;
|
||||||
static LLAtomicU32 BufferedCurlEasyRequest_count;
|
static LLAtomicU32 BufferedCurlEasyRequest_count;
|
||||||
@@ -153,7 +156,7 @@ struct Stats {
|
|||||||
|
|
||||||
// Called to handle changes in Debug Settings.
|
// Called to handle changes in Debug Settings.
|
||||||
bool handleCurlMaxTotalConcurrentConnections(LLSD const& newvalue);
|
bool handleCurlMaxTotalConcurrentConnections(LLSD const& newvalue);
|
||||||
bool handleCurlConcurrentConnectionsPerHost(LLSD const& newvalue);
|
bool handleCurlConcurrentConnectionsPerService(LLSD const& newvalue);
|
||||||
bool handleNoVerifySSLCert(LLSD const& newvalue);
|
bool handleNoVerifySSLCert(LLSD const& newvalue);
|
||||||
|
|
||||||
// Called once at start of application (from newview/llappviewer.cpp by main thread (before threads are created)),
|
// Called once at start of application (from newview/llappviewer.cpp by main thread (before threads are created)),
|
||||||
@@ -161,7 +164,7 @@ bool handleNoVerifySSLCert(LLSD const& newvalue);
|
|||||||
void initCurl(void);
|
void initCurl(void);
|
||||||
|
|
||||||
// Called once at start of application (from LLAppViewer::initThreads), starts AICurlThread.
|
// Called once at start of application (from LLAppViewer::initThreads), starts AICurlThread.
|
||||||
void startCurlThread(U32 CurlMaxTotalConcurrentConnections, U32 CurlConcurrentConnectionsPerHost, bool NoVerifySSLCert);
|
void startCurlThread(LLControlGroup* control_group);
|
||||||
|
|
||||||
// Called once at the end of application before terminating other threads (most notably the texture thread workers)
|
// 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
|
// with the purpose to stop the curl thread from doing any call backs to running responders: the responders sometimes
|
||||||
@@ -185,6 +188,22 @@ void setCAFile(std::string const& file);
|
|||||||
// Can be used to set the path to the Certificate Authority file.
|
// Can be used to set the path to the Certificate Authority file.
|
||||||
void setCAPath(std::string const& file);
|
void setCAPath(std::string const& file);
|
||||||
|
|
||||||
|
// Returns number of queued 'add' commands minus the number of queued 'remove' commands.
|
||||||
|
U32 getNumHTTPCommands(void);
|
||||||
|
|
||||||
|
// Returns the number of queued requests.
|
||||||
|
U32 getNumHTTPQueued(void);
|
||||||
|
|
||||||
|
// Returns the number of curl requests currently added to the multi handle.
|
||||||
|
U32 getNumHTTPAdded(void);
|
||||||
|
|
||||||
|
// This used to be LLAppViewer::getTextureFetch()->getNumHTTPRequests().
|
||||||
|
// Returns the number of active curl easy handles (that are actually attempting to download something).
|
||||||
|
U32 getNumHTTPRunning(void);
|
||||||
|
|
||||||
|
// Cache for gSavedSettings so we have access from llmessage.
|
||||||
|
extern LLControlGroup* sConfigGroup;
|
||||||
|
|
||||||
} // namespace AICurlInterface
|
} // namespace AICurlInterface
|
||||||
|
|
||||||
// Forward declaration (see aicurlprivate.h).
|
// Forward declaration (see aicurlprivate.h).
|
||||||
|
|||||||
@@ -1,175 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file aiperhost.cpp
|
|
||||||
* @brief Implementation of PerHostRequestQueue
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* 04/11/2012
|
|
||||||
* Initial version, written by Aleric Inglewood @ SL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "sys.h"
|
|
||||||
#include "aicurlperhost.h"
|
|
||||||
#include "aicurlthread.h"
|
|
||||||
|
|
||||||
#undef AICurlPrivate
|
|
||||||
|
|
||||||
namespace AICurlPrivate {
|
|
||||||
|
|
||||||
PerHostRequestQueue::threadsafe_instance_map_type PerHostRequestQueue::sInstanceMap;
|
|
||||||
U32 curl_concurrent_connections_per_host;
|
|
||||||
|
|
||||||
//static
|
|
||||||
PerHostRequestQueuePtr PerHostRequestQueue::instance(std::string const& hostname)
|
|
||||||
{
|
|
||||||
llassert(!hostname.empty());
|
|
||||||
instance_map_wat instance_map_w(sInstanceMap);
|
|
||||||
PerHostRequestQueue::iterator iter = instance_map_w->find(hostname);
|
|
||||||
if (iter == instance_map_w->end())
|
|
||||||
{
|
|
||||||
iter = instance_map_w->insert(instance_map_type::value_type(hostname, new RefCountedThreadSafePerHostRequestQueue)).first;
|
|
||||||
}
|
|
||||||
// Note: the creation of PerHostRequestQueuePtr MUST be protected by the lock on sInstanceMap (see release()).
|
|
||||||
return iter->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
//static
|
|
||||||
void PerHostRequestQueue::release(PerHostRequestQueuePtr& instance)
|
|
||||||
{
|
|
||||||
if (instance->exactly_two_left()) // Being 'instance' and the one in sInstanceMap.
|
|
||||||
{
|
|
||||||
// The viewer can be have left main() we can't access the global sInstanceMap anymore.
|
|
||||||
if (LLApp::isStopped())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
instance_map_wat instance_map_w(sInstanceMap);
|
|
||||||
// It is possible that 'exactly_two_left' is not up to date anymore.
|
|
||||||
// Therefore, recheck the condition now that we have locked sInstanceMap.
|
|
||||||
if (!instance->exactly_two_left())
|
|
||||||
{
|
|
||||||
// Some other thread added this host in the meantime.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// The reference in the map is the last one; that means there can't be any curl easy requests queued for this host.
|
|
||||||
llassert(PerHostRequestQueue_wat(*instance)->mQueuedRequests.empty());
|
|
||||||
// Find the host and erase it from the map.
|
|
||||||
iterator const end = instance_map_w->end();
|
|
||||||
for(iterator iter = instance_map_w->begin(); iter != end; ++iter)
|
|
||||||
{
|
|
||||||
if (instance == iter->second)
|
|
||||||
{
|
|
||||||
instance_map_w->erase(iter);
|
|
||||||
instance.reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// We should always find the host.
|
|
||||||
llassert(false);
|
|
||||||
}
|
|
||||||
instance.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PerHostRequestQueue::throttled() const
|
|
||||||
{
|
|
||||||
llassert(mAdded <= int(curl_concurrent_connections_per_host));
|
|
||||||
return mAdded == int(curl_concurrent_connections_per_host);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PerHostRequestQueue::added_to_multi_handle(void)
|
|
||||||
{
|
|
||||||
llassert(mAdded < int(curl_concurrent_connections_per_host));
|
|
||||||
++mAdded;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PerHostRequestQueue::removed_from_multi_handle(void)
|
|
||||||
{
|
|
||||||
--mAdded;
|
|
||||||
llassert(mAdded >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PerHostRequestQueue::queue(AICurlEasyRequest const& easy_request)
|
|
||||||
{
|
|
||||||
mQueuedRequests.push_back(easy_request.get_ptr());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PerHostRequestQueue::cancel(AICurlEasyRequest const& easy_request)
|
|
||||||
{
|
|
||||||
queued_request_type::iterator const end = mQueuedRequests.end();
|
|
||||||
queued_request_type::iterator cur = std::find(mQueuedRequests.begin(), end, easy_request.get_ptr());
|
|
||||||
|
|
||||||
if (cur == end)
|
|
||||||
return false; // Not found.
|
|
||||||
|
|
||||||
// We can't use erase because that uses assignment to move elements,
|
|
||||||
// because it isn't thread-safe. Therefore, move the element that we found to
|
|
||||||
// the back with swap (could just swap with the end immediately, but I don't
|
|
||||||
// want to break the order in which requests where added). Swap is also not
|
|
||||||
// thread-safe, but OK here because it only touches the objects in the deque,
|
|
||||||
// and the deque is protected by the lock on the PerHostRequestQueue object.
|
|
||||||
queued_request_type::iterator prev = cur;
|
|
||||||
while (++cur != end)
|
|
||||||
{
|
|
||||||
prev->swap(*cur); // This is safe,
|
|
||||||
prev = cur;
|
|
||||||
}
|
|
||||||
mQueuedRequests.pop_back(); // if this is safe.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PerHostRequestQueue::add_queued_to(curlthread::MultiHandle* multi_handle)
|
|
||||||
{
|
|
||||||
if (!mQueuedRequests.empty())
|
|
||||||
{
|
|
||||||
multi_handle->add_easy_request(mQueuedRequests.front());
|
|
||||||
mQueuedRequests.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//static
|
|
||||||
void PerHostRequestQueue::purge(void)
|
|
||||||
{
|
|
||||||
instance_map_wat instance_map_w(sInstanceMap);
|
|
||||||
for (iterator host = instance_map_w->begin(); host != instance_map_w->end(); ++host)
|
|
||||||
{
|
|
||||||
Dout(dc::curl, "Purging queue of host \"" << host->first << "\".");
|
|
||||||
PerHostRequestQueue_wat(*host->second)->mQueuedRequests.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Friend functions of RefCountedThreadSafePerHostRequestQueue
|
|
||||||
|
|
||||||
void intrusive_ptr_add_ref(RefCountedThreadSafePerHostRequestQueue* per_host)
|
|
||||||
{
|
|
||||||
per_host->mReferenceCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void intrusive_ptr_release(RefCountedThreadSafePerHostRequestQueue* per_host)
|
|
||||||
{
|
|
||||||
if (--per_host->mReferenceCount == 0)
|
|
||||||
{
|
|
||||||
delete per_host;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace AICurlPrivate
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file aicurlperhost.h
|
|
||||||
* @brief Definition of class PerHostRequestQueue
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* 04/11/2012
|
|
||||||
* Initial version, written by Aleric Inglewood @ SL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef AICURLPERHOST_H
|
|
||||||
#define AICURLPERHOST_H
|
|
||||||
|
|
||||||
#include "llerror.h" // llassert
|
|
||||||
#include <string>
|
|
||||||
#include <deque>
|
|
||||||
#include <map>
|
|
||||||
#include <boost/intrusive_ptr.hpp>
|
|
||||||
#include "aithreadsafe.h"
|
|
||||||
|
|
||||||
class AICurlEasyRequest;
|
|
||||||
|
|
||||||
namespace AICurlPrivate {
|
|
||||||
namespace curlthread { class MultiHandle; }
|
|
||||||
|
|
||||||
class PerHostRequestQueue;
|
|
||||||
class RefCountedThreadSafePerHostRequestQueue;
|
|
||||||
class ThreadSafeBufferedCurlEasyRequest;
|
|
||||||
|
|
||||||
// Forward declaration of BufferedCurlEasyRequestPtr (see aicurlprivate.h).
|
|
||||||
typedef boost::intrusive_ptr<ThreadSafeBufferedCurlEasyRequest> BufferedCurlEasyRequestPtr;
|
|
||||||
|
|
||||||
// PerHostRequestQueue objects are created by the curl thread and destructed by the main thread.
|
|
||||||
// We need locking.
|
|
||||||
typedef AIThreadSafeSimpleDC<PerHostRequestQueue> threadsafe_PerHostRequestQueue;
|
|
||||||
typedef AIAccessConst<PerHostRequestQueue> PerHostRequestQueue_crat;
|
|
||||||
typedef AIAccess<PerHostRequestQueue> PerHostRequestQueue_rat;
|
|
||||||
typedef AIAccess<PerHostRequestQueue> PerHostRequestQueue_wat;
|
|
||||||
|
|
||||||
// We can't put threadsafe_PerHostRequestQueue in a std::map because you can't copy a mutex.
|
|
||||||
// Therefore, use an intrusive pointer for the threadsafe type.
|
|
||||||
typedef boost::intrusive_ptr<RefCountedThreadSafePerHostRequestQueue> PerHostRequestQueuePtr;
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// PerHostRequestQueue
|
|
||||||
|
|
||||||
// This class provides a static interface to create and maintain instances
|
|
||||||
// of PerHostRequestQueue objects, so that at any moment there is at most
|
|
||||||
// one instance per hostname. Those instances then are used to queue curl
|
|
||||||
// requests when the maximum number of connections for that host already
|
|
||||||
// have been reached.
|
|
||||||
class PerHostRequestQueue {
|
|
||||||
private:
|
|
||||||
typedef std::map<std::string, PerHostRequestQueuePtr> instance_map_type;
|
|
||||||
typedef AIThreadSafeSimpleDC<instance_map_type> threadsafe_instance_map_type;
|
|
||||||
typedef AIAccess<instance_map_type> instance_map_rat;
|
|
||||||
typedef AIAccess<instance_map_type> instance_map_wat;
|
|
||||||
|
|
||||||
static threadsafe_instance_map_type sInstanceMap; // Map of PerHostRequestQueue instances with the hostname as key.
|
|
||||||
|
|
||||||
friend class AIThreadSafeSimpleDC<PerHostRequestQueue>; //threadsafe_PerHostRequestQueue
|
|
||||||
PerHostRequestQueue(void) : mAdded(0) { }
|
|
||||||
|
|
||||||
public:
|
|
||||||
typedef instance_map_type::iterator iterator;
|
|
||||||
typedef instance_map_type::const_iterator const_iterator;
|
|
||||||
|
|
||||||
// Return (possibly create) a unique instance for the given hostname.
|
|
||||||
static PerHostRequestQueuePtr instance(std::string const& hostname);
|
|
||||||
|
|
||||||
// Release instance (object will be deleted if this was the last instance).
|
|
||||||
static void release(PerHostRequestQueuePtr& instance);
|
|
||||||
|
|
||||||
// Remove everything. Called upon viewer exit.
|
|
||||||
static void purge(void);
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef std::deque<BufferedCurlEasyRequestPtr> queued_request_type;
|
|
||||||
|
|
||||||
int mAdded; // Number of active easy handles with this host.
|
|
||||||
queued_request_type mQueuedRequests; // Waiting (throttled) requests.
|
|
||||||
|
|
||||||
public:
|
|
||||||
void added_to_multi_handle(void); // Called when an easy handle for this host has been added to the multi handle.
|
|
||||||
void removed_from_multi_handle(void); // Called when an easy handle for this host is removed again from the multi handle.
|
|
||||||
bool throttled(void) const; // Returns true if the maximum number of allowed requests for this host have been added to the multi handle.
|
|
||||||
|
|
||||||
void queue(AICurlEasyRequest const& easy_request); // Add easy_request to the queue.
|
|
||||||
bool cancel(AICurlEasyRequest const& easy_request); // Remove easy_request from the queue (if it's there).
|
|
||||||
|
|
||||||
void add_queued_to(curlthread::MultiHandle* mh); // Add queued easy handle (if any) to the multi handle. The request is removed from the queue,
|
|
||||||
// followed by either a call to added_to_multi_handle() or to queue() to add it back.
|
|
||||||
private:
|
|
||||||
// Disallow copying.
|
|
||||||
PerHostRequestQueue(PerHostRequestQueue const&) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
class RefCountedThreadSafePerHostRequestQueue : public threadsafe_PerHostRequestQueue {
|
|
||||||
public:
|
|
||||||
RefCountedThreadSafePerHostRequestQueue(void) : mReferenceCount(0) { }
|
|
||||||
bool exactly_two_left(void) const { return mReferenceCount == 2; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Used by PerHostRequestQueuePtr. Object is deleted when reference count reaches zero.
|
|
||||||
LLAtomicU32 mReferenceCount;
|
|
||||||
|
|
||||||
friend void intrusive_ptr_add_ref(RefCountedThreadSafePerHostRequestQueue* p);
|
|
||||||
friend void intrusive_ptr_release(RefCountedThreadSafePerHostRequestQueue* p);
|
|
||||||
};
|
|
||||||
|
|
||||||
extern U32 curl_concurrent_connections_per_host;
|
|
||||||
|
|
||||||
} // namespace AICurlPrivate
|
|
||||||
|
|
||||||
#endif // AICURLPERHOST_H
|
|
||||||
368
indra/llmessage/aicurlperservice.cpp
Normal file
368
indra/llmessage/aicurlperservice.cpp
Normal file
@@ -0,0 +1,368 @@
|
|||||||
|
/**
|
||||||
|
* @file aiperservice.cpp
|
||||||
|
* @brief Implementation of AIPerService
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, 2013, 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.
|
||||||
|
*
|
||||||
|
* 04/11/2012
|
||||||
|
* Initial version, written by Aleric Inglewood @ SL
|
||||||
|
*
|
||||||
|
* 06/04/2013
|
||||||
|
* Renamed AICurlPrivate::PerHostRequestQueue[Ptr] to AIPerHostRequestQueue[Ptr]
|
||||||
|
* to allow public access.
|
||||||
|
*
|
||||||
|
* 09/04/2013
|
||||||
|
* Renamed everything "host" to "service" and use "hostname:port" as key
|
||||||
|
* instead of just "hostname".
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sys.h"
|
||||||
|
#include "aicurlperservice.h"
|
||||||
|
#include "aicurlthread.h"
|
||||||
|
#include "llcontrol.h"
|
||||||
|
|
||||||
|
AIPerService::threadsafe_instance_map_type AIPerService::sInstanceMap;
|
||||||
|
AIThreadSafeSimpleDC<AIPerService::TotalQueued> AIPerService::sTotalQueued;
|
||||||
|
|
||||||
|
#undef AICurlPrivate
|
||||||
|
|
||||||
|
namespace AICurlPrivate {
|
||||||
|
|
||||||
|
// Cached value of CurlConcurrentConnectionsPerService.
|
||||||
|
U32 CurlConcurrentConnectionsPerService;
|
||||||
|
|
||||||
|
// Friend functions of RefCountedThreadSafePerService
|
||||||
|
|
||||||
|
void intrusive_ptr_add_ref(RefCountedThreadSafePerService* per_service)
|
||||||
|
{
|
||||||
|
per_service->mReferenceCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void intrusive_ptr_release(RefCountedThreadSafePerService* per_service)
|
||||||
|
{
|
||||||
|
if (--per_service->mReferenceCount == 0)
|
||||||
|
{
|
||||||
|
delete per_service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace AICurlPrivate
|
||||||
|
|
||||||
|
using namespace AICurlPrivate;
|
||||||
|
|
||||||
|
AIPerService::AIPerService(void) :
|
||||||
|
mApprovedRequests(0), mQueuedCommands(0), mAdded(0), mQueueEmpty(false),
|
||||||
|
mQueueFull(false), mRequestStarvation(false), mHTTPBandwidth(25), // 25 = 1000 ms / 40 ms.
|
||||||
|
mConcurrectConnections(CurlConcurrentConnectionsPerService),
|
||||||
|
mMaxPipelinedRequests(CurlConcurrentConnectionsPerService)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AIPerService::~AIPerService()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fake copy constructor.
|
||||||
|
AIPerService::AIPerService(AIPerService const&) : mHTTPBandwidth(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// url must be of the form
|
||||||
|
// (see http://www.ietf.org/rfc/rfc3986.txt Appendix A for definitions not given here):
|
||||||
|
//
|
||||||
|
// url = sheme ":" hier-part [ "?" query ] [ "#" fragment ]
|
||||||
|
// hier-part = "//" authority path-abempty
|
||||||
|
// authority = [ userinfo "@" ] host [ ":" port ]
|
||||||
|
// path-abempty = *( "/" segment )
|
||||||
|
//
|
||||||
|
// That is, a hier-part of the form '/ path-absolute', '/ path-rootless' or
|
||||||
|
// '/ path-empty' is NOT allowed here. This should be safe because we only
|
||||||
|
// call this function for curl access, any file access would use APR.
|
||||||
|
//
|
||||||
|
// However, as a special exception, this function allows:
|
||||||
|
//
|
||||||
|
// url = authority path-abempty
|
||||||
|
//
|
||||||
|
// without the 'sheme ":" "//"' parts.
|
||||||
|
//
|
||||||
|
// As follows from the ABNF (see RFC, Appendix A):
|
||||||
|
// - authority is either terminated by a '/' or by the end of the string because
|
||||||
|
// neither userinfo, host nor port may contain a '/'.
|
||||||
|
// - userinfo does not contain a '@', and if it exists, is always terminated by a '@'.
|
||||||
|
// - port does not contain a ':', and if it exists is always prepended by a ':'.
|
||||||
|
//
|
||||||
|
//static
|
||||||
|
std::string AIPerService::extract_canonical_servicename(std::string const& url)
|
||||||
|
{
|
||||||
|
char const* p = url.data();
|
||||||
|
char const* const end = p + url.size();
|
||||||
|
char const* sheme_colon = NULL;
|
||||||
|
char const* sheme_slash = NULL;
|
||||||
|
char const* first_ampersand = NULL;
|
||||||
|
char const* port_colon = NULL;
|
||||||
|
std::string servicename;
|
||||||
|
char const* hostname = p; // Default in the case there is no "sheme://userinfo@".
|
||||||
|
while (p < end)
|
||||||
|
{
|
||||||
|
int c = *p;
|
||||||
|
if (c == ':')
|
||||||
|
{
|
||||||
|
if (!port_colon && LLStringOps::isDigit(p[1]))
|
||||||
|
{
|
||||||
|
port_colon = p;
|
||||||
|
}
|
||||||
|
else if (!sheme_colon && !sheme_slash && !first_ampersand && !port_colon)
|
||||||
|
{
|
||||||
|
// Found a colon before any slash or ampersand: this has to be the colon between the sheme and the hier-part.
|
||||||
|
sheme_colon = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == '/')
|
||||||
|
{
|
||||||
|
if (!sheme_slash && sheme_colon && sheme_colon == p - 1 && !first_ampersand && p[1] == '/')
|
||||||
|
{
|
||||||
|
// Found the first '/' in the first occurance of the sequence "://".
|
||||||
|
sheme_slash = p;
|
||||||
|
hostname = ++p + 1; // Point hostname to the start of the authority, the default when there is no "userinfo@" part.
|
||||||
|
servicename.clear(); // Remove the sheme.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Found slash that is not part of the "sheme://" string. Signals end of authority.
|
||||||
|
// We're done.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == '@')
|
||||||
|
{
|
||||||
|
if (!first_ampersand)
|
||||||
|
{
|
||||||
|
first_ampersand = p;
|
||||||
|
hostname = p + 1;
|
||||||
|
servicename.clear(); // Remove the "userinfo@"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p >= hostname)
|
||||||
|
{
|
||||||
|
// Convert hostname to lowercase in a way that we compare two hostnames equal iff libcurl does.
|
||||||
|
#if APR_CHARSET_EBCDIC
|
||||||
|
#error Not implemented
|
||||||
|
#else
|
||||||
|
if (c >= 'A' && c <= 'Z')
|
||||||
|
c += ('a' - 'A');
|
||||||
|
#endif
|
||||||
|
servicename += c;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
// Strip of any trailing ":80".
|
||||||
|
if (p - 3 == port_colon && p[-1] == '0' && p[-2] == '8')
|
||||||
|
{
|
||||||
|
return servicename.substr(0, p - hostname - 3);
|
||||||
|
}
|
||||||
|
return servicename;
|
||||||
|
}
|
||||||
|
|
||||||
|
//static
|
||||||
|
AIPerServicePtr AIPerService::instance(std::string const& servicename)
|
||||||
|
{
|
||||||
|
llassert(!servicename.empty());
|
||||||
|
instance_map_wat instance_map_w(sInstanceMap);
|
||||||
|
AIPerService::iterator iter = instance_map_w->find(servicename);
|
||||||
|
if (iter == instance_map_w->end())
|
||||||
|
{
|
||||||
|
iter = instance_map_w->insert(instance_map_type::value_type(servicename, new RefCountedThreadSafePerService)).first;
|
||||||
|
}
|
||||||
|
// Note: the creation of AIPerServicePtr MUST be protected by the lock on sInstanceMap (see release()).
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
//static
|
||||||
|
void AIPerService::release(AIPerServicePtr& instance)
|
||||||
|
{
|
||||||
|
if (instance->exactly_two_left()) // Being 'instance' and the one in sInstanceMap.
|
||||||
|
{
|
||||||
|
// The viewer can be have left main() we can't access the global sInstanceMap anymore.
|
||||||
|
if (LLApp::isStopped())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
instance_map_wat instance_map_w(sInstanceMap);
|
||||||
|
// It is possible that 'exactly_two_left' is not up to date anymore.
|
||||||
|
// Therefore, recheck the condition now that we have locked sInstanceMap.
|
||||||
|
if (!instance->exactly_two_left())
|
||||||
|
{
|
||||||
|
// Some other thread added this host in the meantime.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// The reference in the map is the last one; that means there can't be any curl easy requests queued for this host.
|
||||||
|
llassert(PerService_rat(*instance)->mQueuedRequests.empty());
|
||||||
|
// Find the host and erase it from the map.
|
||||||
|
iterator const end = instance_map_w->end();
|
||||||
|
for(iterator iter = instance_map_w->begin(); iter != end; ++iter)
|
||||||
|
{
|
||||||
|
if (instance == iter->second)
|
||||||
|
{
|
||||||
|
instance_map_w->erase(iter);
|
||||||
|
instance.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We should always find the host.
|
||||||
|
llassert(false);
|
||||||
|
}
|
||||||
|
instance.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AIPerService::throttled() const
|
||||||
|
{
|
||||||
|
return mAdded >= mConcurrectConnections;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AIPerService::added_to_multi_handle(void)
|
||||||
|
{
|
||||||
|
++mAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AIPerService::removed_from_multi_handle(void)
|
||||||
|
{
|
||||||
|
--mAdded;
|
||||||
|
llassert(mAdded >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AIPerService::queue(AICurlEasyRequest const& easy_request)
|
||||||
|
{
|
||||||
|
mQueuedRequests.push_back(easy_request.get_ptr());
|
||||||
|
TotalQueued_wat(sTotalQueued)->count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AIPerService::cancel(AICurlEasyRequest const& easy_request)
|
||||||
|
{
|
||||||
|
queued_request_type::iterator const end = mQueuedRequests.end();
|
||||||
|
queued_request_type::iterator cur = std::find(mQueuedRequests.begin(), end, easy_request.get_ptr());
|
||||||
|
|
||||||
|
if (cur == end)
|
||||||
|
return false; // Not found.
|
||||||
|
|
||||||
|
// We can't use erase because that uses assignment to move elements,
|
||||||
|
// because it isn't thread-safe. Therefore, move the element that we found to
|
||||||
|
// the back with swap (could just swap with the end immediately, but I don't
|
||||||
|
// want to break the order in which requests where added). Swap is also not
|
||||||
|
// thread-safe, but OK here because it only touches the objects in the deque,
|
||||||
|
// and the deque is protected by the lock on the AIPerService object.
|
||||||
|
queued_request_type::iterator prev = cur;
|
||||||
|
while (++cur != end)
|
||||||
|
{
|
||||||
|
prev->swap(*cur); // This is safe,
|
||||||
|
prev = cur;
|
||||||
|
}
|
||||||
|
mQueuedRequests.pop_back(); // if this is safe.
|
||||||
|
TotalQueued_wat total_queued_w(sTotalQueued);
|
||||||
|
total_queued_w->count--;
|
||||||
|
llassert(total_queued_w->count >= 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AIPerService::add_queued_to(curlthread::MultiHandle* multi_handle)
|
||||||
|
{
|
||||||
|
if (!mQueuedRequests.empty())
|
||||||
|
{
|
||||||
|
multi_handle->add_easy_request(mQueuedRequests.front());
|
||||||
|
mQueuedRequests.pop_front();
|
||||||
|
if (mQueuedRequests.empty())
|
||||||
|
{
|
||||||
|
// We obtained a request from the queue, and after that there we no more request in the queue of this host.
|
||||||
|
mQueueEmpty = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We obtained a request from the queue, and even after that there was at least one more request in the queue of this host.
|
||||||
|
mQueueFull = true;
|
||||||
|
}
|
||||||
|
TotalQueued_wat total_queued_w(sTotalQueued);
|
||||||
|
llassert(total_queued_w->count > 0);
|
||||||
|
if (!--(total_queued_w->count))
|
||||||
|
{
|
||||||
|
// We obtained a request from the queue, and after that there we no more request in any queue.
|
||||||
|
total_queued_w->empty = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We obtained a request from the queue, and even after that there was at least one more request in some queue.
|
||||||
|
total_queued_w->full = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We can add a new request, but there is none in the queue!
|
||||||
|
mRequestStarvation = true;
|
||||||
|
TotalQueued_wat total_queued_w(sTotalQueued);
|
||||||
|
if (total_queued_w->count == 0)
|
||||||
|
{
|
||||||
|
// The queue of every host is empty!
|
||||||
|
total_queued_w->starvation = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//static
|
||||||
|
void AIPerService::purge(void)
|
||||||
|
{
|
||||||
|
instance_map_wat instance_map_w(sInstanceMap);
|
||||||
|
for (iterator host = instance_map_w->begin(); host != instance_map_w->end(); ++host)
|
||||||
|
{
|
||||||
|
Dout(dc::curl, "Purging queue of host \"" << host->first << "\".");
|
||||||
|
PerService_wat per_service_w(*host->second);
|
||||||
|
size_t s = per_service_w->mQueuedRequests.size();
|
||||||
|
per_service_w->mQueuedRequests.clear();
|
||||||
|
TotalQueued_wat total_queued_w(sTotalQueued);
|
||||||
|
total_queued_w->count -= s;
|
||||||
|
llassert(total_queued_w->count >= 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//static
|
||||||
|
void AIPerService::adjust_concurrent_connections(int increment)
|
||||||
|
{
|
||||||
|
instance_map_wat instance_map_w(sInstanceMap);
|
||||||
|
for (AIPerService::iterator iter = instance_map_w->begin(); iter != instance_map_w->end(); ++iter)
|
||||||
|
{
|
||||||
|
PerService_wat per_service_w(*iter->second);
|
||||||
|
U32 old_concurrent_connections = per_service_w->mConcurrectConnections;
|
||||||
|
per_service_w->mConcurrectConnections = llclamp(old_concurrent_connections + increment, (U32)1, CurlConcurrentConnectionsPerService);
|
||||||
|
increment = per_service_w->mConcurrectConnections - old_concurrent_connections;
|
||||||
|
per_service_w->mMaxPipelinedRequests = llmax(per_service_w->mMaxPipelinedRequests + increment, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AIPerService::Approvement::honored(void)
|
||||||
|
{
|
||||||
|
if (!mHonored)
|
||||||
|
{
|
||||||
|
mHonored = true;
|
||||||
|
AICurlPrivate::PerService_wat per_service_w(*mPerServicePtr);
|
||||||
|
llassert(per_service_w->mApprovedRequests > 0);
|
||||||
|
per_service_w->mApprovedRequests--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
251
indra/llmessage/aicurlperservice.h
Normal file
251
indra/llmessage/aicurlperservice.h
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
/**
|
||||||
|
* @file aicurlperservice.h
|
||||||
|
* @brief Definition of class AIPerService
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, 2013, 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.
|
||||||
|
*
|
||||||
|
* 04/11/2012
|
||||||
|
* Initial version, written by Aleric Inglewood @ SL
|
||||||
|
*
|
||||||
|
* 06/04/2013
|
||||||
|
* Renamed AIPrivate::PerHostRequestQueue[Ptr] to AIPerHostRequestQueue[Ptr]
|
||||||
|
* to allow public access.
|
||||||
|
*
|
||||||
|
* 09/04/2013
|
||||||
|
* Renamed everything "host" to "service" and use "hostname:port" as key
|
||||||
|
* instead of just "hostname".
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AICURLPERSERVICE_H
|
||||||
|
#define AICURLPERSERVICE_H
|
||||||
|
|
||||||
|
#include "llerror.h" // llassert
|
||||||
|
#include <string>
|
||||||
|
#include <deque>
|
||||||
|
#include <map>
|
||||||
|
#include <boost/intrusive_ptr.hpp>
|
||||||
|
#include "aithreadsafe.h"
|
||||||
|
#include "aiaverage.h"
|
||||||
|
|
||||||
|
class AICurlEasyRequest;
|
||||||
|
class AIPerService;
|
||||||
|
|
||||||
|
namespace AICurlPrivate {
|
||||||
|
namespace curlthread { class MultiHandle; }
|
||||||
|
|
||||||
|
class RefCountedThreadSafePerService;
|
||||||
|
class ThreadSafeBufferedCurlEasyRequest;
|
||||||
|
|
||||||
|
// Forward declaration of BufferedCurlEasyRequestPtr (see aicurlprivate.h).
|
||||||
|
typedef boost::intrusive_ptr<ThreadSafeBufferedCurlEasyRequest> BufferedCurlEasyRequestPtr;
|
||||||
|
|
||||||
|
// AIPerService objects are created by the curl thread and destructed by the main thread.
|
||||||
|
// We need locking.
|
||||||
|
typedef AIThreadSafeSimpleDC<AIPerService> threadsafe_PerService;
|
||||||
|
typedef AIAccessConst<AIPerService> PerService_crat;
|
||||||
|
typedef AIAccess<AIPerService> PerService_rat;
|
||||||
|
typedef AIAccess<AIPerService> PerService_wat;
|
||||||
|
|
||||||
|
} // namespace AICurlPrivate
|
||||||
|
|
||||||
|
// We can't put threadsafe_PerService in a std::map because you can't copy a mutex.
|
||||||
|
// Therefore, use an intrusive pointer for the threadsafe type.
|
||||||
|
typedef boost::intrusive_ptr<AICurlPrivate::RefCountedThreadSafePerService> AIPerServicePtr;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// AIPerService
|
||||||
|
|
||||||
|
// This class provides a static interface to create and maintain instances of AIPerService objects,
|
||||||
|
// so that at any moment there is at most one instance per service (hostname:port).
|
||||||
|
// Those instances then are used to queue curl requests when the maximum number of connections
|
||||||
|
// for that service already have been reached. And to keep track of the bandwidth usage, and the
|
||||||
|
// number of queued requests in the pipeline, for this service.
|
||||||
|
class AIPerService {
|
||||||
|
private:
|
||||||
|
typedef std::map<std::string, AIPerServicePtr> instance_map_type;
|
||||||
|
typedef AIThreadSafeSimpleDC<instance_map_type> threadsafe_instance_map_type;
|
||||||
|
typedef AIAccess<instance_map_type> instance_map_rat;
|
||||||
|
typedef AIAccess<instance_map_type> instance_map_wat;
|
||||||
|
|
||||||
|
static threadsafe_instance_map_type sInstanceMap; // Map of AIPerService instances with the hostname as key.
|
||||||
|
|
||||||
|
friend class AIThreadSafeSimpleDC<AIPerService>; // threadsafe_PerService
|
||||||
|
AIPerService(void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
~AIPerService();
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef instance_map_type::iterator iterator;
|
||||||
|
typedef instance_map_type::const_iterator const_iterator;
|
||||||
|
|
||||||
|
// Utility function; extract canonical (lowercase) hostname and port from url.
|
||||||
|
static std::string extract_canonical_servicename(std::string const& url);
|
||||||
|
|
||||||
|
// Return (possibly create) a unique instance for the given hostname.
|
||||||
|
static AIPerServicePtr instance(std::string const& servicename);
|
||||||
|
|
||||||
|
// Release instance (object will be deleted if this was the last instance).
|
||||||
|
static void release(AIPerServicePtr& instance);
|
||||||
|
|
||||||
|
// Remove everything. Called upon viewer exit.
|
||||||
|
static void purge(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::deque<AICurlPrivate::BufferedCurlEasyRequestPtr> queued_request_type;
|
||||||
|
|
||||||
|
int mApprovedRequests; // The number of approved requests by wantsMoreHTTPRequestsFor that were not added to the command queue yet.
|
||||||
|
int mQueuedCommands; // Number of add commands (minus remove commands) with this host in the command queue.
|
||||||
|
int mAdded; // Number of active easy handles with this host.
|
||||||
|
queued_request_type mQueuedRequests; // Waiting (throttled) requests.
|
||||||
|
|
||||||
|
bool mQueueEmpty; // Set to true when the queue becomes precisely empty.
|
||||||
|
bool mQueueFull; // Set to true when the queue is popped and then still isn't empty;
|
||||||
|
bool mRequestStarvation; // Set to true when the queue was about to be popped but was already empty.
|
||||||
|
|
||||||
|
AIAverage mHTTPBandwidth; // Keeps track on number of bytes received for this service in the past second.
|
||||||
|
int mConcurrectConnections; // The maximum number of allowed concurrent connections to this service.
|
||||||
|
int mMaxPipelinedRequests; // The maximum number of accepted requests for this service that didn't finish yet.
|
||||||
|
|
||||||
|
// Global administration of the total number of queued requests of all services combined.
|
||||||
|
private:
|
||||||
|
struct TotalQueued {
|
||||||
|
S32 count; // The sum of mQueuedRequests.size() of all AIPerService objects together.
|
||||||
|
bool empty; // Set to true when count becomes precisely zero as the result of popping any queue.
|
||||||
|
bool full; // Set to true when count is still larger than zero after popping any queue.
|
||||||
|
bool starvation; // Set to true when any queue was about to be popped when count was already zero.
|
||||||
|
TotalQueued(void) : count(0), empty(false), full(false), starvation(false) { }
|
||||||
|
};
|
||||||
|
static AIThreadSafeSimpleDC<TotalQueued> sTotalQueued;
|
||||||
|
typedef AIAccessConst<TotalQueued> TotalQueued_crat;
|
||||||
|
typedef AIAccess<TotalQueued> TotalQueued_rat;
|
||||||
|
typedef AIAccess<TotalQueued> TotalQueued_wat;
|
||||||
|
public:
|
||||||
|
static S32 total_queued_size(void) { return TotalQueued_rat(sTotalQueued)->count; }
|
||||||
|
|
||||||
|
// Global administration of the maximum number of pipelined requests of all services combined.
|
||||||
|
private:
|
||||||
|
struct MaxPipelinedRequests {
|
||||||
|
S32 count; // The maximum total number of accepted requests that didn't finish yet.
|
||||||
|
U64 last_increment; // Last time that sMaxPipelinedRequests was incremented.
|
||||||
|
U64 last_decrement; // Last time that sMaxPipelinedRequests was decremented.
|
||||||
|
MaxPipelinedRequests(void) : count(32), last_increment(0), last_decrement(0) { }
|
||||||
|
};
|
||||||
|
static AIThreadSafeSimpleDC<MaxPipelinedRequests> sMaxPipelinedRequests;
|
||||||
|
typedef AIAccessConst<MaxPipelinedRequests> MaxPipelinedRequests_crat;
|
||||||
|
typedef AIAccess<MaxPipelinedRequests> MaxPipelinedRequests_rat;
|
||||||
|
typedef AIAccess<MaxPipelinedRequests> MaxPipelinedRequests_wat;
|
||||||
|
public:
|
||||||
|
static void setMaxPipelinedRequests(S32 count) { MaxPipelinedRequests_wat(sMaxPipelinedRequests)->count = count; }
|
||||||
|
static void incrementMaxPipelinedRequests(S32 increment) { MaxPipelinedRequests_wat(sMaxPipelinedRequests)->count += increment; }
|
||||||
|
|
||||||
|
// Global administration of throttle fraction (which is the same for all services).
|
||||||
|
private:
|
||||||
|
struct ThrottleFraction {
|
||||||
|
U32 fraction; // A value between 0 and 1024: each service is throttled when it uses more than max_bandwidth * (sThrottleFraction/1024) bandwidth.
|
||||||
|
AIAverage average; // Average of fraction over 25 * 40ms = 1 second.
|
||||||
|
U64 last_add; // Last time that faction was added to average.
|
||||||
|
ThrottleFraction(void) : fraction(1024), average(25), last_add(0) { }
|
||||||
|
};
|
||||||
|
static AIThreadSafeSimpleDC<ThrottleFraction> sThrottleFraction;
|
||||||
|
typedef AIAccessConst<ThrottleFraction> ThrottleFraction_crat;
|
||||||
|
typedef AIAccess<ThrottleFraction> ThrottleFraction_rat;
|
||||||
|
typedef AIAccess<ThrottleFraction> ThrottleFraction_wat;
|
||||||
|
|
||||||
|
static LLAtomicU32 sHTTPThrottleBandwidth125; // HTTPThrottleBandwidth times 125 (in bytes/s).
|
||||||
|
static bool sNoHTTPBandwidthThrottling; // Global override to disable bandwidth throttling.
|
||||||
|
|
||||||
|
public:
|
||||||
|
void added_to_command_queue(void) { ++mQueuedCommands; }
|
||||||
|
void removed_from_command_queue(void) { --mQueuedCommands; llassert(mQueuedCommands >= 0); }
|
||||||
|
void added_to_multi_handle(void); // Called when an easy handle for this host has been added to the multi handle.
|
||||||
|
void removed_from_multi_handle(void); // Called when an easy handle for this host is removed again from the multi handle.
|
||||||
|
bool throttled(void) const; // Returns true if the maximum number of allowed requests for this host have been added to the multi handle.
|
||||||
|
|
||||||
|
void queue(AICurlEasyRequest const& easy_request); // Add easy_request to the queue.
|
||||||
|
bool cancel(AICurlEasyRequest const& easy_request); // Remove easy_request from the queue (if it's there).
|
||||||
|
|
||||||
|
void add_queued_to(AICurlPrivate::curlthread::MultiHandle* mh);
|
||||||
|
// Add queued easy handle (if any) to the multi handle. The request is removed from the queue,
|
||||||
|
// followed by either a call to added_to_multi_handle() or to queue() to add it back.
|
||||||
|
|
||||||
|
S32 pipelined_requests(void) const { return mApprovedRequests + mQueuedCommands + mQueuedRequests.size() + mAdded; }
|
||||||
|
|
||||||
|
AIAverage& bandwidth(void) { return mHTTPBandwidth; }
|
||||||
|
AIAverage const& bandwidth(void) const { return mHTTPBandwidth; }
|
||||||
|
|
||||||
|
static void setNoHTTPBandwidthThrottling(bool nb) { sNoHTTPBandwidthThrottling = nb; }
|
||||||
|
static void setHTTPThrottleBandwidth(F32 max_kbps) { sHTTPThrottleBandwidth125 = 125.f * max_kbps; }
|
||||||
|
static size_t getHTTPThrottleBandwidth125(void) { return sHTTPThrottleBandwidth125; }
|
||||||
|
|
||||||
|
// Called when CurlConcurrentConnectionsPerService changes.
|
||||||
|
static void adjust_concurrent_connections(int increment);
|
||||||
|
|
||||||
|
// The two following functions are static and have the AIPerService object passed
|
||||||
|
// as first argument as an AIPerServicePtr because that avoids the need of having
|
||||||
|
// the AIPerService object locked for the whole duration of the call.
|
||||||
|
// The functions only lock it when access is required.
|
||||||
|
|
||||||
|
// Returns true if curl can handle another request for this host.
|
||||||
|
// Should return false if the maximum allowed HTTP bandwidth is reached, or when
|
||||||
|
// the latency between request and actual delivery becomes too large.
|
||||||
|
static bool wantsMoreHTTPRequestsFor(AIPerServicePtr const& per_service);
|
||||||
|
// Return true if too much bandwidth is being used.
|
||||||
|
static bool checkBandwidthUsage(AIPerServicePtr const& per_service, U64 sTime_40ms);
|
||||||
|
|
||||||
|
// A helper class to decrement mApprovedRequests after requests approved by wantsMoreHTTPRequestsFor were handled.
|
||||||
|
class Approvement {
|
||||||
|
private:
|
||||||
|
AIPerServicePtr mPerServicePtr;
|
||||||
|
bool mHonored;
|
||||||
|
public:
|
||||||
|
Approvement(AIPerServicePtr const& per_service) : mPerServicePtr(per_service), mHonored(false) { }
|
||||||
|
~Approvement() { honored(); }
|
||||||
|
void honored(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Disallow copying.
|
||||||
|
AIPerService(AIPerService const&);
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace AICurlPrivate {
|
||||||
|
|
||||||
|
class RefCountedThreadSafePerService : public threadsafe_PerService {
|
||||||
|
public:
|
||||||
|
RefCountedThreadSafePerService(void) : mReferenceCount(0) { }
|
||||||
|
bool exactly_two_left(void) const { return mReferenceCount == 2; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Used by AIPerServicePtr. Object is deleted when reference count reaches zero.
|
||||||
|
LLAtomicU32 mReferenceCount;
|
||||||
|
|
||||||
|
friend void intrusive_ptr_add_ref(RefCountedThreadSafePerService* p);
|
||||||
|
friend void intrusive_ptr_release(RefCountedThreadSafePerService* p);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern U32 CurlConcurrentConnectionsPerService;
|
||||||
|
|
||||||
|
} // namespace AICurlPrivate
|
||||||
|
|
||||||
|
#endif // AICURLPERSERVICE_H
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "llatomic.h"
|
#include "llatomic.h"
|
||||||
#include "llrefcount.h"
|
#include "llrefcount.h"
|
||||||
#include "aicurlperhost.h"
|
#include "aicurlperservice.h"
|
||||||
#include "aihttptimeout.h"
|
#include "aihttptimeout.h"
|
||||||
#include "llhttpclient.h"
|
#include "llhttpclient.h"
|
||||||
|
|
||||||
@@ -304,8 +304,8 @@ class CurlEasyRequest : public CurlEasyHandle {
|
|||||||
CURLcode mResult; //AIFIXME: this does not belong in the request object, but belongs in the response object.
|
CURLcode mResult; //AIFIXME: this does not belong in the request object, but belongs in the response object.
|
||||||
|
|
||||||
AIHTTPTimeoutPolicy const* mTimeoutPolicy;
|
AIHTTPTimeoutPolicy const* mTimeoutPolicy;
|
||||||
std::string mLowercaseHostname; // Lowercase hostname (canonicalized) extracted from the url.
|
std::string mLowercaseServicename; // Lowercase hostname:port (canonicalized) extracted from the url.
|
||||||
PerHostRequestQueuePtr mPerHostPtr; // Pointer to the corresponding PerHostRequestQueue.
|
AIPerServicePtr mPerServicePtr; // Pointer to the corresponding AIPerService.
|
||||||
LLPointer<curlthread::HTTPTimeout> mTimeout;// Timeout administration object associated with last created CurlSocketInfo.
|
LLPointer<curlthread::HTTPTimeout> mTimeout;// Timeout administration object associated with last created CurlSocketInfo.
|
||||||
bool mTimeoutIsOrphan; // Set to true when mTimeout is not (yet) associated with a CurlSocketInfo.
|
bool mTimeoutIsOrphan; // Set to true when mTimeout is not (yet) associated with a CurlSocketInfo.
|
||||||
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
|
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
|
||||||
@@ -316,7 +316,8 @@ class CurlEasyRequest : public CurlEasyHandle {
|
|||||||
public:
|
public:
|
||||||
// These two are only valid after finalizeRequest.
|
// These two are only valid after finalizeRequest.
|
||||||
AIHTTPTimeoutPolicy const* getTimeoutPolicy(void) const { return mTimeoutPolicy; }
|
AIHTTPTimeoutPolicy const* getTimeoutPolicy(void) const { return mTimeoutPolicy; }
|
||||||
std::string const& getLowercaseHostname(void) const { return mLowercaseHostname; }
|
std::string const& getLowercaseServicename(void) const { return mLowercaseServicename; }
|
||||||
|
std::string getLowercaseHostname(void) const;
|
||||||
// Called by CurlSocketInfo to allow access to the last (after a redirect) HTTPTimeout object related to this request.
|
// Called by CurlSocketInfo to allow access to the last (after a redirect) HTTPTimeout object related to this request.
|
||||||
// This creates mTimeout (unless mTimeoutIsOrphan is set in which case it adopts the orphan).
|
// This creates mTimeout (unless mTimeoutIsOrphan is set in which case it adopts the orphan).
|
||||||
LLPointer<curlthread::HTTPTimeout>& get_timeout_object(void);
|
LLPointer<curlthread::HTTPTimeout>& get_timeout_object(void);
|
||||||
@@ -347,10 +348,10 @@ class CurlEasyRequest : public CurlEasyHandle {
|
|||||||
inline ThreadSafeBufferedCurlEasyRequest* get_lockobj(void);
|
inline ThreadSafeBufferedCurlEasyRequest* get_lockobj(void);
|
||||||
inline ThreadSafeBufferedCurlEasyRequest const* get_lockobj(void) const;
|
inline ThreadSafeBufferedCurlEasyRequest const* get_lockobj(void) const;
|
||||||
|
|
||||||
// PerHost API.
|
// PerService API.
|
||||||
PerHostRequestQueuePtr getPerHostPtr(void); // (Optionally create and) return a pointer to the unique
|
AIPerServicePtr getPerServicePtr(void); // (Optionally create and) return a pointer to the unique
|
||||||
// PerHostRequestQueue corresponding to mLowercaseHostname.
|
// AIPerService corresponding to mLowercaseServicename.
|
||||||
bool removeFromPerHostQueue(AICurlEasyRequest const&) const; // Remove this request from the per-host queue, if queued at all.
|
bool removeFromPerServiceQueue(AICurlEasyRequest const&) const; // Remove this request from the per-host queue, if queued at all.
|
||||||
// Returns true if it was queued.
|
// Returns true if it was queued.
|
||||||
protected:
|
protected:
|
||||||
// Pass events to parent.
|
// Pass events to parent.
|
||||||
@@ -374,6 +375,9 @@ class BufferedCurlEasyRequest : public CurlEasyRequest {
|
|||||||
void resetState(void);
|
void resetState(void);
|
||||||
void prepRequest(AICurlEasyRequest_wat& buffered_curl_easy_request_w, AIHTTPHeaders const& headers, LLHTTPClient::ResponderPtr responder);
|
void prepRequest(AICurlEasyRequest_wat& buffered_curl_easy_request_w, AIHTTPHeaders const& headers, LLHTTPClient::ResponderPtr responder);
|
||||||
|
|
||||||
|
// Called if this request should be queued on the curl thread when too much bandwidth is being used.
|
||||||
|
void queue_if_too_much_bandwidth_usage(void) { mQueueIfTooMuchBandwidthUsage = true; }
|
||||||
|
|
||||||
buffer_ptr_t& getInput(void) { return mInput; }
|
buffer_ptr_t& getInput(void) { return mInput; }
|
||||||
buffer_ptr_t& getOutput(void) { return mOutput; }
|
buffer_ptr_t& getOutput(void) { return mOutput; }
|
||||||
|
|
||||||
@@ -395,6 +399,9 @@ class BufferedCurlEasyRequest : public CurlEasyRequest {
|
|||||||
// Post-initialization, set the parent to pass the events to.
|
// Post-initialization, set the parent to pass the events to.
|
||||||
void send_buffer_events_to(AIBufferedCurlEasyRequestEvents* target) { mBufferEventsTarget = target; }
|
void send_buffer_events_to(AIBufferedCurlEasyRequestEvents* target) { mBufferEventsTarget = target; }
|
||||||
|
|
||||||
|
// Called whenever new body data was (might be) received. Keeps track of the used HTTP bandwidth.
|
||||||
|
void update_body_bandwidth(void);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Events from this class.
|
// Events from this class.
|
||||||
/*virtual*/ void received_HTTP_header(void);
|
/*virtual*/ void received_HTTP_header(void);
|
||||||
@@ -410,13 +417,15 @@ class BufferedCurlEasyRequest : public CurlEasyRequest {
|
|||||||
U32 mStatus; // HTTP status, decoded from the first header line.
|
U32 mStatus; // HTTP status, decoded from the first header line.
|
||||||
std::string mReason; // The "reason" from the same header line.
|
std::string mReason; // The "reason" from the same header line.
|
||||||
U32 mRequestTransferedBytes;
|
U32 mRequestTransferedBytes;
|
||||||
U32 mResponseTransferedBytes;
|
size_t mTotalRawBytes; // Raw body data (still, possibly, compressed) received from the server so far.
|
||||||
AIBufferedCurlEasyRequestEvents* mBufferEventsTarget;
|
AIBufferedCurlEasyRequestEvents* mBufferEventsTarget;
|
||||||
|
bool mQueueIfTooMuchBandwidthUsage; // Set if the curl thread should check bandwidth usage and queue this request if too much is being used.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static LLChannelDescriptors const sChannels; // Channel object for mInput (channel out()) and mOutput (channel in()).
|
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 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.
|
static bool sShuttingDown; // If true, no additional calls to ResponderBase::finished will be made anymore.
|
||||||
|
static AIAverage sHTTPBandwidth; // HTTP bandwidth usage of all services combined.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// This class may only be created by constructing a ThreadSafeBufferedCurlEasyRequest.
|
// This class may only be created by constructing a ThreadSafeBufferedCurlEasyRequest.
|
||||||
@@ -447,6 +456,9 @@ class BufferedCurlEasyRequest : public CurlEasyRequest {
|
|||||||
// Return true when prepRequest was already called and the object has not been
|
// Return true when prepRequest was already called and the object has not been
|
||||||
// invalidated as a result of calling timed_out().
|
// invalidated as a result of calling timed_out().
|
||||||
bool isValid(void) const { return mResponder; }
|
bool isValid(void) const { return mResponder; }
|
||||||
|
|
||||||
|
// Returns true when this request should be queued by the curl thread when too much bandwidth is being used.
|
||||||
|
bool queueIfTooMuchBandwidthUsage(void) const { return mQueueIfTooMuchBandwidthUsage; }
|
||||||
};
|
};
|
||||||
|
|
||||||
inline ThreadSafeBufferedCurlEasyRequest* CurlEasyRequest::get_lockobj(void)
|
inline ThreadSafeBufferedCurlEasyRequest* CurlEasyRequest::get_lockobj(void)
|
||||||
|
|||||||
@@ -32,10 +32,12 @@
|
|||||||
#include "aicurlthread.h"
|
#include "aicurlthread.h"
|
||||||
#include "aihttptimeoutpolicy.h"
|
#include "aihttptimeoutpolicy.h"
|
||||||
#include "aihttptimeout.h"
|
#include "aihttptimeout.h"
|
||||||
#include "aicurlperhost.h"
|
#include "aicurlperservice.h"
|
||||||
|
#include "aiaverage.h"
|
||||||
#include "lltimer.h" // ms_sleep, get_clock_count
|
#include "lltimer.h" // ms_sleep, get_clock_count
|
||||||
#include "llhttpstatuscodes.h"
|
#include "llhttpstatuscodes.h"
|
||||||
#include "llbuffer.h"
|
#include "llbuffer.h"
|
||||||
|
#include "llcontrol.h"
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#if !LL_WINDOWS
|
#if !LL_WINDOWS
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
@@ -264,9 +266,15 @@ void Command::reset(void)
|
|||||||
//
|
//
|
||||||
// If at this point addRequest is called again, then it is detected that the ThreadSafeBufferedCurlEasyRequest is active.
|
// If at this point addRequest is called again, then it is detected that the ThreadSafeBufferedCurlEasyRequest is active.
|
||||||
|
|
||||||
|
struct command_queue_st {
|
||||||
|
std::deque<Command> commands; // The commands
|
||||||
|
size_t size; // Number of add commands in the queue minus the number of remove commands.
|
||||||
|
};
|
||||||
|
|
||||||
// Multi-threaded queue for passing Command objects from the main-thread to the curl-thread.
|
// Multi-threaded queue for passing Command objects from the main-thread to the curl-thread.
|
||||||
AIThreadSafeSimpleDC<std::deque<Command> > command_queue;
|
AIThreadSafeSimpleDC<command_queue_st> command_queue; // Fills 'size' with zero, because it's a global.
|
||||||
typedef AIAccess<std::deque<Command> > command_queue_wat;
|
typedef AIAccess<command_queue_st> command_queue_wat;
|
||||||
|
typedef AIAccess<command_queue_st> command_queue_rat;
|
||||||
|
|
||||||
AIThreadSafeDC<Command> command_being_processed;
|
AIThreadSafeDC<Command> command_being_processed;
|
||||||
typedef AIWriteAccess<Command> command_being_processed_wat;
|
typedef AIWriteAccess<Command> command_being_processed_wat;
|
||||||
@@ -880,7 +888,7 @@ AICurlThread* AICurlThread::sInstance = NULL;
|
|||||||
AICurlThread::AICurlThread(void) : LLThread("AICurlThread"),
|
AICurlThread::AICurlThread(void) : LLThread("AICurlThread"),
|
||||||
mWakeUpFd_in(CURL_SOCKET_BAD),
|
mWakeUpFd_in(CURL_SOCKET_BAD),
|
||||||
mWakeUpFd(CURL_SOCKET_BAD),
|
mWakeUpFd(CURL_SOCKET_BAD),
|
||||||
mZeroTimeout(0), mRunning(true), mWakeUpFlag(false)
|
mZeroTimeout(0), mWakeUpFlag(false), mRunning(true)
|
||||||
{
|
{
|
||||||
create_wakeup_fds();
|
create_wakeup_fds();
|
||||||
sInstance = this;
|
sInstance = this;
|
||||||
@@ -1289,7 +1297,7 @@ void AICurlThread::process_commands(AICurlMultiHandle_wat const& multi_handle_w)
|
|||||||
// Access command_queue, and move command to command_being_processed.
|
// Access command_queue, and move command to command_being_processed.
|
||||||
{
|
{
|
||||||
command_queue_wat command_queue_w(command_queue);
|
command_queue_wat command_queue_w(command_queue);
|
||||||
if (command_queue_w->empty())
|
if (command_queue_w->commands.empty())
|
||||||
{
|
{
|
||||||
mWakeUpFlagMutex.lock();
|
mWakeUpFlagMutex.lock();
|
||||||
mWakeUpFlag = false;
|
mWakeUpFlag = false;
|
||||||
@@ -1297,8 +1305,22 @@ void AICurlThread::process_commands(AICurlMultiHandle_wat const& multi_handle_w)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Move the next command from the queue into command_being_processed.
|
// Move the next command from the queue into command_being_processed.
|
||||||
*command_being_processed_wat(command_being_processed) = command_queue_w->front();
|
command_st command;
|
||||||
command_queue_w->pop_front();
|
{
|
||||||
|
command_being_processed_wat command_being_processed_w(command_being_processed);
|
||||||
|
*command_being_processed_w = command_queue_w->commands.front();
|
||||||
|
command = command_being_processed_w->command();
|
||||||
|
}
|
||||||
|
// Update the size: the number netto number of pending requests in the command queue.
|
||||||
|
command_queue_w->commands.pop_front();
|
||||||
|
if (command == cmd_add)
|
||||||
|
{
|
||||||
|
command_queue_w->size--;
|
||||||
|
}
|
||||||
|
else if (command == cmd_remove)
|
||||||
|
{
|
||||||
|
command_queue_w->size++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Access command_being_processed only.
|
// Access command_being_processed only.
|
||||||
{
|
{
|
||||||
@@ -1309,9 +1331,11 @@ void AICurlThread::process_commands(AICurlMultiHandle_wat const& multi_handle_w)
|
|||||||
case cmd_boost: // FIXME: future stuff
|
case cmd_boost: // FIXME: future stuff
|
||||||
break;
|
break;
|
||||||
case cmd_add:
|
case cmd_add:
|
||||||
|
PerService_wat(*AICurlEasyRequest_wat(*command_being_processed_r->easy_request())->getPerServicePtr())->removed_from_command_queue();
|
||||||
multi_handle_w->add_easy_request(AICurlEasyRequest(command_being_processed_r->easy_request()));
|
multi_handle_w->add_easy_request(AICurlEasyRequest(command_being_processed_r->easy_request()));
|
||||||
break;
|
break;
|
||||||
case cmd_remove:
|
case cmd_remove:
|
||||||
|
PerService_wat(*AICurlEasyRequest_wat(*command_being_processed_r->easy_request())->getPerServicePtr())->added_to_command_queue(); // Not really, but this has the same effect as 'removed a remove command'.
|
||||||
multi_handle_w->remove_easy_request(AICurlEasyRequest(command_being_processed_r->easy_request()), true);
|
multi_handle_w->remove_easy_request(AICurlEasyRequest(command_being_processed_r->easy_request()), true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1520,8 +1544,8 @@ void AICurlThread::run(void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Clock count used for timeouts.
|
// Clock count used for timeouts.
|
||||||
HTTPTimeout::sClockCount = get_clock_count();
|
HTTPTimeout::sTime_10ms = get_clock_count() * HTTPTimeout::sClockWidth_10ms;
|
||||||
Dout(dc::curl, "HTTPTimeout::sClockCount = " << HTTPTimeout::sClockCount);
|
Dout(dc::curl, "HTTPTimeout::sTime_10ms = " << HTTPTimeout::sTime_10ms);
|
||||||
if (ready == 0)
|
if (ready == 0)
|
||||||
{
|
{
|
||||||
multi_handle_w->socket_action(CURL_SOCKET_TIMEOUT, 0);
|
multi_handle_w->socket_action(CURL_SOCKET_TIMEOUT, 0);
|
||||||
@@ -1553,7 +1577,7 @@ void AICurlThread::run(void)
|
|||||||
multi_handle_w->check_msg_queue();
|
multi_handle_w->check_msg_queue();
|
||||||
}
|
}
|
||||||
// Clear the queued requests.
|
// Clear the queued requests.
|
||||||
PerHostRequestQueue::purge();
|
AIPerService::purge();
|
||||||
}
|
}
|
||||||
AICurlMultiHandle::destroyInstance();
|
AICurlMultiHandle::destroyInstance();
|
||||||
}
|
}
|
||||||
@@ -1561,6 +1585,8 @@ void AICurlThread::run(void)
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// MultiHandle
|
// MultiHandle
|
||||||
|
|
||||||
|
LLAtomicU32 MultiHandle::sTotalAdded;
|
||||||
|
|
||||||
MultiHandle::MultiHandle(void) : mTimeout(-1), mReadPollSet(NULL), mWritePollSet(NULL)
|
MultiHandle::MultiHandle(void) : mTimeout(-1), mReadPollSet(NULL), mWritePollSet(NULL)
|
||||||
{
|
{
|
||||||
mReadPollSet = new PollSet;
|
mReadPollSet = new PollSet;
|
||||||
@@ -1653,6 +1679,7 @@ CURLMcode MultiHandle::socket_action(curl_socket_t sockfd, int ev_bitmask)
|
|||||||
}
|
}
|
||||||
while(res == CURLM_CALL_MULTI_PERFORM);
|
while(res == CURLM_CALL_MULTI_PERFORM);
|
||||||
llassert(mAddedEasyRequests.size() >= (size_t)running_handles);
|
llassert(mAddedEasyRequests.size() >= (size_t)running_handles);
|
||||||
|
AICurlInterface::Stats::running_handles = running_handles;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1677,30 +1704,37 @@ static U32 curl_max_total_concurrent_connections = 32; // Initialized on st
|
|||||||
void MultiHandle::add_easy_request(AICurlEasyRequest const& easy_request)
|
void MultiHandle::add_easy_request(AICurlEasyRequest const& easy_request)
|
||||||
{
|
{
|
||||||
bool throttled = true; // Default.
|
bool throttled = true; // Default.
|
||||||
PerHostRequestQueuePtr per_host;
|
AIPerServicePtr per_service;
|
||||||
{
|
{
|
||||||
AICurlEasyRequest_wat curl_easy_request_w(*easy_request);
|
AICurlEasyRequest_wat curl_easy_request_w(*easy_request);
|
||||||
per_host = curl_easy_request_w->getPerHostPtr();
|
per_service = curl_easy_request_w->getPerServicePtr();
|
||||||
PerHostRequestQueue_wat per_host_w(*per_host);
|
bool too_much_bandwidth = curl_easy_request_w->queueIfTooMuchBandwidthUsage() && AIPerService::checkBandwidthUsage(per_service, get_clock_count() * HTTPTimeout::sClockWidth_40ms);
|
||||||
if (mAddedEasyRequests.size() < curl_max_total_concurrent_connections && !per_host_w->throttled())
|
PerService_wat per_service_w(*per_service);
|
||||||
|
if (!too_much_bandwidth && mAddedEasyRequests.size() < curl_max_total_concurrent_connections && !per_service_w->throttled())
|
||||||
{
|
{
|
||||||
curl_easy_request_w->set_timeout_opts();
|
curl_easy_request_w->set_timeout_opts();
|
||||||
if (curl_easy_request_w->add_handle_to_multi(curl_easy_request_w, mMultiHandle) == CURLM_OK)
|
if (curl_easy_request_w->add_handle_to_multi(curl_easy_request_w, mMultiHandle) == CURLM_OK)
|
||||||
{
|
{
|
||||||
per_host_w->added_to_multi_handle(); // (About to be) added to mAddedEasyRequests.
|
per_service_w->added_to_multi_handle(); // (About to be) added to mAddedEasyRequests.
|
||||||
throttled = false; // Fall through...
|
throttled = false; // Fall through...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // Release the lock on easy_request.
|
} // Release the lock on easy_request.
|
||||||
if (!throttled)
|
if (!throttled)
|
||||||
{ // ... to here.
|
{ // ... to here.
|
||||||
std::pair<addedEasyRequests_type::iterator, bool> res = mAddedEasyRequests.insert(easy_request);
|
#ifdef SHOW_ASSERT
|
||||||
|
std::pair<addedEasyRequests_type::iterator, bool> res =
|
||||||
|
#endif
|
||||||
|
mAddedEasyRequests.insert(easy_request);
|
||||||
llassert(res.second); // May not have been added before.
|
llassert(res.second); // May not have been added before.
|
||||||
Dout(dc::curl, "MultiHandle::add_easy_request: Added AICurlEasyRequest " << (void*)easy_request.get_ptr().get() << "; now processing " << mAddedEasyRequests.size() << " easy handles.");
|
sTotalAdded++;
|
||||||
|
llassert(sTotalAdded == mAddedEasyRequests.size());
|
||||||
|
Dout(dc::curl, "MultiHandle::add_easy_request: Added AICurlEasyRequest " << (void*)easy_request.get_ptr().get() <<
|
||||||
|
"; now processing " << mAddedEasyRequests.size() << " easy handles [running_handles = " << AICurlInterface::Stats::running_handles << "].");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The request could not be added, we have to queue it.
|
// The request could not be added, we have to queue it.
|
||||||
PerHostRequestQueue_wat(*per_host)->queue(easy_request);
|
PerService_wat(*per_service)->queue(easy_request);
|
||||||
#ifdef SHOW_ASSERT
|
#ifdef SHOW_ASSERT
|
||||||
// Not active yet, but it's no longer an error if next we try to remove the request.
|
// Not active yet, but it's no longer an error if next we try to remove the request.
|
||||||
AICurlEasyRequest_wat(*easy_request)->mRemovedPerCommand = false;
|
AICurlEasyRequest_wat(*easy_request)->mRemovedPerCommand = false;
|
||||||
@@ -1717,7 +1751,7 @@ CURLMcode MultiHandle::remove_easy_request(AICurlEasyRequest const& easy_request
|
|||||||
#ifdef SHOW_ASSERT
|
#ifdef SHOW_ASSERT
|
||||||
bool removed =
|
bool removed =
|
||||||
#endif
|
#endif
|
||||||
easy_request_w->removeFromPerHostQueue(easy_request);
|
easy_request_w->removeFromPerServiceQueue(easy_request);
|
||||||
#ifdef SHOW_ASSERT
|
#ifdef SHOW_ASSERT
|
||||||
if (removed)
|
if (removed)
|
||||||
{
|
{
|
||||||
@@ -1733,12 +1767,12 @@ CURLMcode MultiHandle::remove_easy_request(AICurlEasyRequest const& easy_request
|
|||||||
CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator const& iter, bool as_per_command)
|
CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator const& iter, bool as_per_command)
|
||||||
{
|
{
|
||||||
CURLMcode res;
|
CURLMcode res;
|
||||||
PerHostRequestQueuePtr per_host;
|
AIPerServicePtr per_service;
|
||||||
{
|
{
|
||||||
AICurlEasyRequest_wat curl_easy_request_w(**iter);
|
AICurlEasyRequest_wat curl_easy_request_w(**iter);
|
||||||
res = curl_easy_request_w->remove_handle_from_multi(curl_easy_request_w, mMultiHandle);
|
res = curl_easy_request_w->remove_handle_from_multi(curl_easy_request_w, mMultiHandle);
|
||||||
per_host = curl_easy_request_w->getPerHostPtr();
|
per_service = curl_easy_request_w->getPerServicePtr();
|
||||||
PerHostRequestQueue_wat(*per_host)->removed_from_multi_handle(); // (About to be) removed from mAddedEasyRequests.
|
PerService_wat(*per_service)->removed_from_multi_handle(); // (About to be) removed from mAddedEasyRequests.
|
||||||
#ifdef SHOW_ASSERT
|
#ifdef SHOW_ASSERT
|
||||||
curl_easy_request_w->mRemovedPerCommand = as_per_command;
|
curl_easy_request_w->mRemovedPerCommand = as_per_command;
|
||||||
#endif
|
#endif
|
||||||
@@ -1747,12 +1781,15 @@ CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator cons
|
|||||||
ThreadSafeBufferedCurlEasyRequest* lockobj = iter->get_ptr().get();
|
ThreadSafeBufferedCurlEasyRequest* lockobj = iter->get_ptr().get();
|
||||||
#endif
|
#endif
|
||||||
mAddedEasyRequests.erase(iter);
|
mAddedEasyRequests.erase(iter);
|
||||||
|
--sTotalAdded;
|
||||||
|
llassert(sTotalAdded == mAddedEasyRequests.size());
|
||||||
#if CWDEBUG
|
#if CWDEBUG
|
||||||
Dout(dc::curl, "MultiHandle::remove_easy_request: Removed AICurlEasyRequest " << (void*)lockobj << "; now processing " << mAddedEasyRequests.size() << " easy handles.");
|
Dout(dc::curl, "MultiHandle::remove_easy_request: Removed AICurlEasyRequest " << (void*)lockobj <<
|
||||||
|
"; now processing " << mAddedEasyRequests.size() << " easy handles [running_handles = " << AICurlInterface::Stats::running_handles << "].");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Attempt to add a queued request, if any.
|
// Attempt to add a queued request, if any.
|
||||||
PerHostRequestQueue_wat(*per_host)->add_queued_to(this);
|
PerService_wat(*per_service)->add_queued_to(this);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1795,6 +1832,8 @@ void MultiHandle::check_msg_queue(void)
|
|||||||
void MultiHandle::finish_easy_request(AICurlEasyRequest const& easy_request, CURLcode result)
|
void MultiHandle::finish_easy_request(AICurlEasyRequest const& easy_request, CURLcode result)
|
||||||
{
|
{
|
||||||
AICurlEasyRequest_wat curl_easy_request_w(*easy_request);
|
AICurlEasyRequest_wat curl_easy_request_w(*easy_request);
|
||||||
|
// Final body bandwidth update.
|
||||||
|
curl_easy_request_w->update_body_bandwidth();
|
||||||
// Store the result in the easy handle.
|
// Store the result in the easy handle.
|
||||||
curl_easy_request_w->storeResult(result);
|
curl_easy_request_w->storeResult(result);
|
||||||
#ifdef CWDEBUG
|
#ifdef CWDEBUG
|
||||||
@@ -1926,7 +1965,8 @@ void clearCommandQueue(void)
|
|||||||
{
|
{
|
||||||
// Clear the command queue now in order to avoid the global deinitialization order fiasco.
|
// Clear the command queue now in order to avoid the global deinitialization order fiasco.
|
||||||
command_queue_wat command_queue_w(command_queue);
|
command_queue_wat command_queue_w(command_queue);
|
||||||
command_queue_w->clear();
|
command_queue_w->commands.clear();
|
||||||
|
command_queue_w->size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@@ -1988,10 +2028,10 @@ void BufferedCurlEasyRequest::processOutput(void)
|
|||||||
if (responseCode == HTTP_INTERNAL_ERROR_LOW_SPEED)
|
if (responseCode == HTTP_INTERNAL_ERROR_LOW_SPEED)
|
||||||
{
|
{
|
||||||
// Rewrite error to something understandable.
|
// Rewrite error to something understandable.
|
||||||
responseReason = llformat("Connection to \"%s\" stalled: download speed dropped below %u bytes/s for %u seconds (up till that point, %s received a total of %u bytes). "
|
responseReason = llformat("Connection to \"%s\" stalled: download speed dropped below %u bytes/s for %u seconds (up till that point, %s received a total of %lu bytes). "
|
||||||
"To change these values, go to Advanced --> Debug Settings and change CurlTimeoutLowSpeedLimit and CurlTimeoutLowSpeedTime respectively.",
|
"To change these values, go to Advanced --> Debug Settings and change CurlTimeoutLowSpeedLimit and CurlTimeoutLowSpeedTime respectively.",
|
||||||
mResponder->getURL().c_str(), mResponder->getHTTPTimeoutPolicy().getLowSpeedLimit(), mResponder->getHTTPTimeoutPolicy().getLowSpeedTime(),
|
mResponder->getURL().c_str(), mResponder->getHTTPTimeoutPolicy().getLowSpeedLimit(), mResponder->getHTTPTimeoutPolicy().getLowSpeedTime(),
|
||||||
mResponder->getName(), mResponseTransferedBytes);
|
mResponder->getName(), mTotalRawBytes);
|
||||||
}
|
}
|
||||||
setopt(CURLOPT_FRESH_CONNECT, TRUE);
|
setopt(CURLOPT_FRESH_CONNECT, TRUE);
|
||||||
}
|
}
|
||||||
@@ -2058,7 +2098,9 @@ size_t BufferedCurlEasyRequest::curlWriteCallback(char* data, size_t size, size_
|
|||||||
// BufferedCurlEasyRequest::setBodyLimit is never called, so buffer_w->mBodyLimit is infinite.
|
// BufferedCurlEasyRequest::setBodyLimit is never called, so buffer_w->mBodyLimit is infinite.
|
||||||
//S32 bytes = llmin(size * nmemb, buffer_w->mBodyLimit); buffer_w->mBodyLimit -= bytes;
|
//S32 bytes = llmin(size * nmemb, buffer_w->mBodyLimit); buffer_w->mBodyLimit -= bytes;
|
||||||
self_w->getOutput()->append(sChannels.in(), (U8 const*)data, bytes);
|
self_w->getOutput()->append(sChannels.in(), (U8 const*)data, bytes);
|
||||||
self_w->mResponseTransferedBytes += bytes; // Accumulate data received from the server.
|
// Update HTTP bandwith.
|
||||||
|
self_w->update_body_bandwidth();
|
||||||
|
// Update timeout administration.
|
||||||
if (self_w->httptimeout()->data_received(bytes)) // Update timeout administration.
|
if (self_w->httptimeout()->data_received(bytes)) // Update timeout administration.
|
||||||
{
|
{
|
||||||
// Transfer timed out. Return 0 which will abort with error CURLE_WRITE_ERROR.
|
// Transfer timed out. Return 0 which will abort with error CURLE_WRITE_ERROR.
|
||||||
@@ -2067,6 +2109,25 @@ size_t BufferedCurlEasyRequest::curlWriteCallback(char* data, size_t size, size_
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BufferedCurlEasyRequest::update_body_bandwidth(void)
|
||||||
|
{
|
||||||
|
double size_download; // Total amount of raw bytes received so far (ie. still compressed, 'bytes' is uncompressed).
|
||||||
|
getinfo(CURLINFO_SIZE_DOWNLOAD, &size_download);
|
||||||
|
size_t total_raw_bytes = size_download;
|
||||||
|
size_t raw_bytes = total_raw_bytes - mTotalRawBytes;
|
||||||
|
mTotalRawBytes = total_raw_bytes;
|
||||||
|
// Note that in some cases (like HTTP_PARTIAL_CONTENT), the output of CURLINFO_SIZE_DOWNLOAD lags
|
||||||
|
// behind and will return 0 the first time, and the value of the previous chunk the next time.
|
||||||
|
// The last call from MultiHandle::finish_easy_request recorrects this, in that case.
|
||||||
|
if (raw_bytes > 0)
|
||||||
|
{
|
||||||
|
U64 const sTime_40ms = curlthread::HTTPTimeout::sTime_10ms >> 2;
|
||||||
|
AIAverage& http_bandwidth(PerService_wat(*getPerServicePtr())->bandwidth());
|
||||||
|
http_bandwidth.addData(raw_bytes, sTime_40ms);
|
||||||
|
sHTTPBandwidth.addData(raw_bytes, sTime_40ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//static
|
//static
|
||||||
size_t BufferedCurlEasyRequest::curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data)
|
size_t BufferedCurlEasyRequest::curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data)
|
||||||
{
|
{
|
||||||
@@ -2124,7 +2185,7 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size
|
|||||||
std::string::iterator pos3 = std::find(pos2, end, '\r');
|
std::string::iterator pos3 = std::find(pos2, end, '\r');
|
||||||
U32 status = 0;
|
U32 status = 0;
|
||||||
std::string reason;
|
std::string reason;
|
||||||
if (pos3 != end && std::isdigit(*pos1))
|
if (pos3 != end && LLStringOps::isDigit(*pos1))
|
||||||
{
|
{
|
||||||
status = atoi(&header_line[pos1 - begin]);
|
status = atoi(&header_line[pos1 - begin]);
|
||||||
reason.assign(pos2, pos3);
|
reason.assign(pos2, pos3);
|
||||||
@@ -2154,6 +2215,11 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size
|
|||||||
self_w->httptimeout()->being_redirected();
|
self_w->httptimeout()->being_redirected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Update HTTP bandwidth.
|
||||||
|
U64 const sTime_40ms = curlthread::HTTPTimeout::sTime_10ms >> 2;
|
||||||
|
AIAverage& http_bandwidth(PerService_wat(*self_w->getPerServicePtr())->bandwidth());
|
||||||
|
http_bandwidth.addData(header_len, sTime_40ms);
|
||||||
|
sHTTPBandwidth.addData(header_len, sTime_40ms);
|
||||||
// Update timeout administration. This must be done after the status is already known.
|
// Update timeout administration. This must be done after the status is already known.
|
||||||
if (self_w->httptimeout()->data_received(header_len/*,*/ ASSERT_ONLY_COMMA(self_w->upload_error_status())))
|
if (self_w->httptimeout()->data_received(header_len/*,*/ ASSERT_ONLY_COMMA(self_w->upload_error_status())))
|
||||||
{
|
{
|
||||||
@@ -2328,7 +2394,7 @@ void AICurlEasyRequest::addRequest(void)
|
|||||||
|
|
||||||
// Find the last command added.
|
// Find the last command added.
|
||||||
command_st cmd = cmd_none;
|
command_st cmd = cmd_none;
|
||||||
for (std::deque<Command>::iterator iter = command_queue_w->begin(); iter != command_queue_w->end(); ++iter)
|
for (std::deque<Command>::iterator iter = command_queue_w->commands.begin(); iter != command_queue_w->commands.end(); ++iter)
|
||||||
{
|
{
|
||||||
if (*iter == *this)
|
if (*iter == *this)
|
||||||
{
|
{
|
||||||
@@ -2354,8 +2420,11 @@ void AICurlEasyRequest::addRequest(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// Add a command to add the new request to the multi session to the command queue.
|
// Add a command to add the new request to the multi session to the command queue.
|
||||||
command_queue_w->push_back(Command(*this, cmd_add));
|
command_queue_w->commands.push_back(Command(*this, cmd_add));
|
||||||
AICurlEasyRequest_wat(*get())->add_queued();
|
command_queue_w->size++;
|
||||||
|
AICurlEasyRequest_wat curl_easy_request_w(*get());
|
||||||
|
PerService_wat(*curl_easy_request_w->getPerServicePtr())->added_to_command_queue();
|
||||||
|
curl_easy_request_w->add_queued();
|
||||||
}
|
}
|
||||||
// Something was added to the queue, wake up the thread to get it.
|
// Something was added to the queue, wake up the thread to get it.
|
||||||
wakeUpCurlThread();
|
wakeUpCurlThread();
|
||||||
@@ -2378,7 +2447,7 @@ void AICurlEasyRequest::removeRequest(void)
|
|||||||
|
|
||||||
// Find the last command added.
|
// Find the last command added.
|
||||||
command_st cmd = cmd_none;
|
command_st cmd = cmd_none;
|
||||||
for (std::deque<Command>::iterator iter = command_queue_w->begin(); iter != command_queue_w->end(); ++iter)
|
for (std::deque<Command>::iterator iter = command_queue_w->commands.begin(); iter != command_queue_w->commands.end(); ++iter)
|
||||||
{
|
{
|
||||||
if (*iter == *this)
|
if (*iter == *this)
|
||||||
{
|
{
|
||||||
@@ -2415,9 +2484,12 @@ void AICurlEasyRequest::removeRequest(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// Add a command to remove this request from the multi session to the command queue.
|
// Add a command to remove this request from the multi session to the command queue.
|
||||||
command_queue_w->push_back(Command(*this, cmd_remove));
|
command_queue_w->commands.push_back(Command(*this, cmd_remove));
|
||||||
|
command_queue_w->size--;
|
||||||
|
AICurlEasyRequest_wat curl_easy_request_w(*get());
|
||||||
|
PerService_wat(*curl_easy_request_w->getPerServicePtr())->removed_from_command_queue(); // Note really, but this has the same effect as 'added a remove command'.
|
||||||
// Suppress warning that would otherwise happen if the callbacks are revoked before the curl thread removed the request.
|
// Suppress warning that would otherwise happen if the callbacks are revoked before the curl thread removed the request.
|
||||||
AICurlEasyRequest_wat(*get())->remove_queued();
|
curl_easy_request_w->remove_queued();
|
||||||
}
|
}
|
||||||
// Something was added to the queue, wake up the thread to get it.
|
// Something was added to the queue, wake up the thread to get it.
|
||||||
wakeUpCurlThread();
|
wakeUpCurlThread();
|
||||||
@@ -2427,7 +2499,9 @@ void AICurlEasyRequest::removeRequest(void)
|
|||||||
|
|
||||||
namespace AICurlInterface {
|
namespace AICurlInterface {
|
||||||
|
|
||||||
void startCurlThread(U32 CurlMaxTotalConcurrentConnections, U32 CurlConcurrentConnectionsPerHost, bool NoVerifySSLCert)
|
LLControlGroup* sConfigGroup;
|
||||||
|
|
||||||
|
void startCurlThread(LLControlGroup* control_group)
|
||||||
{
|
{
|
||||||
using namespace AICurlPrivate;
|
using namespace AICurlPrivate;
|
||||||
using namespace AICurlPrivate::curlthread;
|
using namespace AICurlPrivate::curlthread;
|
||||||
@@ -2435,9 +2509,12 @@ void startCurlThread(U32 CurlMaxTotalConcurrentConnections, U32 CurlConcurrentCo
|
|||||||
llassert(is_main_thread());
|
llassert(is_main_thread());
|
||||||
|
|
||||||
// Cache Debug Settings.
|
// Cache Debug Settings.
|
||||||
curl_max_total_concurrent_connections = CurlMaxTotalConcurrentConnections;
|
sConfigGroup = control_group;
|
||||||
curl_concurrent_connections_per_host = CurlConcurrentConnectionsPerHost;
|
curl_max_total_concurrent_connections = sConfigGroup->getU32("CurlMaxTotalConcurrentConnections");
|
||||||
gNoVerifySSLCert = NoVerifySSLCert;
|
CurlConcurrentConnectionsPerService = sConfigGroup->getU32("CurlConcurrentConnectionsPerService");
|
||||||
|
gNoVerifySSLCert = sConfigGroup->getBOOL("NoVerifySSLCert");
|
||||||
|
AIPerService::setMaxPipelinedRequests(curl_max_total_concurrent_connections);
|
||||||
|
AIPerService::setHTTPThrottleBandwidth(sConfigGroup->getF32("HTTPThrottleBandwidth"));
|
||||||
|
|
||||||
AICurlThread::sInstance = new AICurlThread;
|
AICurlThread::sInstance = new AICurlThread;
|
||||||
AICurlThread::sInstance->start();
|
AICurlThread::sInstance->start();
|
||||||
@@ -2445,19 +2522,24 @@ void startCurlThread(U32 CurlMaxTotalConcurrentConnections, U32 CurlConcurrentCo
|
|||||||
|
|
||||||
bool handleCurlMaxTotalConcurrentConnections(LLSD const& newvalue)
|
bool handleCurlMaxTotalConcurrentConnections(LLSD const& newvalue)
|
||||||
{
|
{
|
||||||
|
using namespace AICurlPrivate;
|
||||||
using namespace AICurlPrivate::curlthread;
|
using namespace AICurlPrivate::curlthread;
|
||||||
|
|
||||||
|
U32 old = curl_max_total_concurrent_connections;
|
||||||
curl_max_total_concurrent_connections = newvalue.asInteger();
|
curl_max_total_concurrent_connections = newvalue.asInteger();
|
||||||
|
AIPerService::incrementMaxPipelinedRequests(curl_max_total_concurrent_connections - old);
|
||||||
llinfos << "CurlMaxTotalConcurrentConnections set to " << curl_max_total_concurrent_connections << llendl;
|
llinfos << "CurlMaxTotalConcurrentConnections set to " << curl_max_total_concurrent_connections << llendl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handleCurlConcurrentConnectionsPerHost(LLSD const& newvalue)
|
bool handleCurlConcurrentConnectionsPerService(LLSD const& newvalue)
|
||||||
{
|
{
|
||||||
using namespace AICurlPrivate;
|
using namespace AICurlPrivate;
|
||||||
|
|
||||||
curl_concurrent_connections_per_host = newvalue.asInteger();
|
U32 new_concurrent_connections = newvalue.asInteger();
|
||||||
llinfos << "CurlConcurrentConnectionsPerHost set to " << curl_concurrent_connections_per_host << llendl;
|
AIPerService::adjust_concurrent_connections(new_concurrent_connections - CurlConcurrentConnectionsPerService);
|
||||||
|
CurlConcurrentConnectionsPerService = new_concurrent_connections;
|
||||||
|
llinfos << "CurlConcurrentConnectionsPerService set to " << CurlConcurrentConnectionsPerService << llendl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2467,5 +2549,245 @@ bool handleNoVerifySSLCert(LLSD const& newvalue)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U32 getNumHTTPCommands(void)
|
||||||
|
{
|
||||||
|
using namespace AICurlPrivate;
|
||||||
|
|
||||||
|
command_queue_rat command_queue_r(command_queue);
|
||||||
|
return command_queue_r->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 getNumHTTPQueued(void)
|
||||||
|
{
|
||||||
|
return AIPerService::total_queued_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 getNumHTTPAdded(void)
|
||||||
|
{
|
||||||
|
return AICurlPrivate::curlthread::MultiHandle::total_added_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getHTTPBandwidth(void)
|
||||||
|
{
|
||||||
|
using namespace AICurlPrivate;
|
||||||
|
|
||||||
|
U64 const sTime_40ms = get_clock_count() * curlthread::HTTPTimeout::sClockWidth_40ms;
|
||||||
|
return BufferedCurlEasyRequest::sHTTPBandwidth.truncateData(sTime_40ms);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace AICurlInterface
|
} // namespace AICurlInterface
|
||||||
|
|
||||||
|
// Global AIPerService members.
|
||||||
|
AIThreadSafeSimpleDC<AIPerService::MaxPipelinedRequests> AIPerService::sMaxPipelinedRequests;
|
||||||
|
AIThreadSafeSimpleDC<AIPerService::ThrottleFraction> AIPerService::sThrottleFraction;
|
||||||
|
LLAtomicU32 AIPerService::sHTTPThrottleBandwidth125(250000);
|
||||||
|
bool AIPerService::sNoHTTPBandwidthThrottling;
|
||||||
|
|
||||||
|
// Return true if we want at least one more HTTP request for this host.
|
||||||
|
//
|
||||||
|
// It's OK if this function is a bit fuzzy, but we don't want it to return
|
||||||
|
// true a hundred times on a row when it is called fast in a loop.
|
||||||
|
// Hence the following consideration:
|
||||||
|
//
|
||||||
|
// This function is called only from LLTextureFetchWorker::doWork, and when it returns true
|
||||||
|
// then doWork will call LLHTTPClient::request with a NULL default engine (signaling that
|
||||||
|
// it is OK to run in any thread).
|
||||||
|
//
|
||||||
|
// At the end, LLHTTPClient::request calls AIStateMachine::run, which in turn calls
|
||||||
|
// AIStateMachine::reset at the end. Because NULL is passed as default_engine, reset will
|
||||||
|
// call AIStateMachine::multiplex to immediately start running the state machine. This
|
||||||
|
// causes it to go through the states bs_reset, bs_initialize and then bs_multiplex with
|
||||||
|
// run state AICurlEasyRequestStateMachine_addRequest. Finally, in this state, multiplex
|
||||||
|
// calls AICurlEasyRequestStateMachine::multiplex_impl which then calls AICurlEasyRequest::addRequest
|
||||||
|
// which causes an increment of command_queue_w->size and AIPerService::mQueuedCommands.
|
||||||
|
//
|
||||||
|
// It is therefore guaranteed that in one loop of LLTextureFetchWorker::doWork,
|
||||||
|
// this size is incremented; stopping this function from returning true once we reached the
|
||||||
|
// threshold of "pipelines" requests (the sum of requests in the command queue, the ones
|
||||||
|
// throttled and queued in AIPerService::mQueuedRequests and the already
|
||||||
|
// running requests (in MultiHandle::mAddedEasyRequests)).
|
||||||
|
//
|
||||||
|
//static
|
||||||
|
bool AIPerService::wantsMoreHTTPRequestsFor(AIPerServicePtr const& per_service)
|
||||||
|
{
|
||||||
|
using namespace AICurlPrivate;
|
||||||
|
using namespace AICurlPrivate::curlthread;
|
||||||
|
|
||||||
|
// Do certain things at most once every 40ms.
|
||||||
|
U64 const sTime_40ms = get_clock_count() * HTTPTimeout::sClockWidth_40ms; // Time in 40ms units.
|
||||||
|
|
||||||
|
// Cache all sTotalQueued info.
|
||||||
|
bool starvation, decrement_threshold;
|
||||||
|
S32 total_queued_or_added = MultiHandle::total_added_size();
|
||||||
|
{
|
||||||
|
TotalQueued_wat total_queued_w(sTotalQueued);
|
||||||
|
total_queued_or_added += total_queued_w->count;
|
||||||
|
starvation = total_queued_w->starvation;
|
||||||
|
decrement_threshold = total_queued_w->full && !total_queued_w->empty;
|
||||||
|
total_queued_w->empty = total_queued_w->full = false; // Reset flags.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whether or not we're going to approve a new request, decrement the global threshold first, when appropriate.
|
||||||
|
|
||||||
|
if (decrement_threshold)
|
||||||
|
{
|
||||||
|
MaxPipelinedRequests_wat max_pipelined_requests_w(sMaxPipelinedRequests);
|
||||||
|
if (max_pipelined_requests_w->count > (S32)curl_max_total_concurrent_connections &&
|
||||||
|
sTime_40ms > max_pipelined_requests_w->last_decrement)
|
||||||
|
{
|
||||||
|
// Decrement the threshold because since the last call to this function at least one curl request finished
|
||||||
|
// and was replaced with another request from the queue, but the queue never ran empty: we have too many
|
||||||
|
// queued requests.
|
||||||
|
max_pipelined_requests_w->count--;
|
||||||
|
// Do this at most once every 40 ms.
|
||||||
|
max_pipelined_requests_w->last_decrement = sTime_40ms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's ok to get a new request for this particular service and update the per-service threshold.
|
||||||
|
|
||||||
|
bool reject, equal, increment_threshold;
|
||||||
|
{
|
||||||
|
PerService_wat per_service_w(*per_service);
|
||||||
|
S32 const pipelined_requests_per_service = per_service_w->pipelined_requests();
|
||||||
|
//llassert(pipelined_requests_per_service >= 0 && pipelined_requests_per_service <= 16);
|
||||||
|
reject = pipelined_requests_per_service >= per_service_w->mMaxPipelinedRequests;
|
||||||
|
equal = pipelined_requests_per_service == per_service_w->mMaxPipelinedRequests;
|
||||||
|
increment_threshold = per_service_w->mRequestStarvation;
|
||||||
|
decrement_threshold = per_service_w->mQueueFull && !per_service_w->mQueueEmpty;
|
||||||
|
// Reset flags.
|
||||||
|
per_service_w->mQueueFull = per_service_w->mQueueEmpty = per_service_w->mRequestStarvation = false;
|
||||||
|
if (decrement_threshold)
|
||||||
|
{
|
||||||
|
if (per_service_w->mMaxPipelinedRequests > per_service_w->mConcurrectConnections)
|
||||||
|
{
|
||||||
|
per_service_w->mMaxPipelinedRequests--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (increment_threshold && reject)
|
||||||
|
{
|
||||||
|
if (per_service_w->mMaxPipelinedRequests < 2 * per_service_w->mConcurrectConnections)
|
||||||
|
{
|
||||||
|
per_service_w->mMaxPipelinedRequests++;
|
||||||
|
// Immediately take the new threshold into account.
|
||||||
|
reject = !equal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!reject)
|
||||||
|
{
|
||||||
|
// Before releasing the lock on per_service, stop other threads from getting a
|
||||||
|
// too small value from pipelined_requests() and approving too many requests.
|
||||||
|
per_service_w->mApprovedRequests++;
|
||||||
|
//llassert(per_service_w->mApprovedRequests <= 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (reject)
|
||||||
|
{
|
||||||
|
// Too many request for this service already.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throttle on bandwidth usage.
|
||||||
|
if (checkBandwidthUsage(per_service, sTime_40ms))
|
||||||
|
{
|
||||||
|
// Too much bandwidth is being used, either in total or for this service.
|
||||||
|
PerService_wat(*per_service)->mApprovedRequests--; // Not approved after all.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's ok to get a new request based on the total number of requests and increment the threshold if appropriate.
|
||||||
|
|
||||||
|
S32 const pipelined_requests = command_queue_rat(command_queue)->size + total_queued_or_added;
|
||||||
|
// We can't take the command being processed (command_being_processed) into account without
|
||||||
|
// introducing relatively long waiting times for some mutex (namely between when the command
|
||||||
|
// is moved from command_queue to command_being_processed, till it's actually being added to
|
||||||
|
// mAddedEasyRequests). The whole purpose of command_being_processed is to reduce the time
|
||||||
|
// that things are locked to micro seconds, so we'll just accept an off-by-one fuzziness
|
||||||
|
// here instead.
|
||||||
|
|
||||||
|
// The maximum number of requests that may be queued in command_queue is equal to the total number of requests
|
||||||
|
// that may exist in the pipeline minus the number of requests queued in AIPerService objects, minus
|
||||||
|
// the number of already running requests.
|
||||||
|
MaxPipelinedRequests_wat max_pipelined_requests_w(sMaxPipelinedRequests);
|
||||||
|
reject = pipelined_requests >= max_pipelined_requests_w->count;
|
||||||
|
equal = pipelined_requests == max_pipelined_requests_w->count;
|
||||||
|
increment_threshold = starvation;
|
||||||
|
if (increment_threshold && reject)
|
||||||
|
{
|
||||||
|
if (max_pipelined_requests_w->count < 2 * (S32)curl_max_total_concurrent_connections &&
|
||||||
|
sTime_40ms > max_pipelined_requests_w->last_increment)
|
||||||
|
{
|
||||||
|
max_pipelined_requests_w->count++;
|
||||||
|
max_pipelined_requests_w->last_increment = sTime_40ms;
|
||||||
|
// Immediately take the new threshold into account.
|
||||||
|
reject = !equal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (reject)
|
||||||
|
{
|
||||||
|
PerService_wat(*per_service)->mApprovedRequests--; // Not approved after all.
|
||||||
|
}
|
||||||
|
return !reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AIPerService::checkBandwidthUsage(AIPerServicePtr const& per_service, U64 sTime_40ms)
|
||||||
|
{
|
||||||
|
if (sNoHTTPBandwidthThrottling)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
using namespace AICurlPrivate;
|
||||||
|
|
||||||
|
// Truncate the sums to the last second, and get their value.
|
||||||
|
size_t const max_bandwidth = AIPerService::getHTTPThrottleBandwidth125();
|
||||||
|
size_t const total_bandwidth = BufferedCurlEasyRequest::sHTTPBandwidth.truncateData(sTime_40ms); // Bytes received in the past second.
|
||||||
|
size_t const service_bandwidth = PerService_wat(*per_service)->bandwidth().truncateData(sTime_40ms); // Idem for just this service.
|
||||||
|
ThrottleFraction_wat throttle_fraction_w(sThrottleFraction);
|
||||||
|
if (sTime_40ms > throttle_fraction_w->last_add)
|
||||||
|
{
|
||||||
|
throttle_fraction_w->average.addData(throttle_fraction_w->fraction, sTime_40ms);
|
||||||
|
// Only add throttle_fraction_w->fraction once every 40 ms at most.
|
||||||
|
// It's ok to ignore other values in the same 40 ms because the value only changes on the scale of 1 second.
|
||||||
|
throttle_fraction_w->last_add = sTime_40ms;
|
||||||
|
}
|
||||||
|
double fraction_avg = throttle_fraction_w->average.getAverage(1024.0); // throttle_fraction_w->fraction averaged over the past second, or 1024 if there is no data.
|
||||||
|
|
||||||
|
// Adjust the fraction based on total bandwidth usage.
|
||||||
|
if (total_bandwidth == 0)
|
||||||
|
throttle_fraction_w->fraction = 1024;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This is the main formula. It can be made plausible by assuming
|
||||||
|
// an equilibrium where total_bandwidth == max_bandwidth and
|
||||||
|
// thus fraction == fraction_avg for more than a second.
|
||||||
|
//
|
||||||
|
// Then, more bandwidth is being used (for example because another
|
||||||
|
// service starts downloading). Assuming that all services that use
|
||||||
|
// a significant portion of the bandwidth, the new service included,
|
||||||
|
// must be throttled (all using the same bandwidth; note that the
|
||||||
|
// new service is immediately throttled at the same value), then
|
||||||
|
// the limit should be reduced linear with the fraction:
|
||||||
|
// max_bandwidth / total_bandwidth.
|
||||||
|
//
|
||||||
|
// For example, let max_bandwidth be 1. Let there be two throttled
|
||||||
|
// services, each using 0.5 (fraction_avg = 1024/2). Let the new
|
||||||
|
// service use what it can: also 0.5 - then without reduction the
|
||||||
|
// total_bandwidth would become 1.5, and fraction would
|
||||||
|
// become (1024/2) * 1/1.5 = 1024/3: from 2 to 3 services.
|
||||||
|
//
|
||||||
|
// In reality, total_bandwidth would rise linear from 1.0 to 1.5 in
|
||||||
|
// one second if the throttle fraction wasn't changed. However it is
|
||||||
|
// changed here. The end result is that any change more or less
|
||||||
|
// linear fades away in one second.
|
||||||
|
throttle_fraction_w->fraction = llmin(1024., fraction_avg * max_bandwidth / total_bandwidth + 0.5);
|
||||||
|
}
|
||||||
|
if (total_bandwidth > max_bandwidth)
|
||||||
|
{
|
||||||
|
throttle_fraction_w->fraction *= 0.95;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throttle this service if it uses too much bandwidth.
|
||||||
|
// Warning: this requires max_bandwidth * 1024 to fit in a size_t.
|
||||||
|
// On 32 bit that means that HTTPThrottleBandwidth must be less than 33554 kbps.
|
||||||
|
return (service_bandwidth > (max_bandwidth * throttle_fraction_w->fraction / 1024));
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,12 +75,13 @@ class MultiHandle : public CurlMultiHandle
|
|||||||
typedef std::set<AICurlEasyRequest, AICurlEasyRequestCompare> addedEasyRequests_type;
|
typedef std::set<AICurlEasyRequest, AICurlEasyRequestCompare> addedEasyRequests_type;
|
||||||
addedEasyRequests_type mAddedEasyRequests; // All easy requests currently added to the multi handle.
|
addedEasyRequests_type mAddedEasyRequests; // All easy requests currently added to the multi handle.
|
||||||
long mTimeout; // The last timeout in ms as set by the callback CURLMOPT_TIMERFUNCTION.
|
long mTimeout; // The last timeout in ms as set by the callback CURLMOPT_TIMERFUNCTION.
|
||||||
|
static LLAtomicU32 sTotalAdded; // The (sum of the) size of mAddedEasyRequests (of every MultiHandle, but there is only one).
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Store result and trigger events for easy request.
|
// Store result and trigger events for easy request.
|
||||||
void finish_easy_request(AICurlEasyRequest const& easy_request, CURLcode result);
|
void finish_easy_request(AICurlEasyRequest const& easy_request, CURLcode result);
|
||||||
// Remove easy request at iter (must exist).
|
// Remove easy request at iter (must exist).
|
||||||
// Note that it's possible that a new request from a PerHostRequestQueue::mQueuedRequests is inserted before iter.
|
// Note that it's possible that a new request from a AIPerService::mQueuedRequests is inserted before iter.
|
||||||
CURLMcode remove_easy_request(addedEasyRequests_type::iterator const& iter, bool as_per_command);
|
CURLMcode remove_easy_request(addedEasyRequests_type::iterator const& iter, bool as_per_command);
|
||||||
|
|
||||||
static int socket_callback(CURL* easy, curl_socket_t s, int action, void* userp, void* socketp);
|
static int socket_callback(CURL* easy, curl_socket_t s, int action, void* userp, void* socketp);
|
||||||
@@ -96,6 +97,9 @@ class MultiHandle : public CurlMultiHandle
|
|||||||
// Called from the main loop every time select() timed out.
|
// Called from the main loop every time select() timed out.
|
||||||
void handle_stalls(void);
|
void handle_stalls(void);
|
||||||
|
|
||||||
|
// Return the total number of added curl requests.
|
||||||
|
static U32 total_added_size(void) { return sTotalAdded; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Curl socket administration:
|
// Curl socket administration:
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ namespace AICurlPrivate {
|
|||||||
class BufferedCurlEasyRequest {
|
class BufferedCurlEasyRequest {
|
||||||
public:
|
public:
|
||||||
char const* getLowercaseHostname(void) const { return "hostname.com"; }
|
char const* getLowercaseHostname(void) const { return "hostname.com"; }
|
||||||
|
char const* getLowercaseServicename(void) const { return "hostname.com:12047"; }
|
||||||
void getinfo(const int&, double* p) { *p = 0.1; }
|
void getinfo(const int&, double* p) { *p = 0.1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -96,8 +97,9 @@ namespace curlthread {
|
|||||||
// HTTPTimeout
|
// HTTPTimeout
|
||||||
|
|
||||||
//static
|
//static
|
||||||
F64 const HTTPTimeout::sClockWidth = 1.0 / calc_clock_frequency(); // Time between two clock ticks, in seconds.
|
F64 const HTTPTimeout::sClockWidth_10ms = 100.0 / calc_clock_frequency(); // Time between two clock ticks, in 10ms units.
|
||||||
U64 HTTPTimeout::sClockCount; // Clock count, set once per select() exit.
|
F64 const HTTPTimeout::sClockWidth_40ms = HTTPTimeout::sClockWidth_10ms * 0.25; // Time between two clock ticks, in 40ms units.
|
||||||
|
U64 HTTPTimeout::sTime_10ms; // Time in 10ms units, set once per select() exit.
|
||||||
|
|
||||||
// CURL-THREAD
|
// CURL-THREAD
|
||||||
// This is called when body data was sent to the server socket.
|
// This is called when body data was sent to the server socket.
|
||||||
@@ -125,7 +127,7 @@ bool HTTPTimeout::data_sent(size_t n, bool finished)
|
|||||||
// | |
|
// | |
|
||||||
void HTTPTimeout::reset_lowspeed(void)
|
void HTTPTimeout::reset_lowspeed(void)
|
||||||
{
|
{
|
||||||
mLowSpeedClock = sClockCount;
|
mLowSpeedClock = sTime_10ms;
|
||||||
mLowSpeedOn = true;
|
mLowSpeedOn = true;
|
||||||
mLastBytesSent = false; // We're just starting!
|
mLastBytesSent = false; // We're just starting!
|
||||||
mLastSecond = -1; // This causes lowspeed to initialize the rest.
|
mLastSecond = -1; // This causes lowspeed to initialize the rest.
|
||||||
@@ -162,8 +164,8 @@ void HTTPTimeout::upload_finished(void)
|
|||||||
// We finished uploading (if there was a body to upload at all), so no more transfer rate timeouts.
|
// We finished uploading (if there was a body to upload at all), so no more transfer rate timeouts.
|
||||||
mLowSpeedOn = false;
|
mLowSpeedOn = false;
|
||||||
// Timeout if the server doesn't reply quick enough.
|
// Timeout if the server doesn't reply quick enough.
|
||||||
mStalled = sClockCount + mPolicy->getReplyDelay() / sClockWidth;
|
mStalled = sTime_10ms + 100 * mPolicy->getReplyDelay();
|
||||||
DoutCurl("upload_finished: mStalled set to sClockCount (" << sClockCount << ") + " << (mStalled - sClockCount) << " (" << mPolicy->getReplyDelay() << " seconds)");
|
DoutCurl("upload_finished: mStalled set to Time_10ms (" << sTime_10ms << ") + " << (mStalled - sTime_10ms) << " (" << mPolicy->getReplyDelay() << " seconds)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// CURL-THREAD
|
// CURL-THREAD
|
||||||
@@ -230,8 +232,7 @@ bool HTTPTimeout::lowspeed(size_t bytes, bool finished)
|
|||||||
// less than low_speed_limit, we abort.
|
// less than low_speed_limit, we abort.
|
||||||
|
|
||||||
// When are we?
|
// When are we?
|
||||||
S32 second = (sClockCount - mLowSpeedClock) * sClockWidth;
|
S32 second = (sTime_10ms - mLowSpeedClock) / 100;
|
||||||
llassert(sClockWidth > 0.0);
|
|
||||||
// This REALLY should never happen, but due to another bug it did happened
|
// This REALLY should never happen, but due to another bug it did happened
|
||||||
// and caused something so evil and hard to find that... NEVER AGAIN!
|
// and caused something so evil and hard to find that... NEVER AGAIN!
|
||||||
llassert(second >= 0);
|
llassert(second >= 0);
|
||||||
@@ -315,8 +316,8 @@ bool HTTPTimeout::lowspeed(size_t bytes, bool finished)
|
|||||||
// Just give these bytes 4 more seconds to be written to the socket (after which we'll
|
// Just give these bytes 4 more seconds to be written to the socket (after which we'll
|
||||||
// assume that the 'upload finished' detection failed and we'll wait another ReplyDelay
|
// assume that the 'upload finished' detection failed and we'll wait another ReplyDelay
|
||||||
// seconds before finally, actually timing out.
|
// seconds before finally, actually timing out.
|
||||||
mStalled = sClockCount + 4 / sClockWidth;
|
mStalled = sTime_10ms + 400; // 4 seconds into the future.
|
||||||
DoutCurl("mStalled set to sClockCount (" << sClockCount << ") + " << (mStalled - sClockCount) << " (4 seconds)");
|
DoutCurl("mStalled set to sTime_10ms (" << sTime_10ms << ") + 400 (4 seconds)");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// The average transfer rate over the passed low_speed_time seconds is too low. Abort the transfer.
|
// The average transfer rate over the passed low_speed_time seconds is too low. Abort the transfer.
|
||||||
@@ -368,8 +369,8 @@ bool HTTPTimeout::lowspeed(size_t bytes, bool finished)
|
|||||||
while(total_bytes >= mintotalbytes);
|
while(total_bytes >= mintotalbytes);
|
||||||
}
|
}
|
||||||
// If this function isn't called again within max_stall_time seconds, we stalled.
|
// If this function isn't called again within max_stall_time seconds, we stalled.
|
||||||
mStalled = sClockCount + max_stall_time / sClockWidth;
|
mStalled = sTime_10ms + 100 * max_stall_time;
|
||||||
DoutCurl("mStalled set to sClockCount (" << sClockCount << ") + " << (mStalled - sClockCount) << " (" << max_stall_time << " seconds)");
|
DoutCurl("mStalled set to sTime_10ms (" << sTime_10ms << ") + " << (mStalled - sTime_10ms) << " (" << max_stall_time << " seconds)");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -435,7 +436,7 @@ bool HTTPTimeout::maybe_upload_finished(void)
|
|||||||
void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, char const* eff_url)
|
void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, char const* eff_url)
|
||||||
{
|
{
|
||||||
#ifndef HTTPTIMEOUT_TESTSUITE
|
#ifndef HTTPTIMEOUT_TESTSUITE
|
||||||
llwarns << "Request to \"" << curl_easy_request->getLowercaseHostname() << "\" timed out for " << curl_easy_request->getTimeoutPolicy()->name() << llendl;
|
llwarns << "Request to \"" << curl_easy_request->getLowercaseServicename() << "\" timed out for " << curl_easy_request->getTimeoutPolicy()->name() << llendl;
|
||||||
llinfos << "Effective URL: \"" << eff_url << "\"." << llendl;
|
llinfos << "Effective URL: \"" << eff_url << "\"." << llendl;
|
||||||
double namelookup_time, connect_time, appconnect_time, pretransfer_time, starttransfer_time;
|
double namelookup_time, connect_time, appconnect_time, pretransfer_time, starttransfer_time;
|
||||||
curl_easy_request->getinfo(CURLINFO_NAMELOOKUP_TIME, &namelookup_time);
|
curl_easy_request->getinfo(CURLINFO_NAMELOOKUP_TIME, &namelookup_time);
|
||||||
|
|||||||
@@ -85,11 +85,12 @@ class HTTPTimeout : public LLRefCount {
|
|||||||
S32 mLastSecond; // The time at which lowspeed() was last called, in seconds since mLowSpeedClock.
|
S32 mLastSecond; // The time at which lowspeed() was last called, in seconds since mLowSpeedClock.
|
||||||
S32 mOverwriteSecond; // The second at which the first bucket of this transfer will be overwritten.
|
S32 mOverwriteSecond; // The second at which the first bucket of this transfer will be overwritten.
|
||||||
U32 mTotalBytes; // The sum of all bytes in mBuckets.
|
U32 mTotalBytes; // The sum of all bytes in mBuckets.
|
||||||
U64 mLowSpeedClock; // Clock count at which low speed detection (re)started.
|
U64 mLowSpeedClock; // The time (sTime_10ms) at which low speed detection (re)started.
|
||||||
U64 mStalled; // The clock count at which this transaction is considered to be stalling if nothing is transfered anymore.
|
U64 mStalled; // The time (sTime_10ms) at which this transaction is considered to be stalling if nothing is transfered anymore.
|
||||||
public:
|
public:
|
||||||
static F64 const sClockWidth; // Time between two clock ticks in seconds.
|
static F64 const sClockWidth_10ms; // Time between two clock ticks in 10 ms units.
|
||||||
static U64 sClockCount; // Clock count used as 'now' during one loop of the main loop.
|
static F64 const sClockWidth_40ms; // Time between two clock ticks in 40 ms units.
|
||||||
|
static U64 sTime_10ms; // Time since the epoch in 10 ms units.
|
||||||
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
|
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
|
||||||
ThreadSafeBufferedCurlEasyRequest* mLockObj;
|
ThreadSafeBufferedCurlEasyRequest* mLockObj;
|
||||||
#endif
|
#endif
|
||||||
@@ -121,7 +122,7 @@ class HTTPTimeout : public LLRefCount {
|
|||||||
void done(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode code);
|
void done(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode code);
|
||||||
|
|
||||||
// Returns true when we REALLY timed out. Might call upload_finished heuristically.
|
// Returns true when we REALLY timed out. Might call upload_finished heuristically.
|
||||||
bool has_stalled(void) { return mStalled < sClockCount && !maybe_upload_finished(); }
|
bool has_stalled(void) { return mStalled < sTime_10ms && !maybe_upload_finished(); }
|
||||||
|
|
||||||
// Called from BufferedCurlEasyRequest::processOutput if a timeout occurred.
|
// Called from BufferedCurlEasyRequest::processOutput if a timeout occurred.
|
||||||
void print_diagnostics(CurlEasyRequest const* curl_easy_request, char const* eff_url);
|
void print_diagnostics(CurlEasyRequest const* curl_easy_request, char const* eff_url);
|
||||||
|
|||||||
@@ -208,7 +208,8 @@ void LLHTTPClient::request(
|
|||||||
EAllowCompressedReply allow_compression,
|
EAllowCompressedReply allow_compression,
|
||||||
AIStateMachine* parent,
|
AIStateMachine* parent,
|
||||||
AIStateMachine::state_type new_parent_state,
|
AIStateMachine::state_type new_parent_state,
|
||||||
AIEngine* default_engine)
|
AIEngine* default_engine,
|
||||||
|
bool queue_if_too_much_bandwidth_usage)
|
||||||
{
|
{
|
||||||
llassert(responder);
|
llassert(responder);
|
||||||
|
|
||||||
@@ -221,7 +222,7 @@ void LLHTTPClient::request(
|
|||||||
LLURLRequest* req;
|
LLURLRequest* req;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
req = new LLURLRequest(method, url, body_injector, responder, headers, keepalive, does_auth, allow_compression);
|
req = new LLURLRequest(method, url, body_injector, responder, headers, keepalive, does_auth, allow_compression, queue_if_too_much_bandwidth_usage);
|
||||||
#ifdef DEBUG_CURLIO
|
#ifdef DEBUG_CURLIO
|
||||||
req->mCurlEasyRequest.debug(debug);
|
req->mCurlEasyRequest.debug(debug);
|
||||||
#endif
|
#endif
|
||||||
@@ -701,6 +702,11 @@ void LLHTTPClient::post(std::string const& url, LLSD const& body, ResponderPtr r
|
|||||||
request(url, HTTP_POST, new LLSDInjector(body), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, no_does_authentication, allow_compressed_reply, parent, new_parent_state);
|
request(url, HTTP_POST, new LLSDInjector(body), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, no_does_authentication, allow_compressed_reply, parent, new_parent_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LLHTTPClient::post_nb(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive, AIStateMachine* parent, AIStateMachine::state_type new_parent_state)
|
||||||
|
{
|
||||||
|
request(url, HTTP_POST, new LLSDInjector(body), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, no_does_authentication, allow_compressed_reply, parent, new_parent_state, &gMainThreadEngine, false);
|
||||||
|
}
|
||||||
|
|
||||||
void LLHTTPClient::postXMLRPC(std::string const& url, XMLRPC_REQUEST xmlrpc_request, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
|
void LLHTTPClient::postXMLRPC(std::string const& url, XMLRPC_REQUEST xmlrpc_request, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
|
||||||
{
|
{
|
||||||
request(url, HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, does_authentication, allow_compressed_reply);
|
request(url, HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, does_authentication, allow_compressed_reply);
|
||||||
|
|||||||
@@ -433,7 +433,8 @@ public:
|
|||||||
EAllowCompressedReply allow_compression = allow_compressed_reply,
|
EAllowCompressedReply allow_compression = allow_compressed_reply,
|
||||||
AIStateMachine* parent = NULL,
|
AIStateMachine* parent = NULL,
|
||||||
/*AIStateMachine::state_type*/ U32 new_parent_state = 0,
|
/*AIStateMachine::state_type*/ U32 new_parent_state = 0,
|
||||||
AIEngine* default_engine = &gMainThreadEngine);
|
AIEngine* default_engine = &gMainThreadEngine,
|
||||||
|
bool queue_if_too_much_bandwidth_usage = true);
|
||||||
|
|
||||||
/** @name non-blocking API */
|
/** @name non-blocking API */
|
||||||
//@{
|
//@{
|
||||||
@@ -465,6 +466,10 @@ public:
|
|||||||
static void post(std::string const& url, LLSD const& body, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive, AIStateMachine* parent = NULL, U32 new_parent_state = 0)
|
static void post(std::string const& url, LLSD const& body, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive, AIStateMachine* parent = NULL, U32 new_parent_state = 0)
|
||||||
{ AIHTTPHeaders headers; post(url, body, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, parent, new_parent_state); }
|
{ AIHTTPHeaders headers; post(url, body, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, parent, new_parent_state); }
|
||||||
|
|
||||||
|
static void post_nb(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive, AIStateMachine* parent = NULL, U32 new_parent_state = 0);
|
||||||
|
static void post_nb(std::string const& url, LLSD const& body, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive, AIStateMachine* parent = NULL, U32 new_parent_state = 0)
|
||||||
|
{ AIHTTPHeaders headers; post_nb(url, body, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, parent, new_parent_state); }
|
||||||
|
|
||||||
/** Takes ownership of request and deletes it when sent */
|
/** Takes ownership of request and deletes it when sent */
|
||||||
static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
|
static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
|
||||||
static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
|
static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
|
||||||
|
|||||||
@@ -75,10 +75,15 @@ std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action)
|
|||||||
|
|
||||||
// This might throw AICurlNoEasyHandle.
|
// This might throw AICurlNoEasyHandle.
|
||||||
LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url, Injector* body,
|
LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url, Injector* body,
|
||||||
LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool keepalive, bool is_auth, bool compression) :
|
LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool keepalive, bool is_auth, bool compression,
|
||||||
|
bool queue_if_too_much_bandwidth_usage) :
|
||||||
mAction(action), mURL(url), mKeepAlive(keepalive), mIsAuth(is_auth), mNoCompression(!compression),
|
mAction(action), mURL(url), mKeepAlive(keepalive), mIsAuth(is_auth), mNoCompression(!compression),
|
||||||
mBody(body), mResponder(responder), mHeaders(headers), mResponderNameCache(responder ? responder->getName() : "<uninitialized>")
|
mBody(body), mResponder(responder), mHeaders(headers), mResponderNameCache(responder ? responder->getName() : "<uninitialized>")
|
||||||
{
|
{
|
||||||
|
if (queue_if_too_much_bandwidth_usage)
|
||||||
|
{
|
||||||
|
AICurlEasyRequest_wat(*mCurlEasyRequest)->queue_if_too_much_bandwidth_usage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLURLRequest::initialize_impl(void)
|
void LLURLRequest::initialize_impl(void)
|
||||||
|
|||||||
@@ -64,7 +64,9 @@ class LLURLRequest : public AICurlEasyRequestStateMachine {
|
|||||||
* @param action One of the ERequestAction enumerations.
|
* @param action One of the ERequestAction enumerations.
|
||||||
* @param url The url of the request. It should already be encoded.
|
* @param url The url of the request. It should already be encoded.
|
||||||
*/
|
*/
|
||||||
LLURLRequest(ERequestAction action, std::string const& url, Injector* body, LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool keepalive, bool is_auth, bool no_compression);
|
LLURLRequest(ERequestAction action, std::string const& url, Injector* body,
|
||||||
|
LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers,
|
||||||
|
bool keepalive, bool is_auth, bool no_compression, bool queue_if_too_much_bandwidth_usage);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Cached value of responder->getName() as passed to the constructor.
|
* @brief Cached value of responder->getName() as passed to the constructor.
|
||||||
|
|||||||
@@ -50,7 +50,6 @@
|
|||||||
#include "lldarray.h"
|
#include "lldarray.h"
|
||||||
#include "lldir.h"
|
#include "lldir.h"
|
||||||
#include "llerror.h"
|
#include "llerror.h"
|
||||||
#include "llerrorlegacy.h"
|
|
||||||
#include "llfasttimer.h"
|
#include "llfasttimer.h"
|
||||||
#include "llhttpclient.h"
|
#include "llhttpclient.h"
|
||||||
#include "llhttpnodeadapter.h"
|
#include "llhttpnodeadapter.h"
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ include(LLPlugin)
|
|||||||
include(Linking)
|
include(Linking)
|
||||||
include(PluginAPI)
|
include(PluginAPI)
|
||||||
include(LLMessage)
|
include(LLMessage)
|
||||||
include(GooglePerfTools)
|
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
${LLPLUGIN_INCLUDE_DIRS}
|
${LLPLUGIN_INCLUDE_DIRS}
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ include(LLXML)
|
|||||||
#include(LScript)
|
#include(LScript)
|
||||||
include(Linking)
|
include(Linking)
|
||||||
include(NDOF)
|
include(NDOF)
|
||||||
include(GooglePerfTools)
|
|
||||||
include(StateMachine)
|
include(StateMachine)
|
||||||
include(TemplateCheck)
|
include(TemplateCheck)
|
||||||
include(UI)
|
include(UI)
|
||||||
@@ -90,6 +89,7 @@ set(viewer_SOURCE_FILES
|
|||||||
floaterao.cpp
|
floaterao.cpp
|
||||||
floaterlocalassetbrowse.cpp
|
floaterlocalassetbrowse.cpp
|
||||||
floatervoicelicense.cpp
|
floatervoicelicense.cpp
|
||||||
|
generichandlers.cpp
|
||||||
hbfloatergrouptitles.cpp
|
hbfloatergrouptitles.cpp
|
||||||
hippofloaterxml.cpp
|
hippofloaterxml.cpp
|
||||||
hippogridmanager.cpp
|
hippogridmanager.cpp
|
||||||
@@ -185,6 +185,7 @@ set(viewer_SOURCE_FILES
|
|||||||
llfloaterbuycontents.cpp
|
llfloaterbuycontents.cpp
|
||||||
llfloaterbuycurrency.cpp
|
llfloaterbuycurrency.cpp
|
||||||
llfloaterbuyland.cpp
|
llfloaterbuyland.cpp
|
||||||
|
llfloaterbvhpreview.cpp
|
||||||
llfloatercamera.cpp
|
llfloatercamera.cpp
|
||||||
llfloaterchat.cpp
|
llfloaterchat.cpp
|
||||||
llfloaterchatterbox.cpp
|
llfloaterchatterbox.cpp
|
||||||
@@ -591,6 +592,7 @@ set(viewer_HEADER_FILES
|
|||||||
floaterao.h
|
floaterao.h
|
||||||
floaterlocalassetbrowse.h
|
floaterlocalassetbrowse.h
|
||||||
floatervoicelicense.h
|
floatervoicelicense.h
|
||||||
|
generichandlers.h
|
||||||
hbfloatergrouptitles.h
|
hbfloatergrouptitles.h
|
||||||
hippofloaterxml.h
|
hippofloaterxml.h
|
||||||
hippogridmanager.h
|
hippogridmanager.h
|
||||||
@@ -687,6 +689,7 @@ set(viewer_HEADER_FILES
|
|||||||
llfloaterbuycontents.h
|
llfloaterbuycontents.h
|
||||||
llfloaterbuycurrency.h
|
llfloaterbuycurrency.h
|
||||||
llfloaterbuyland.h
|
llfloaterbuyland.h
|
||||||
|
llfloaterbvhpreview.h
|
||||||
llfloatercamera.h
|
llfloatercamera.h
|
||||||
llfloaterchat.h
|
llfloaterchat.h
|
||||||
llfloaterchatterbox.h
|
llfloaterchatterbox.h
|
||||||
|
|||||||
@@ -171,44 +171,14 @@
|
|||||||
<key>Value</key>
|
<key>Value</key>
|
||||||
<integer>1</integer>
|
<integer>1</integer>
|
||||||
</map>
|
</map>
|
||||||
|
|
||||||
<key>HTTPRequestRate</key>
|
|
||||||
<map>
|
|
||||||
<key>Comment</key>
|
|
||||||
<string>Number of HTTP texture requests fired per second.</string>
|
|
||||||
<key>Persist</key>
|
|
||||||
<integer>1</integer>
|
|
||||||
<key>Type</key>
|
|
||||||
<string>U32</string>
|
|
||||||
<key>Value</key>
|
|
||||||
<integer>30</integer>
|
|
||||||
</map>
|
|
||||||
<key>HTTPMaxRequests</key>
|
|
||||||
<map>
|
|
||||||
<key>Comment</key>
|
|
||||||
<string>Maximum number of simultaneous HTTP requests in progress.</string>
|
|
||||||
<key>Persist</key>
|
|
||||||
<integer>1</integer>
|
|
||||||
<key>Type</key>
|
|
||||||
<string>U32</string>
|
|
||||||
<key>Value</key>
|
|
||||||
<integer>12</integer>
|
|
||||||
</map>
|
|
||||||
<key>HTTPMinRequests</key>
|
|
||||||
<map>
|
|
||||||
<key>Comment</key>
|
|
||||||
<string>Attempt to maintain at least this many HTTP requests in progress by ignoring bandwidth</string>
|
|
||||||
<key>Persist</key>
|
|
||||||
<integer>1</integer>
|
|
||||||
<key>Type</key>
|
|
||||||
<string>U32</string>
|
|
||||||
<key>Value</key>
|
|
||||||
<integer>2</integer>
|
|
||||||
</map>
|
|
||||||
<key>HTTPThrottleBandwidth</key>
|
<key>HTTPThrottleBandwidth</key>
|
||||||
<map>
|
<map>
|
||||||
<key>Comment</key>
|
<key>Comment</key>
|
||||||
<string>The bandwidth (in kbit/s) to strive for</string>
|
<string>The bandwidth (in kbit/s) to strive for. Smaller values might reduce network
|
||||||
|
congestion (sim ping time, aka avatar responsiveness). Higher values might download
|
||||||
|
textures and the inventory faster, although in some cases a too high value might
|
||||||
|
actually slow that down due to serverside throttling. If unsure, choose 2000.</string>
|
||||||
<key>Persist</key>
|
<key>Persist</key>
|
||||||
<integer>1</integer>
|
<integer>1</integer>
|
||||||
<key>Type</key>
|
<key>Type</key>
|
||||||
@@ -4503,16 +4473,16 @@ This should be as low as possible, but too low may break functionality</string>
|
|||||||
<key>Value</key>
|
<key>Value</key>
|
||||||
<integer>64</integer>
|
<integer>64</integer>
|
||||||
</map>
|
</map>
|
||||||
<key>CurlConcurrentConnectionsPerHost</key>
|
<key>CurlConcurrentConnectionsPerService</key>
|
||||||
<map>
|
<map>
|
||||||
<key>Comment</key>
|
<key>Comment</key>
|
||||||
<string>Maximum number of simultaneous curl connections per host</string>
|
<string>Maximum number of simultaneous curl connections per host:port service</string>
|
||||||
<key>Persist</key>
|
<key>Persist</key>
|
||||||
<integer>0</integer>
|
<integer>0</integer>
|
||||||
<key>Type</key>
|
<key>Type</key>
|
||||||
<string>U32</string>
|
<string>U32</string>
|
||||||
<key>Value</key>
|
<key>Value</key>
|
||||||
<integer>16</integer>
|
<integer>8</integer>
|
||||||
</map>
|
</map>
|
||||||
<key>CurlTimeoutDNSLookup</key>
|
<key>CurlTimeoutDNSLookup</key>
|
||||||
<map>
|
<map>
|
||||||
@@ -4965,7 +4935,18 @@ This should be as low as possible, but too low may break functionality</string>
|
|||||||
<key>Value</key>
|
<key>Value</key>
|
||||||
<integer>-1</integer>
|
<integer>-1</integer>
|
||||||
</map>
|
</map>
|
||||||
<key>DebugStatModeTexture</key>
|
<key>DebugStatModeHTTPTexture</key>
|
||||||
|
<map>
|
||||||
|
<key>Comment</key>
|
||||||
|
<string>Mode of stat in Statistics floater</string>
|
||||||
|
<key>Persist</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>Type</key>
|
||||||
|
<string>S32</string>
|
||||||
|
<key>Value</key>
|
||||||
|
<integer>-1</integer>
|
||||||
|
</map>
|
||||||
|
<key>DebugStatModeUDPTexture</key>
|
||||||
<map>
|
<map>
|
||||||
<key>Comment</key>
|
<key>Comment</key>
|
||||||
<string>Mode of stat in Statistics floater</string>
|
<string>Mode of stat in Statistics floater</string>
|
||||||
|
|||||||
@@ -1,15 +1,48 @@
|
|||||||
<llsd>
|
<llsd>
|
||||||
<map>
|
<map>
|
||||||
<key>CrashSubmitBehavior</key>
|
<key>CrashSubmitBehavior</key>
|
||||||
<map>
|
<map>
|
||||||
<key>Comment</key>
|
<key>Comment</key>
|
||||||
<string>Controls behavior when viewer crashes (0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)</string>
|
<string>Controls behavior when viewer crashes (0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)</string>
|
||||||
<key>Persist</key>
|
<key>Persist</key>
|
||||||
<integer>2</integer>
|
<integer>2</integer>
|
||||||
<key>Type</key>
|
<key>Type</key>
|
||||||
<string>S32</string>
|
<string>S32</string>
|
||||||
<key>Value</key>
|
<key>Value</key>
|
||||||
<integer>2</integer>
|
<integer>2</integer>
|
||||||
</map>
|
|
||||||
</map>
|
</map>
|
||||||
|
<key>CurlMaxTotalConcurrentConnections</key>
|
||||||
|
<map>
|
||||||
|
<key>Comment</key>
|
||||||
|
<string>Maximum total number of simultaneous curl connections</string>
|
||||||
|
<key>Persist</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>Type</key>
|
||||||
|
<string>U32</string>
|
||||||
|
<key>Value</key>
|
||||||
|
<integer>64</integer>
|
||||||
|
</map>
|
||||||
|
<key>CurlConcurrentConnectionsPerService</key>
|
||||||
|
<map>
|
||||||
|
<key>Comment</key>
|
||||||
|
<string>Maximum number of simultaneous curl connections per host:port service</string>
|
||||||
|
<key>Persist</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>Type</key>
|
||||||
|
<string>U32</string>
|
||||||
|
<key>Value</key>
|
||||||
|
<integer>16</integer>
|
||||||
|
</map>
|
||||||
|
<key>NoVerifySSLCert</key>
|
||||||
|
<map>
|
||||||
|
<key>Comment</key>
|
||||||
|
<string>Do not verify SSL certificates.</string>
|
||||||
|
<key>Persist</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>Type</key>
|
||||||
|
<string>Boolean</string>
|
||||||
|
<key>Value</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
</map>
|
||||||
|
</map>
|
||||||
</llsd>
|
</llsd>
|
||||||
|
|||||||
75
indra/newview/generichandlers.cpp
Normal file
75
indra/newview/generichandlers.cpp
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) The Singularity dev Team and Melanie Thielker
|
||||||
|
* Refer to the singularity project for a full lst of copyright holders
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Neither the name of the Singularity Viewwer Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "llviewerprecompiledheaders.h"
|
||||||
|
#include "generichandlers.h"
|
||||||
|
#include "llviewergenericmessage.h"
|
||||||
|
#include "llviewerinventory.h"
|
||||||
|
#include "llappearancemgr.h"
|
||||||
|
#include "llviewerregion.h"
|
||||||
|
#include "llagent.h"
|
||||||
|
|
||||||
|
GenericHandlers *gGenericHandlers = NULL;
|
||||||
|
|
||||||
|
class DispatchReplaceOutfit : public LLDispatchHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual bool operator()(
|
||||||
|
const LLDispatcher* dispatcher,
|
||||||
|
const std::string& key,
|
||||||
|
const LLUUID& invoice,
|
||||||
|
const sparam_t& strings)
|
||||||
|
{
|
||||||
|
if (strings.size() != 1) return false;
|
||||||
|
LLUUID folder_id(strings[0]);
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id);
|
||||||
|
if (cat != NULL)
|
||||||
|
{
|
||||||
|
LLAppearanceMgr::instance().wearInventoryCategory(cat, FALSE, FALSE);
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLViewerRegion* regionp = gAgent.getRegion();
|
||||||
|
if (!regionp) return true;
|
||||||
|
|
||||||
|
std::string url = regionp->getCapability("WearablesLoaded");
|
||||||
|
if (url.empty()) return true;
|
||||||
|
|
||||||
|
LLSD data = LLSD(success);
|
||||||
|
|
||||||
|
LLHTTPClient::post(url, data, new LLHTTPClient::ResponderIgnore);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static DispatchReplaceOutfit sDispatchReplaceOutfit;
|
||||||
|
|
||||||
|
GenericHandlers::GenericHandlers()
|
||||||
|
{
|
||||||
|
gGenericDispatcher.addHandler("replaceoutfit", &sDispatchReplaceOutfit);
|
||||||
|
}
|
||||||
|
|
||||||
31
indra/newview/generichandlers.h
Normal file
31
indra/newview/generichandlers.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) The Singularity dev Team and Melanie Thielker
|
||||||
|
* Refer to the singularity project for a full lst of copyright holders
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Neither the name of the Singularity Viewwer Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class GenericHandlers
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GenericHandlers();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern GenericHandlers *gGenericHandlers;
|
||||||
@@ -64,6 +64,8 @@ class HippoFloaterXmlImpl : public LLFloater
|
|||||||
const std::string &cmds, std::string::size_type &offset,
|
const std::string &cmds, std::string::size_type &offset,
|
||||||
std::string &response);
|
std::string &response);
|
||||||
|
|
||||||
|
U32 mChannel;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string mName;
|
std::string mName;
|
||||||
bool mIsNotifyOnClose;
|
bool mIsNotifyOnClose;
|
||||||
@@ -162,7 +164,7 @@ void XmlData::release(const std::string &floaterName)
|
|||||||
// create HippoFloaterXmlImpl
|
// create HippoFloaterXmlImpl
|
||||||
|
|
||||||
HippoFloaterXmlImpl::HippoFloaterXmlImpl(const std::string &name, const std::string &xml) :
|
HippoFloaterXmlImpl::HippoFloaterXmlImpl(const std::string &name, const std::string &xml) :
|
||||||
mName(name), mIsNotifyOnClose(false)
|
mName(name), mIsNotifyOnClose(false), mChannel(CHANNEL)
|
||||||
{
|
{
|
||||||
gInstances[mName] = this;
|
gInstances[mName] = this;
|
||||||
LLUICtrlFactory::getInstance()->buildFloaterFromBuffer(this, xml);
|
LLUICtrlFactory::getInstance()->buildFloaterFromBuffer(this, xml);
|
||||||
@@ -223,7 +225,7 @@ void HippoFloaterXml::execute(const std::string &cmds)
|
|||||||
if (!floater->execute(floater, floater, cmds, offset, response))
|
if (!floater->execute(floater, floater, cmds, offset, response))
|
||||||
break;
|
break;
|
||||||
if (!response.empty())
|
if (!response.empty())
|
||||||
send_chat_from_viewer(response, CHAT_TYPE_WHISPER, CHANNEL);
|
send_chat_from_viewer(response, CHAT_TYPE_WHISPER, floater->mChannel);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
|
|
||||||
@@ -267,18 +269,22 @@ void HippoFloaterXml::execute(const std::string &cmds)
|
|||||||
// ********************************************************************
|
// ********************************************************************
|
||||||
// generic notification callbacks
|
// generic notification callbacks
|
||||||
|
|
||||||
static void notifyCallback(void *c)
|
static void notifyCallback(void *c, void *f)
|
||||||
{
|
{
|
||||||
|
HippoFloaterXmlImpl* floaterp = (HippoFloaterXmlImpl*)f;
|
||||||
|
|
||||||
LLUICtrl *ctrl = (LLUICtrl *)c;
|
LLUICtrl *ctrl = (LLUICtrl *)c;
|
||||||
std::string msg = "NOTIFY:";
|
std::string msg = "NOTIFY:";
|
||||||
msg += ctrl->getName();
|
msg += ctrl->getName();
|
||||||
msg += ':';
|
msg += ':';
|
||||||
msg += ctrl->getValue().asString();
|
msg += ctrl->getValue().asString();
|
||||||
send_chat_from_viewer(msg, CHAT_TYPE_WHISPER, CHANNEL);
|
send_chat_from_viewer(msg, CHAT_TYPE_WHISPER, floaterp->mChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void callbackAvatarPick(void *c, const uuid_vec_t& ids, const std::vector<LLAvatarName>& names)
|
void callbackAvatarPick(void *c, void *f, const uuid_vec_t& ids, const std::vector<LLAvatarName>& names)
|
||||||
{
|
{
|
||||||
|
HippoFloaterXmlImpl* floaterp = (HippoFloaterXmlImpl*)f;
|
||||||
|
|
||||||
LLUICtrl *ctrl = (LLUICtrl *)c;
|
LLUICtrl *ctrl = (LLUICtrl *)c;
|
||||||
|
|
||||||
LLUUID id = ids[0];
|
LLUUID id = ids[0];
|
||||||
@@ -289,7 +295,7 @@ void callbackAvatarPick(void *c, const uuid_vec_t& ids, const std::vector<LLAvat
|
|||||||
msg += id.asString();
|
msg += id.asString();
|
||||||
msg += ':';
|
msg += ':';
|
||||||
msg += names[0].getCompleteName();
|
msg += names[0].getCompleteName();
|
||||||
send_chat_from_viewer(msg, CHAT_TYPE_WHISPER, CHANNEL);
|
send_chat_from_viewer(msg, CHAT_TYPE_WHISPER, floaterp->mChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pickerCallback(void *c, void *f)
|
static void pickerCallback(void *c, void *f)
|
||||||
@@ -297,7 +303,7 @@ static void pickerCallback(void *c, void *f)
|
|||||||
LLUICtrl *ctrl = (LLUICtrl *)c;
|
LLUICtrl *ctrl = (LLUICtrl *)c;
|
||||||
HippoFloaterXmlImpl* floaterp = (HippoFloaterXmlImpl*)f;
|
HippoFloaterXmlImpl* floaterp = (HippoFloaterXmlImpl*)f;
|
||||||
|
|
||||||
floaterp->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&callbackAvatarPick, ctrl, _1, _2), FALSE, TRUE));
|
floaterp->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&callbackAvatarPick, ctrl, floaterp, _1, _2), FALSE, TRUE));
|
||||||
//send_chat_from_viewer(msg, CHAT_TYPE_WHISPER, CHANNEL);
|
//send_chat_from_viewer(msg, CHAT_TYPE_WHISPER, CHANNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,7 +311,7 @@ void HippoFloaterXmlImpl::onClose(bool quitting)
|
|||||||
{
|
{
|
||||||
if (mIsNotifyOnClose)
|
if (mIsNotifyOnClose)
|
||||||
send_chat_from_viewer("NOTIFY:" + mName + ":closed",
|
send_chat_from_viewer("NOTIFY:" + mName + ":closed",
|
||||||
CHAT_TYPE_WHISPER, CHANNEL);
|
CHAT_TYPE_WHISPER, mChannel);
|
||||||
LLFloater::onClose(quitting);
|
LLFloater::onClose(quitting);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,17 +348,23 @@ bool HippoFloaterXmlImpl::execute(LLFloater *floater, LLUICtrl *ctrl,
|
|||||||
return false;
|
return false;
|
||||||
} else if (key == "setValue") {
|
} else if (key == "setValue") {
|
||||||
ctrl->setValue(value);
|
ctrl->setValue(value);
|
||||||
|
} else if (key == "channel") {
|
||||||
|
if (HippoFloaterXmlImpl *floater = dynamic_cast<HippoFloaterXmlImpl*>(ctrl)) {
|
||||||
|
floater->mChannel = atoi(value.c_str());
|
||||||
|
}
|
||||||
} else if (key == "setLabel") {
|
} else if (key == "setLabel") {
|
||||||
/*ctrl->setLabel(value);*/
|
/*ctrl->setLabel(value);*/
|
||||||
} else if (key == "setVisible") {
|
} else if (key == "setVisible") {
|
||||||
ctrl->setVisible(value != "0");
|
ctrl->setVisible(value != "0");
|
||||||
|
} else if (key == "setEnabled") {
|
||||||
|
ctrl->setEnabled(value != "0");
|
||||||
} else if (key == "notify") {
|
} else if (key == "notify") {
|
||||||
bool set = (value != "0");
|
bool set = (value != "0");
|
||||||
if (HippoFloaterXmlImpl *floater = dynamic_cast<HippoFloaterXmlImpl*>(ctrl)) {
|
if (HippoFloaterXmlImpl *floaterp = dynamic_cast<HippoFloaterXmlImpl*>(ctrl)) {
|
||||||
floater->mIsNotifyOnClose = set;
|
floaterp->mIsNotifyOnClose = set;
|
||||||
} else {
|
} else {
|
||||||
if (set)
|
if (set)
|
||||||
ctrl->setCommitCallback(boost::bind(¬ifyCallback, _1), ctrl);
|
ctrl->setCommitCallback(boost::bind(¬ifyCallback, _1, floater), ctrl);
|
||||||
else
|
else
|
||||||
ctrl->setCommitCallback(0);
|
ctrl->setCommitCallback(0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,13 +52,16 @@ HippoGridInfo::HippoGridInfo(const std::string& gridName) :
|
|||||||
mXmlState(XML_VOID),
|
mXmlState(XML_VOID),
|
||||||
mVoiceConnector("SLVoice"),
|
mVoiceConnector("SLVoice"),
|
||||||
mIsInProductionGrid(false),
|
mIsInProductionGrid(false),
|
||||||
|
mIsInAvination(false),
|
||||||
mRenderCompat(true),
|
mRenderCompat(true),
|
||||||
mInvLinks(false),
|
mInvLinks(false),
|
||||||
mAutoUpdate(false),
|
mAutoUpdate(false),
|
||||||
mMaxAgentGroups(-1),
|
mMaxAgentGroups(-1),
|
||||||
mCurrencySymbol("OS$"),
|
mCurrencySymbol("OS$"),
|
||||||
|
mCurrencyText("OS Dollars"),
|
||||||
mRealCurrencySymbol("US$"),
|
mRealCurrencySymbol("US$"),
|
||||||
mDirectoryFee(30)
|
mDirectoryFee(30),
|
||||||
|
mUPCSupported(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,37 +69,6 @@ HippoGridInfo::HippoGridInfo(const std::string& gridName) :
|
|||||||
// ********************************************************************
|
// ********************************************************************
|
||||||
// Getters
|
// Getters
|
||||||
|
|
||||||
HippoGridInfo::Platform HippoGridInfo::getPlatform()
|
|
||||||
{
|
|
||||||
return mPlatform;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HippoGridInfo::isOpenSimulator() const
|
|
||||||
{
|
|
||||||
return (mPlatform == HippoGridInfo::PLATFORM_OPENSIM || mPlatform == HippoGridInfo::PLATFORM_AURORA);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HippoGridInfo::isAurora() const
|
|
||||||
{
|
|
||||||
return (mPlatform == HippoGridInfo::PLATFORM_AURORA);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HippoGridInfo::isSecondLife() const
|
|
||||||
{
|
|
||||||
return (mPlatform == HippoGridInfo::PLATFORM_SECONDLIFE);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HippoGridInfo::isInProductionGrid() const
|
|
||||||
{
|
|
||||||
llassert(mPlatform == HippoGridInfo::PLATFORM_SECONDLIFE);
|
|
||||||
return mIsInProductionGrid;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& HippoGridInfo::getGridName() const
|
|
||||||
{
|
|
||||||
return mGridName;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& HippoGridInfo::getGridOwner() const
|
const std::string& HippoGridInfo::getGridOwner() const
|
||||||
{
|
{
|
||||||
if(isSecondLife())
|
if(isSecondLife())
|
||||||
@@ -110,68 +82,6 @@ const std::string& HippoGridInfo::getGridOwner() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& HippoGridInfo::getLoginUri() const
|
|
||||||
{
|
|
||||||
return mLoginUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& HippoGridInfo::getLoginPage() const
|
|
||||||
{
|
|
||||||
return mLoginPage;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& HippoGridInfo::getHelperUri() const
|
|
||||||
{
|
|
||||||
return mHelperUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& HippoGridInfo::getWebSite() const
|
|
||||||
{
|
|
||||||
return mWebSite;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& HippoGridInfo::getSupportUrl() const
|
|
||||||
{
|
|
||||||
return mSupportUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& HippoGridInfo::getRegisterUrl() const
|
|
||||||
{
|
|
||||||
return mRegisterUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& HippoGridInfo::getPasswordUrl() const
|
|
||||||
{
|
|
||||||
return mPasswordUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& HippoGridInfo::getSearchUrl() const
|
|
||||||
{
|
|
||||||
return mSearchUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& HippoGridInfo::getGridMessage() const
|
|
||||||
{
|
|
||||||
return mGridMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HippoGridInfo::isRenderCompat() const
|
|
||||||
{
|
|
||||||
return mRenderCompat;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& HippoGridInfo::getCurrencySymbol() const
|
|
||||||
{
|
|
||||||
return mCurrencySymbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& HippoGridInfo::getRealCurrencySymbol() const
|
|
||||||
{
|
|
||||||
return mRealCurrencySymbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ********************************************************************
|
// ********************************************************************
|
||||||
// Setters
|
// Setters
|
||||||
|
|
||||||
@@ -181,6 +91,7 @@ void HippoGridInfo::setPlatform(Platform platform)
|
|||||||
if (mPlatform == PLATFORM_SECONDLIFE)
|
if (mPlatform == PLATFORM_SECONDLIFE)
|
||||||
{
|
{
|
||||||
mCurrencySymbol = "L$";
|
mCurrencySymbol = "L$";
|
||||||
|
mCurrencyText = "Linden Dollars";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,6 +151,10 @@ void HippoGridInfo::setGridNick(std::string gridNick)
|
|||||||
{
|
{
|
||||||
mIsInProductionGrid = true;
|
mIsInProductionGrid = true;
|
||||||
}
|
}
|
||||||
|
if(gridNick == "avination")
|
||||||
|
{
|
||||||
|
mIsInAvination = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HippoGridInfo::setLoginUri(const std::string& loginUri)
|
void HippoGridInfo::setLoginUri(const std::string& loginUri)
|
||||||
@@ -250,6 +165,11 @@ void HippoGridInfo::setLoginUri(const std::string& loginUri)
|
|||||||
{
|
{
|
||||||
mIsInProductionGrid = true;
|
mIsInProductionGrid = true;
|
||||||
}
|
}
|
||||||
|
if (utf8str_tolower(LLURI(uri).hostName()) == "login.avination.com" ||
|
||||||
|
utf8str_tolower(LLURI(uri).hostName()) == "login.avination.net")
|
||||||
|
{
|
||||||
|
mIsInAvination = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HippoGridInfo::setLoginPage(const std::string& loginPage)
|
void HippoGridInfo::setLoginPage(const std::string& loginPage)
|
||||||
@@ -303,6 +223,11 @@ void HippoGridInfo::setCurrencySymbol(const std::string& sym)
|
|||||||
mCurrencySymbol = sym.substr(0, 3);
|
mCurrencySymbol = sym.substr(0, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HippoGridInfo::setCurrencyText(const std::string& text)
|
||||||
|
{
|
||||||
|
mCurrencyText = text;
|
||||||
|
}
|
||||||
|
|
||||||
void HippoGridInfo::setRealCurrencySymbol(const std::string& sym)
|
void HippoGridInfo::setRealCurrencySymbol(const std::string& sym)
|
||||||
{
|
{
|
||||||
mRealCurrencySymbol = sym.substr(0, 3);
|
mRealCurrencySymbol = sym.substr(0, 3);
|
||||||
@@ -456,8 +381,11 @@ void HippoGridInfo::onXmlCharacterData(void* userData, const XML_Char* s, int le
|
|||||||
{
|
{
|
||||||
case XML_GRIDNICK:
|
case XML_GRIDNICK:
|
||||||
{
|
{
|
||||||
if (self->mGridNick == "") self->mGridNick.assign(s, len);
|
if (self->mGridNick == "")
|
||||||
self->mGridNick = sanitizeGridNick(self->mGridNick);
|
{
|
||||||
|
self->mGridNick.assign(s, len);
|
||||||
|
self->mGridNick = sanitizeGridNick(self->mGridNick);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,7 +417,15 @@ void HippoGridInfo::onXmlCharacterData(void* userData, const XML_Char* s, int le
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case XML_GRIDNAME: self->mGridName.assign(s, len); break;
|
case XML_GRIDNAME:
|
||||||
|
{
|
||||||
|
if (self->mGridName == "")
|
||||||
|
{
|
||||||
|
self->mGridName.assign(s, len);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case XML_LOGINPAGE: self->mLoginPage.assign(s, len); break;
|
case XML_LOGINPAGE: self->mLoginPage.assign(s, len); break;
|
||||||
case XML_WEBSITE: self->mWebSite.assign(s, len); break;
|
case XML_WEBSITE: self->mWebSite.assign(s, len); break;
|
||||||
case XML_SUPPORT: self->mSupportUrl.assign(s, len); break;
|
case XML_SUPPORT: self->mSupportUrl.assign(s, len); break;
|
||||||
@@ -676,6 +612,19 @@ void HippoGridInfo::setAutoUpdate(bool b)
|
|||||||
mAutoUpdate = b;
|
mAutoUpdate = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HippoGridInfo::getUPCSupported()
|
||||||
|
{
|
||||||
|
if(isSecondLife())
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return mUPCSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HippoGridInfo::setUPCSupported(bool b)
|
||||||
|
{
|
||||||
|
mUPCSupported = b;
|
||||||
|
}
|
||||||
|
|
||||||
// ********************************************************************
|
// ********************************************************************
|
||||||
// ********************************************************************
|
// ********************************************************************
|
||||||
// HippoGridManager
|
// HippoGridManager
|
||||||
@@ -747,13 +696,6 @@ HippoGridInfo* HippoGridManager::getGrid(const std::string& grid) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HippoGridInfo* HippoGridManager::getConnectedGrid() const
|
|
||||||
{
|
|
||||||
return (mConnectedGrid)? mConnectedGrid: getCurrentGrid();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HippoGridInfo* HippoGridManager::getCurrentGrid() const
|
HippoGridInfo* HippoGridManager::getCurrentGrid() const
|
||||||
{
|
{
|
||||||
HippoGridInfo* grid = getGrid(mCurrentGrid);
|
HippoGridInfo* grid = getGrid(mCurrentGrid);
|
||||||
|
|||||||
@@ -36,31 +36,33 @@ public:
|
|||||||
|
|
||||||
explicit HippoGridInfo(const std::string& gridName);
|
explicit HippoGridInfo(const std::string& gridName);
|
||||||
|
|
||||||
Platform getPlatform();
|
Platform getPlatform() { return mPlatform; }
|
||||||
bool isOpenSimulator() const;
|
bool isOpenSimulator() const { return (mPlatform == PLATFORM_OPENSIM || mPlatform == PLATFORM_AURORA); }
|
||||||
bool isAurora() const;
|
bool isAurora() const { return (mPlatform == PLATFORM_AURORA); }
|
||||||
bool isSecondLife() const;
|
bool isSecondLife() const { return (mPlatform == PLATFORM_SECONDLIFE); }
|
||||||
bool isInProductionGrid() const; // Should only be called if isSecondLife() returns true.
|
bool isAvination() const { return mIsInAvination; }
|
||||||
const std::string& getGridName() const;
|
bool isInProductionGrid() const { llassert(mPlatform == PLATFORM_SECONDLIFE); return mIsInProductionGrid; } // Should only be called if isSecondLife() returns true.
|
||||||
|
const std::string& getGridName() const { return mGridName; }
|
||||||
const std::string& getGridOwner() const;
|
const std::string& getGridOwner() const;
|
||||||
const std::string& getLoginUri() const;
|
const std::string& getLoginUri() const { return mLoginUri; }
|
||||||
const std::string& getLoginPage() const;
|
const std::string& getLoginPage() const { return mLoginPage; }
|
||||||
const std::string& getHelperUri() const;
|
const std::string& getHelperUri() const { return mHelperUri; }
|
||||||
const std::string& getWebSite() const;
|
const std::string& getWebSite() const { return mWebSite; }
|
||||||
const std::string& getSupportUrl() const;
|
const std::string& getSupportUrl() const { return mSupportUrl; }
|
||||||
const std::string& getRegisterUrl() const;
|
const std::string& getRegisterUrl() const { return mRegisterUrl; }
|
||||||
const std::string& getPasswordUrl() const;
|
const std::string& getPasswordUrl() const { return mPasswordUrl; }
|
||||||
// Returns the url base used for the Web Search tab
|
// Returns the url base used for the Web Search tab
|
||||||
const std::string& getSearchUrl() const;
|
const std::string& getSearchUrl() const { return mSearchUrl; }
|
||||||
const std::string& getGridMessage() const;
|
const std::string& getGridMessage() const { return mGridMessage; }
|
||||||
const std::string& getVoiceConnector() const { return mVoiceConnector; }
|
const std::string& getVoiceConnector() const { return mVoiceConnector; }
|
||||||
std::string getSearchUrl(SearchType ty, bool is_web) const;
|
std::string getSearchUrl(SearchType ty, bool is_web) const;
|
||||||
bool isRenderCompat() const;
|
bool isRenderCompat() const { return mRenderCompat; }
|
||||||
std::string getGridNick();
|
std::string getGridNick();
|
||||||
int getMaxAgentGroups() const { return mMaxAgentGroups; }
|
int getMaxAgentGroups() const { return mMaxAgentGroups; }
|
||||||
|
|
||||||
const std::string& getCurrencySymbol() const;
|
const std::string& getCurrencySymbol() const { return mCurrencySymbol; }
|
||||||
const std::string& getRealCurrencySymbol() const;
|
const std::string& getCurrencyText() const { return mCurrencyText; }
|
||||||
|
const std::string& getRealCurrencySymbol() const { return mRealCurrencySymbol; }
|
||||||
std::string getUploadFee() const;
|
std::string getUploadFee() const;
|
||||||
std::string getGroupCreationFee() const;
|
std::string getGroupCreationFee() const;
|
||||||
std::string getDirectoryFee() const;
|
std::string getDirectoryFee() const;
|
||||||
@@ -82,8 +84,11 @@ public:
|
|||||||
void setRenderCompat(bool compat);
|
void setRenderCompat(bool compat);
|
||||||
void setMaxAgentGroups(int max) { mMaxAgentGroups = max; }
|
void setMaxAgentGroups(int max) { mMaxAgentGroups = max; }
|
||||||
void setVoiceConnector(const std::string& vc) { mVoiceConnector = vc; }
|
void setVoiceConnector(const std::string& vc) { mVoiceConnector = vc; }
|
||||||
|
void setUPCSupported(bool on);
|
||||||
|
bool getUPCSupported();
|
||||||
|
|
||||||
void setCurrencySymbol(const std::string& sym);
|
void setCurrencySymbol(const std::string& sym);
|
||||||
|
void setCurrencyText(const std::string& text);
|
||||||
void setRealCurrencySymbol(const std::string& sym);
|
void setRealCurrencySymbol(const std::string& sym);
|
||||||
void setDirectoryFee(int fee);
|
void setDirectoryFee(int fee);
|
||||||
bool supportsInvLinks();
|
bool supportsInvLinks();
|
||||||
@@ -113,12 +118,15 @@ private:
|
|||||||
std::string mSearchUrl;
|
std::string mSearchUrl;
|
||||||
std::string mVoiceConnector;
|
std::string mVoiceConnector;
|
||||||
bool mIsInProductionGrid;
|
bool mIsInProductionGrid;
|
||||||
|
bool mIsInAvination;
|
||||||
bool mRenderCompat;
|
bool mRenderCompat;
|
||||||
bool mInvLinks;
|
bool mInvLinks;
|
||||||
bool mAutoUpdate;
|
bool mAutoUpdate;
|
||||||
|
bool mUPCSupported;
|
||||||
int mMaxAgentGroups;
|
int mMaxAgentGroups;
|
||||||
|
|
||||||
std::string mCurrencySymbol;
|
std::string mCurrencySymbol;
|
||||||
|
std::string mCurrencyText;
|
||||||
std::string mRealCurrencySymbol;
|
std::string mRealCurrencySymbol;
|
||||||
int mDirectoryFee;
|
int mDirectoryFee;
|
||||||
std::string mGridMessage;
|
std::string mGridMessage;
|
||||||
@@ -152,7 +160,8 @@ public:
|
|||||||
void discardAndReload();
|
void discardAndReload();
|
||||||
|
|
||||||
HippoGridInfo* getGrid(const std::string& grid) const;
|
HippoGridInfo* getGrid(const std::string& grid) const;
|
||||||
HippoGridInfo* getConnectedGrid() const;
|
HippoGridInfo* getConnectedGrid() const { return mConnectedGrid ? mConnectedGrid : getCurrentGrid(); }
|
||||||
|
|
||||||
HippoGridInfo* getCurrentGrid() const;
|
HippoGridInfo* getCurrentGrid() const;
|
||||||
const std::string& getDefaultGridNick() const;
|
const std::string& getDefaultGridNick() const;
|
||||||
const std::string& getCurrentGridNick() const;
|
const std::string& getCurrentGridNick() const;
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ BOOL HippoPanelGridsImpl::postBuild()
|
|||||||
requires<LLButton>("btn_add");
|
requires<LLButton>("btn_add");
|
||||||
requires<LLButton>("btn_copy");
|
requires<LLButton>("btn_copy");
|
||||||
requires<LLButton>("btn_default");
|
requires<LLButton>("btn_default");
|
||||||
//requires<LLButton>("btn_gridinfo");
|
requires<LLButton>("btn_gridinfo");
|
||||||
requires<LLButton>("btn_help_render_compat");
|
requires<LLButton>("btn_help_render_compat");
|
||||||
if (!checkRequirements()) return false;
|
if (!checkRequirements()) return false;
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ BOOL HippoPanelGridsImpl::postBuild()
|
|||||||
childSetAction("btn_add", onClickAdd, this);
|
childSetAction("btn_add", onClickAdd, this);
|
||||||
childSetAction("btn_copy", onClickCopy, this);
|
childSetAction("btn_copy", onClickCopy, this);
|
||||||
childSetAction("btn_default", onClickDefault, this);
|
childSetAction("btn_default", onClickDefault, this);
|
||||||
//childSetAction("btn_gridinfo", onClickGridInfo, this);
|
childSetAction("btn_gridinfo", onClickGridInfo, this);
|
||||||
childSetAction("btn_help_render_compat", onClickHelpRenderCompat, this);
|
childSetAction("btn_help_render_compat", onClickHelpRenderCompat, this);
|
||||||
childSetAction("btn_advanced", onClickAdvanced, this);
|
childSetAction("btn_advanced", onClickAdvanced, this);
|
||||||
|
|
||||||
|
|||||||
0
indra/newview/linux_tools/refresh_desktop_app_entry.sh
Normal file → Executable file
0
indra/newview/linux_tools/refresh_desktop_app_entry.sh
Normal file → Executable file
@@ -141,7 +141,7 @@ if [ -n "$LL_TCMALLOC" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
export VIEWER_BINARY='singularity-do-not-run-directly'
|
export VIEWER_BINARY='singularity-do-not-run-directly'
|
||||||
BINARY_TYPE=$(expr match "$(file -b bin/$VIEWER_BINARY)" '\(.*executable\)')
|
BINARY_TYPE=$(expr match "$(file -b bin/$VIEWER_BINARY)" '\(.*executable\)' | sed -e 's/ / /g')
|
||||||
if [ "${BINARY_TYPE}" == "ELF 64-bit LSB executable" ]; then
|
if [ "${BINARY_TYPE}" == "ELF 64-bit LSB executable" ]; then
|
||||||
SL_ENV+='LD_LIBRARY_PATH="`pwd`/lib64:`pwd`/lib32:$LD_LIBRARY_PATH"'
|
SL_ENV+='LD_LIBRARY_PATH="`pwd`/lib64:`pwd`/lib32:$LD_LIBRARY_PATH"'
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ void LLInitialWearablesFetch::processContents()
|
|||||||
LLInventoryModel::cat_array_t cat_array;
|
LLInventoryModel::cat_array_t cat_array;
|
||||||
LLInventoryModel::item_array_t wearable_array;
|
LLInventoryModel::item_array_t wearable_array;
|
||||||
LLFindWearables is_wearable;
|
LLFindWearables is_wearable;
|
||||||
llassert_always(mComplete.size() != 0);
|
llassert(mComplete.size() != 0);
|
||||||
gInventory.collectDescendentsIf(mComplete.front(), cat_array, wearable_array,
|
gInventory.collectDescendentsIf(mComplete.front(), cat_array, wearable_array,
|
||||||
LLInventoryModel::EXCLUDE_TRASH, is_wearable);
|
LLInventoryModel::EXCLUDE_TRASH, is_wearable);
|
||||||
|
|
||||||
|
|||||||
@@ -1895,9 +1895,7 @@ bool LLAppViewer::initThreads()
|
|||||||
// State machine thread.
|
// State machine thread.
|
||||||
startEngineThread();
|
startEngineThread();
|
||||||
|
|
||||||
AICurlInterface::startCurlThread(gSavedSettings.getU32("CurlMaxTotalConcurrentConnections"),
|
AICurlInterface::startCurlThread(&gSavedSettings);
|
||||||
gSavedSettings.getU32("CurlConcurrentConnectionsPerHost"),
|
|
||||||
gSavedSettings.getBOOL("NoVerifySSLCert"));
|
|
||||||
|
|
||||||
LLImage::initClass();
|
LLImage::initClass();
|
||||||
|
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ namespace
|
|||||||
if (!content.get("events") ||
|
if (!content.get("events") ||
|
||||||
!content.get("id"))
|
!content.get("id"))
|
||||||
{
|
{
|
||||||
llwarns << "received event poll with no events or id key" << llendl;
|
//llwarns << "received event poll with no events or id key" << llendl;
|
||||||
makeRequest();
|
makeRequest();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2,9 +2,7 @@
|
|||||||
* @file llfloateranimpreview.h
|
* @file llfloateranimpreview.h
|
||||||
* @brief LLFloaterAnimPreview class definition
|
* @brief LLFloaterAnimPreview class definition
|
||||||
*
|
*
|
||||||
* $LicenseInfo:firstyear=2004&license=viewergpl$
|
* Copyright (c) 2012, Linden Research, Inc.
|
||||||
*
|
|
||||||
* Copyright (c) 2004-2009, Linden Research, Inc.
|
|
||||||
*
|
*
|
||||||
* Second Life Viewer Source Code
|
* Second Life Viewer Source Code
|
||||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||||
@@ -34,112 +32,11 @@
|
|||||||
#define LL_LLFLOATERANIMPREVIEW_H
|
#define LL_LLFLOATERANIMPREVIEW_H
|
||||||
|
|
||||||
#include "llfloaternamedesc.h"
|
#include "llfloaternamedesc.h"
|
||||||
#include "lldynamictexture.h"
|
|
||||||
#include "llcharacter.h"
|
|
||||||
#include "llquaternion.h"
|
|
||||||
|
|
||||||
class LLVOAvatar;
|
class LLFloaterAnimPreview : public LLFloaterNameDesc {
|
||||||
class LLViewerJointMesh;
|
public:
|
||||||
|
LLFloaterAnimPreview(LLSD const& filename);
|
||||||
class LLPreviewAnimation : public LLViewerDynamicTexture
|
virtual BOOL postBuild(void);
|
||||||
{
|
|
||||||
protected:
|
|
||||||
virtual ~LLPreviewAnimation();
|
|
||||||
|
|
||||||
public:
|
|
||||||
LLPreviewAnimation(S32 width, S32 height);
|
|
||||||
|
|
||||||
/*virtual*/ S8 getType() const ;
|
|
||||||
|
|
||||||
BOOL render();
|
|
||||||
void requestUpdate();
|
|
||||||
void rotate(F32 yaw_radians, F32 pitch_radians);
|
|
||||||
void zoom(F32 zoom_delta);
|
|
||||||
void setZoom(F32 zoom_amt);
|
|
||||||
void pan(F32 right, F32 up);
|
|
||||||
virtual BOOL needsUpdate() { return mNeedsUpdate; }
|
|
||||||
|
|
||||||
LLVOAvatar* getDummyAvatar() { return mDummyAvatar; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
BOOL mNeedsUpdate;
|
|
||||||
F32 mCameraDistance;
|
|
||||||
F32 mCameraYaw;
|
|
||||||
F32 mCameraPitch;
|
|
||||||
F32 mCameraZoom;
|
|
||||||
LLVector3 mCameraOffset;
|
|
||||||
LLVector3 mCameraRelPos;
|
|
||||||
LLPointer<LLVOAvatar> mDummyAvatar;
|
|
||||||
};
|
|
||||||
|
|
||||||
class LLFloaterAnimPreview : public LLFloaterNameDesc
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
//<edit>
|
|
||||||
LLFloaterAnimPreview(const std::string& filename, void* item = NULL);
|
|
||||||
//<edit>
|
|
||||||
virtual ~LLFloaterAnimPreview();
|
|
||||||
|
|
||||||
BOOL postBuild();
|
|
||||||
|
|
||||||
BOOL handleMouseDown(S32 x, S32 y, MASK mask);
|
|
||||||
BOOL handleMouseUp(S32 x, S32 y, MASK mask);
|
|
||||||
BOOL handleHover(S32 x, S32 y, MASK mask);
|
|
||||||
BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
|
|
||||||
void onMouseCaptureLost();
|
|
||||||
|
|
||||||
void refresh();
|
|
||||||
|
|
||||||
static void onBtnPlay(void*);
|
|
||||||
static void onBtnStop(void*);
|
|
||||||
static void setUploadAmount(S32 amount) { sUploadAmount = amount; }
|
|
||||||
static void onSliderMove(LLUICtrl*, void*);
|
|
||||||
static void onCommitBaseAnim(LLUICtrl*, void*);
|
|
||||||
static void onCommitLoop(LLUICtrl*, void*);
|
|
||||||
static void onCommitLoopIn(LLUICtrl*, void*);
|
|
||||||
static void onCommitLoopOut(LLUICtrl*, void*);
|
|
||||||
static BOOL validateLoopIn(LLUICtrl*, void*);
|
|
||||||
static BOOL validateLoopOut(LLUICtrl*, void*);
|
|
||||||
static void onCommitName(LLUICtrl*, void*);
|
|
||||||
static void onCommitHandPose(LLUICtrl*, void*);
|
|
||||||
static void onCommitEmote(LLUICtrl*, void*);
|
|
||||||
static void onCommitPriority(LLUICtrl*, void*);
|
|
||||||
static void onCommitEaseIn(LLUICtrl*, void*);
|
|
||||||
static void onCommitEaseOut(LLUICtrl*, void*);
|
|
||||||
static BOOL validateEaseIn(LLUICtrl*, void*);
|
|
||||||
static BOOL validateEaseOut(LLUICtrl*, void*);
|
|
||||||
static void onBtnOK(void*);
|
|
||||||
static void onSaveComplete(const LLUUID& asset_uuid,
|
|
||||||
LLAssetType::EType type,
|
|
||||||
void* user_data,
|
|
||||||
S32 status, LLExtStat ext_status);
|
|
||||||
private:
|
|
||||||
void setAnimCallbacks() ;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void draw();
|
|
||||||
void resetMotion();
|
|
||||||
|
|
||||||
LLPointer< LLPreviewAnimation> mAnimPreview;
|
|
||||||
S32 mLastMouseX;
|
|
||||||
S32 mLastMouseY;
|
|
||||||
LLButton* mPlayButton;
|
|
||||||
LLButton* mStopButton;
|
|
||||||
LLRect mPreviewRect;
|
|
||||||
LLRectf mPreviewImageRect;
|
|
||||||
LLAssetID mMotionID;
|
|
||||||
LLTransactionID mTransactionID;
|
|
||||||
BOOL mEnabled;
|
|
||||||
BOOL mInWorld;
|
|
||||||
LLAnimPauseRequest mPauseRequest;
|
|
||||||
|
|
||||||
std::map<std::string, LLUUID> mIDList;
|
|
||||||
|
|
||||||
static S32 sUploadAmount;
|
|
||||||
|
|
||||||
//<edit>
|
|
||||||
void* mItem;
|
|
||||||
//</edit>
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LL_LLFLOATERANIMPREVIEW_H
|
#endif // LL_LLFLOATERANIMPREVIEW_H
|
||||||
|
|||||||
@@ -43,6 +43,25 @@ void LLFloaterBlacklist::show()
|
|||||||
sInstance->open();
|
sInstance->open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// static
|
||||||
|
void LLFloaterBlacklist::toggle()
|
||||||
|
{
|
||||||
|
if (sInstance && sInstance->getVisible())
|
||||||
|
{
|
||||||
|
delete sInstance;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// static
|
||||||
|
BOOL LLFloaterBlacklist::visible()
|
||||||
|
{
|
||||||
|
if (sInstance && sInstance->getVisible())
|
||||||
|
return TRUE;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
BOOL LLFloaterBlacklist::postBuild()
|
BOOL LLFloaterBlacklist::postBuild()
|
||||||
{
|
{
|
||||||
childSetAction("add_btn", onClickAdd, this);
|
childSetAction("add_btn", onClickAdd, this);
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ public:
|
|||||||
LLFloaterBlacklist();
|
LLFloaterBlacklist();
|
||||||
~LLFloaterBlacklist();
|
~LLFloaterBlacklist();
|
||||||
static void show();
|
static void show();
|
||||||
|
static void toggle();
|
||||||
|
static BOOL visible();
|
||||||
BOOL postBuild();
|
BOOL postBuild();
|
||||||
void refresh();
|
void refresh();
|
||||||
static LLFloaterBlacklist* getInstance() { return sInstance; };
|
static LLFloaterBlacklist* getInstance() { return sInstance; };
|
||||||
|
|||||||
1630
indra/newview/llfloaterbvhpreview.cpp
Normal file
1630
indra/newview/llfloaterbvhpreview.cpp
Normal file
File diff suppressed because it is too large
Load Diff
145
indra/newview/llfloaterbvhpreview.h
Normal file
145
indra/newview/llfloaterbvhpreview.h
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
/**
|
||||||
|
* @file llfloaterbvhpreview.h
|
||||||
|
* @brief LLFloaterBvhPreview class definition
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2004&license=viewergpl$
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004-2009, Linden Research, Inc.
|
||||||
|
*
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||||
|
* to you under the terms of the GNU General Public License, version 2.0
|
||||||
|
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||||
|
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||||
|
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||||
|
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||||
|
*
|
||||||
|
* 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, or
|
||||||
|
* online at
|
||||||
|
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||||
|
*
|
||||||
|
* By copying, modifying or distributing this software, you acknowledge
|
||||||
|
* that you have read and understood your obligations described above,
|
||||||
|
* and agree to abide by those obligations.
|
||||||
|
*
|
||||||
|
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||||
|
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||||
|
* COMPLETENESS OR PERFORMANCE.
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LL_LLFLOATERBVHPREVIEW_H
|
||||||
|
#define LL_LLFLOATERBVHPREVIEW_H
|
||||||
|
|
||||||
|
#include "llfloaternamedesc.h"
|
||||||
|
#include "lldynamictexture.h"
|
||||||
|
#include "llcharacter.h"
|
||||||
|
#include "llquaternion.h"
|
||||||
|
|
||||||
|
class LLVOAvatar;
|
||||||
|
class LLViewerJointMesh;
|
||||||
|
|
||||||
|
class LLPreviewAnimation : public LLViewerDynamicTexture
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
virtual ~LLPreviewAnimation();
|
||||||
|
|
||||||
|
public:
|
||||||
|
LLPreviewAnimation(S32 width, S32 height);
|
||||||
|
|
||||||
|
/*virtual*/ S8 getType() const ;
|
||||||
|
|
||||||
|
BOOL render();
|
||||||
|
void requestUpdate();
|
||||||
|
void rotate(F32 yaw_radians, F32 pitch_radians);
|
||||||
|
void zoom(F32 zoom_delta);
|
||||||
|
void setZoom(F32 zoom_amt);
|
||||||
|
void pan(F32 right, F32 up);
|
||||||
|
virtual BOOL needsUpdate() { return mNeedsUpdate; }
|
||||||
|
|
||||||
|
LLVOAvatar* getDummyAvatar() { return mDummyAvatar; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BOOL mNeedsUpdate;
|
||||||
|
F32 mCameraDistance;
|
||||||
|
F32 mCameraYaw;
|
||||||
|
F32 mCameraPitch;
|
||||||
|
F32 mCameraZoom;
|
||||||
|
LLVector3 mCameraOffset;
|
||||||
|
LLVector3 mCameraRelPos;
|
||||||
|
LLPointer<LLVOAvatar> mDummyAvatar;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LLFloaterBvhPreview : public LLFloaterNameDesc
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//<edit>
|
||||||
|
LLFloaterBvhPreview(const std::string& filename, void* item = NULL);
|
||||||
|
//<edit>
|
||||||
|
virtual ~LLFloaterBvhPreview();
|
||||||
|
|
||||||
|
BOOL postBuild();
|
||||||
|
|
||||||
|
BOOL handleMouseDown(S32 x, S32 y, MASK mask);
|
||||||
|
BOOL handleMouseUp(S32 x, S32 y, MASK mask);
|
||||||
|
BOOL handleHover(S32 x, S32 y, MASK mask);
|
||||||
|
BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
|
||||||
|
void onMouseCaptureLost();
|
||||||
|
|
||||||
|
void refresh();
|
||||||
|
|
||||||
|
static void onBtnPlay(void*);
|
||||||
|
static void onBtnStop(void*);
|
||||||
|
static void setUploadAmount(S32 amount) { sUploadAmount = amount; }
|
||||||
|
static void onSliderMove(LLUICtrl*, void*);
|
||||||
|
static void onCommitBaseAnim(LLUICtrl*, void*);
|
||||||
|
static void onCommitLoop(LLUICtrl*, void*);
|
||||||
|
static void onCommitLoopIn(LLUICtrl*, void*);
|
||||||
|
static void onCommitLoopOut(LLUICtrl*, void*);
|
||||||
|
static BOOL validateLoopIn(LLUICtrl*, void*);
|
||||||
|
static BOOL validateLoopOut(LLUICtrl*, void*);
|
||||||
|
static void onCommitName(LLUICtrl*, void*);
|
||||||
|
static void onCommitHandPose(LLUICtrl*, void*);
|
||||||
|
static void onCommitEmote(LLUICtrl*, void*);
|
||||||
|
static void onCommitPriority(LLUICtrl*, void*);
|
||||||
|
static void onCommitEaseIn(LLUICtrl*, void*);
|
||||||
|
static void onCommitEaseOut(LLUICtrl*, void*);
|
||||||
|
static BOOL validateEaseIn(LLUICtrl*, void*);
|
||||||
|
static BOOL validateEaseOut(LLUICtrl*, void*);
|
||||||
|
static void onBtnOK(void*);
|
||||||
|
static void onSaveComplete(const LLUUID& asset_uuid,
|
||||||
|
LLAssetType::EType type,
|
||||||
|
void* user_data,
|
||||||
|
S32 status, LLExtStat ext_status);
|
||||||
|
private:
|
||||||
|
void setAnimCallbacks() ;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void draw();
|
||||||
|
void resetMotion();
|
||||||
|
|
||||||
|
LLPointer< LLPreviewAnimation> mAnimPreview;
|
||||||
|
S32 mLastMouseX;
|
||||||
|
S32 mLastMouseY;
|
||||||
|
LLButton* mPlayButton;
|
||||||
|
LLButton* mStopButton;
|
||||||
|
LLRect mPreviewRect;
|
||||||
|
LLRectf mPreviewImageRect;
|
||||||
|
LLAssetID mMotionID;
|
||||||
|
LLTransactionID mTransactionID;
|
||||||
|
BOOL mEnabled;
|
||||||
|
BOOL mInWorld;
|
||||||
|
LLAnimPauseRequest mPauseRequest;
|
||||||
|
|
||||||
|
std::map<std::string, LLUUID> mIDList;
|
||||||
|
|
||||||
|
static S32 sUploadAmount;
|
||||||
|
|
||||||
|
//<edit>
|
||||||
|
void* mItem;
|
||||||
|
//</edit>
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LL_LLFLOATERBVHPREVIEW_H
|
||||||
@@ -189,6 +189,7 @@ LLFloaterCustomize::~LLFloaterCustomize()
|
|||||||
BOOL LLFloaterCustomize::postBuild()
|
BOOL LLFloaterCustomize::postBuild()
|
||||||
{
|
{
|
||||||
getChild<LLUICtrl>("Make Outfit")->setCommitCallback(boost::bind(&LLFloaterCustomize::onBtnMakeOutfit, this));
|
getChild<LLUICtrl>("Make Outfit")->setCommitCallback(boost::bind(&LLFloaterCustomize::onBtnMakeOutfit, this));
|
||||||
|
getChild<LLUICtrl>("Save Outfit")->setCommitCallback(boost::bind(&LLAppearanceMgr::updateBaseOutfit, LLAppearanceMgr::getInstance()));
|
||||||
getChild<LLUICtrl>("Ok")->setCommitCallback(boost::bind(&LLFloaterCustomize::onBtnOk, this));
|
getChild<LLUICtrl>("Ok")->setCommitCallback(boost::bind(&LLFloaterCustomize::onBtnOk, this));
|
||||||
getChild<LLUICtrl>("Cancel")->setCommitCallback(boost::bind(&LLFloater::onClickClose, this));
|
getChild<LLUICtrl>("Cancel")->setCommitCallback(boost::bind(&LLFloater::onClickClose, this));
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "llfloaterexploreanimations.h"
|
#include "llfloaterexploreanimations.h"
|
||||||
#include "lluictrlfactory.h"
|
#include "lluictrlfactory.h"
|
||||||
#include "llscrolllistctrl.h"
|
#include "llscrolllistctrl.h"
|
||||||
#include "llfloateranimpreview.h"
|
#include "llfloaterbvhpreview.h"
|
||||||
#include "llvoavatar.h"
|
#include "llvoavatar.h"
|
||||||
#include "lllocalinventory.h"
|
#include "lllocalinventory.h"
|
||||||
#include "llviewercamera.h"
|
#include "llviewercamera.h"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#define LL_LLFLOATEREXPLOREANIMATIONS_H
|
#define LL_LLFLOATEREXPLOREANIMATIONS_H
|
||||||
|
|
||||||
#include "llfloater.h"
|
#include "llfloater.h"
|
||||||
#include "llfloateranimpreview.h"
|
#include "llfloaterbvhpreview.h"
|
||||||
#include "llviewerwindow.h" // gViewerWindow
|
#include "llviewerwindow.h" // gViewerWindow
|
||||||
|
|
||||||
class LLAnimHistoryItem
|
class LLAnimHistoryItem
|
||||||
|
|||||||
@@ -68,6 +68,13 @@ void LLFloaterExploreSounds::toggle()
|
|||||||
else LLFloaterExploreSounds::sInstance = new LLFloaterExploreSounds();
|
else LLFloaterExploreSounds::sInstance = new LLFloaterExploreSounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL LLFloaterExploreSounds::visible()
|
||||||
|
{
|
||||||
|
if (LLFloaterExploreSounds::sInstance)
|
||||||
|
return TRUE;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
void LLFloaterExploreSounds::close(bool app_quitting)
|
void LLFloaterExploreSounds::close(bool app_quitting)
|
||||||
{
|
{
|
||||||
LLFloater::close(app_quitting);
|
LLFloater::close(app_quitting);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ public:
|
|||||||
static LLFloaterExploreSounds* sInstance;
|
static LLFloaterExploreSounds* sInstance;
|
||||||
|
|
||||||
static void toggle();
|
static void toggle();
|
||||||
|
static BOOL visible();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -238,25 +238,53 @@ void LLFloaterStats::buildStats()
|
|||||||
// Network statistics
|
// Network statistics
|
||||||
LLStatView *net_statviewp = stat_viewp->addStatView("network stat view", "Network", "OpenDebugStatNet", rect);
|
LLStatView *net_statviewp = stat_viewp->addStatView("network stat view", "Network", "OpenDebugStatNet", rect);
|
||||||
|
|
||||||
stat_barp = net_statviewp->addStat("Packets In", &(LLViewerStats::getInstance()->mPacketsInStat), "DebugStatModePacketsIn");
|
stat_barp = net_statviewp->addStat("UDP Packets In", &(LLViewerStats::getInstance()->mPacketsInStat), "DebugStatModePacketsIn");
|
||||||
stat_barp->setUnitLabel("/sec");
|
stat_barp->setUnitLabel("/sec");
|
||||||
|
|
||||||
stat_barp = net_statviewp->addStat("Packets Out", &(LLViewerStats::getInstance()->mPacketsOutStat), "DebugStatModePacketsOut");
|
stat_barp = net_statviewp->addStat("UDP Packets Out", &(LLViewerStats::getInstance()->mPacketsOutStat), "DebugStatModePacketsOut");
|
||||||
stat_barp->setUnitLabel("/sec");
|
stat_barp->setUnitLabel("/sec");
|
||||||
|
|
||||||
stat_barp = net_statviewp->addStat("Objects", &(LLViewerStats::getInstance()->mObjectKBitStat), "DebugStatModeObjects");
|
stat_barp = net_statviewp->addStat("HTTP Textures", &(LLViewerStats::getInstance()->mHTTPTextureKBitStat), "DebugStatModeHTTPTexture");
|
||||||
stat_barp->setUnitLabel(" kbps");
|
stat_barp->setUnitLabel(" kbps");
|
||||||
|
stat_barp->mMinBar = 0.f;
|
||||||
|
stat_barp->mMaxBar = gSavedSettings.getF32("HTTPThrottleBandwidth");
|
||||||
|
stat_barp->mMaxBar *= llclamp(2.0 - (stat_barp->mMaxBar - 400.f) / 3600.f, 1.0, 2.0); // Allow for overshoot (allow more for low bandwidth values).
|
||||||
|
stat_barp->mTickSpacing = 1.f;
|
||||||
|
while (stat_barp->mTickSpacing < stat_barp->mMaxBar / 8)
|
||||||
|
stat_barp->mTickSpacing *= 2.f;
|
||||||
|
stat_barp->mLabelSpacing = 2 * stat_barp->mTickSpacing;
|
||||||
|
stat_barp->mPerSec = FALSE;
|
||||||
|
stat_barp->mDisplayMean = FALSE;
|
||||||
|
|
||||||
stat_barp = net_statviewp->addStat("Texture", &(LLViewerStats::getInstance()->mTextureKBitStat), "DebugStatModeTexture");
|
stat_barp = net_statviewp->addStat("UDP Textures", &(LLViewerStats::getInstance()->mUDPTextureKBitStat), "DebugStatModeUDPTexture");
|
||||||
stat_barp->setUnitLabel(" kbps");
|
stat_barp->setUnitLabel(" kbps");
|
||||||
|
stat_barp->mMinBar = 0.f;
|
||||||
|
stat_barp->mMaxBar = 1024.f;
|
||||||
|
stat_barp->mTickSpacing = 128.f;
|
||||||
|
stat_barp->mLabelSpacing = 256.f;
|
||||||
|
|
||||||
stat_barp = net_statviewp->addStat("Asset", &(LLViewerStats::getInstance()->mAssetKBitStat), "DebugStatModeAsset");
|
stat_barp = net_statviewp->addStat("Objects (UDP)", &(LLViewerStats::getInstance()->mObjectKBitStat), "DebugStatModeObjects");
|
||||||
stat_barp->setUnitLabel(" kbps");
|
stat_barp->setUnitLabel(" kbps");
|
||||||
|
stat_barp->mMinBar = 0.f;
|
||||||
|
stat_barp->mMaxBar = 1024.f;
|
||||||
|
stat_barp->mTickSpacing = 128.f;
|
||||||
|
stat_barp->mLabelSpacing = 256.f;
|
||||||
|
|
||||||
stat_barp = net_statviewp->addStat("Layers", &(LLViewerStats::getInstance()->mLayersKBitStat), "DebugStatModeLayers");
|
stat_barp = net_statviewp->addStat("Assets (UDP)", &(LLViewerStats::getInstance()->mAssetKBitStat), "DebugStatModeAsset");
|
||||||
stat_barp->setUnitLabel(" kbps");
|
stat_barp->setUnitLabel(" kbps");
|
||||||
|
stat_barp->mMinBar = 0.f;
|
||||||
|
stat_barp->mMaxBar = 1024.f;
|
||||||
|
stat_barp->mTickSpacing = 128.f;
|
||||||
|
stat_barp->mLabelSpacing = 256.f;
|
||||||
|
|
||||||
stat_barp = net_statviewp->addStat("Actual In", &(LLViewerStats::getInstance()->mActualInKBitStat),
|
stat_barp = net_statviewp->addStat("Layers (UDP)", &(LLViewerStats::getInstance()->mLayersKBitStat), "DebugStatModeLayers");
|
||||||
|
stat_barp->setUnitLabel(" kbps");
|
||||||
|
stat_barp->mMinBar = 0.f;
|
||||||
|
stat_barp->mMaxBar = 1024.f;
|
||||||
|
stat_barp->mTickSpacing = 128.f;
|
||||||
|
stat_barp->mLabelSpacing = 256.f;
|
||||||
|
|
||||||
|
stat_barp = net_statviewp->addStat("Actual In (UDP)", &(LLViewerStats::getInstance()->mActualInKBitStat),
|
||||||
"DebugStatModeActualIn", TRUE, FALSE);
|
"DebugStatModeActualIn", TRUE, FALSE);
|
||||||
stat_barp->setUnitLabel(" kbps");
|
stat_barp->setUnitLabel(" kbps");
|
||||||
stat_barp->mMinBar = 0.f;
|
stat_barp->mMinBar = 0.f;
|
||||||
@@ -264,7 +292,7 @@ void LLFloaterStats::buildStats()
|
|||||||
stat_barp->mTickSpacing = 128.f;
|
stat_barp->mTickSpacing = 128.f;
|
||||||
stat_barp->mLabelSpacing = 256.f;
|
stat_barp->mLabelSpacing = 256.f;
|
||||||
|
|
||||||
stat_barp = net_statviewp->addStat("Actual Out", &(LLViewerStats::getInstance()->mActualOutKBitStat),
|
stat_barp = net_statviewp->addStat("Actual Out (UDP)", &(LLViewerStats::getInstance()->mActualOutKBitStat),
|
||||||
"DebugStatModeActualOut", TRUE, FALSE);
|
"DebugStatModeActualOut", TRUE, FALSE);
|
||||||
stat_barp->setUnitLabel(" kbps");
|
stat_barp->setUnitLabel(" kbps");
|
||||||
stat_barp->mMinBar = 0.f;
|
stat_barp->mMinBar = 0.f;
|
||||||
|
|||||||
@@ -31,11 +31,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "llviewerprecompiledheaders.h"
|
#include "llviewerprecompiledheaders.h"
|
||||||
|
|
||||||
#include "llagentwearables.h"
|
#include "llagentwearables.h"
|
||||||
|
#include "llappearancemgr.h"
|
||||||
|
#include "llfoldervieweventlistener.h"
|
||||||
#include "llimview.h"
|
#include "llimview.h"
|
||||||
#include "llinventoryfunctions.h"
|
|
||||||
#include "llinventorybridge.h"
|
#include "llinventorybridge.h"
|
||||||
#include "llinventoryclipboard.h"
|
#include "llinventoryclipboard.h"
|
||||||
|
#include "llinventoryfunctions.h"
|
||||||
#include "llinventorymodelbackgroundfetch.h"
|
#include "llinventorymodelbackgroundfetch.h"
|
||||||
#include "llinventorypanel.h"
|
#include "llinventorypanel.h"
|
||||||
#include "llmakeoutfitdialog.h"
|
#include "llmakeoutfitdialog.h"
|
||||||
@@ -43,7 +46,6 @@
|
|||||||
#include "llpanelmaininventory.h"
|
#include "llpanelmaininventory.h"
|
||||||
#include "llpanelobjectinventory.h"
|
#include "llpanelobjectinventory.h"
|
||||||
#include "llpreview.h" // For LLMultiPreview
|
#include "llpreview.h" // For LLMultiPreview
|
||||||
#include "llfoldervieweventlistener.h"
|
|
||||||
#include "lltrans.h"
|
#include "lltrans.h"
|
||||||
#include "llvoavatarself.h"
|
#include "llvoavatarself.h"
|
||||||
|
|
||||||
@@ -317,7 +319,7 @@ void do_create(LLInventoryModel *model, LLInventoryPanel *ptr, std::string type,
|
|||||||
LLInventoryType::IT_GESTURE,
|
LLInventoryType::IT_GESTURE,
|
||||||
PERM_ALL);
|
PERM_ALL);
|
||||||
}
|
}
|
||||||
else if ("outfit" == type)
|
else if ("outfit" == type || ("update outfit" == type && !LLAppearanceMgr::getInstance()->updateBaseOutfit())) // If updateBaseOutfit fails, prompt to make a new outfit
|
||||||
{
|
{
|
||||||
new LLMakeOutfitDialog(false);
|
new LLMakeOutfitDialog(false);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include "llviewermessage.h"
|
#include "llviewermessage.h"
|
||||||
#include "llviewerregion.h"
|
#include "llviewerregion.h"
|
||||||
#include "llviewerwindow.h"
|
#include "llviewerwindow.h"
|
||||||
|
#include "hippogridmanager.h"
|
||||||
|
|
||||||
class AIHTTPTimeoutPolicy;
|
class AIHTTPTimeoutPolicy;
|
||||||
extern AIHTTPTimeoutPolicy inventoryModelFetchDescendentsResponder_timeout;
|
extern AIHTTPTimeoutPolicy inventoryModelFetchDescendentsResponder_timeout;
|
||||||
@@ -115,7 +116,6 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
|
|||||||
{ // it's a folder, do a bulk fetch
|
{ // it's a folder, do a bulk fetch
|
||||||
LL_DEBUGS("InventoryFetch") << "Start fetching category: " << id << ", recursive: " << recursive << LL_ENDL;
|
LL_DEBUGS("InventoryFetch") << "Start fetching category: " << id << ", recursive: " << recursive << LL_ENDL;
|
||||||
|
|
||||||
mBackgroundFetchActive = TRUE;
|
|
||||||
mFolderFetchActive = true;
|
mFolderFetchActive = true;
|
||||||
if (id.isNull())
|
if (id.isNull())
|
||||||
{
|
{
|
||||||
@@ -124,12 +124,14 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
|
|||||||
mRecursiveInventoryFetchStarted |= recursive;
|
mRecursiveInventoryFetchStarted |= recursive;
|
||||||
mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive));
|
mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive));
|
||||||
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
|
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
|
||||||
|
mBackgroundFetchActive = TRUE;
|
||||||
}
|
}
|
||||||
if (!mRecursiveLibraryFetchStarted)
|
if (!mRecursiveLibraryFetchStarted)
|
||||||
{
|
{
|
||||||
mRecursiveLibraryFetchStarted |= recursive;
|
mRecursiveLibraryFetchStarted |= recursive;
|
||||||
mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive));
|
mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive));
|
||||||
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
|
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
|
||||||
|
mBackgroundFetchActive = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -139,6 +141,7 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
|
|||||||
{
|
{
|
||||||
mFetchQueue.push_front(FetchQueueInfo(id, recursive));
|
mFetchQueue.push_front(FetchQueueInfo(id, recursive));
|
||||||
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
|
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
|
||||||
|
mBackgroundFetchActive = TRUE;
|
||||||
}
|
}
|
||||||
if (id == gInventory.getLibraryRootFolderID())
|
if (id == gInventory.getLibraryRootFolderID())
|
||||||
{
|
{
|
||||||
@@ -178,6 +181,11 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched()
|
|||||||
mAllFoldersFetched = TRUE;
|
mAllFoldersFetched = TRUE;
|
||||||
}
|
}
|
||||||
mFolderFetchActive = false;
|
mFolderFetchActive = false;
|
||||||
|
if (mBackgroundFetchActive)
|
||||||
|
{
|
||||||
|
gIdleCallbacks.deleteFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
|
||||||
|
mBackgroundFetchActive = FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *)
|
void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *)
|
||||||
@@ -190,14 +198,27 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
|
|||||||
LLViewerRegion* region = gAgent.getRegion();
|
LLViewerRegion* region = gAgent.getRegion();
|
||||||
if (mBackgroundFetchActive && region && region->capabilitiesReceived())
|
if (mBackgroundFetchActive && region && region->capabilitiesReceived())
|
||||||
{
|
{
|
||||||
// If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
|
if (gSavedSettings.getBOOL("UseHTTPInventory"))
|
||||||
std::string url = region->getCapability("FetchInventory2");
|
|
||||||
if (gSavedSettings.getBOOL("UseHTTPInventory") && !url.empty())
|
|
||||||
{
|
{
|
||||||
bulkFetch();
|
// If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
|
||||||
return;
|
std::string url = region->getCapability("FetchInventory2");
|
||||||
}
|
if (!url.empty())
|
||||||
|
{
|
||||||
|
if (!mPerServicePtr)
|
||||||
|
{
|
||||||
|
// One time initialization needed for bulkFetch().
|
||||||
|
std::string servicename = AIPerService::extract_canonical_servicename(url);
|
||||||
|
if (!servicename.empty())
|
||||||
|
{
|
||||||
|
llinfos << "Initialized service name for bulk inventory fetching with \"" << servicename << "\"." << llendl;
|
||||||
|
mPerServicePtr = AIPerService::instance(servicename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bulkFetch();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
//--------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------
|
||||||
// DEPRECATED OLD CODE
|
// DEPRECATED OLD CODE
|
||||||
@@ -207,10 +228,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
|
|||||||
if (mFetchQueue.empty())
|
if (mFetchQueue.empty())
|
||||||
{
|
{
|
||||||
llinfos << "Inventory fetch completed" << llendl;
|
llinfos << "Inventory fetch completed" << llendl;
|
||||||
|
|
||||||
setAllFoldersFetched();
|
setAllFoldersFetched();
|
||||||
mBackgroundFetchActive = false;
|
|
||||||
mFolderFetchActive = false;
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -395,7 +413,6 @@ class LLInventoryModelFetchDescendentsResponder : public LLHTTPClient::Responder
|
|||||||
mRequestSD(request_sd),
|
mRequestSD(request_sd),
|
||||||
mRecursiveCatUUIDs(recursive_cats)
|
mRecursiveCatUUIDs(recursive_cats)
|
||||||
{};
|
{};
|
||||||
//LLInventoryModelFetchDescendentsResponder() {};
|
|
||||||
/*virtual*/ void result(const LLSD& content);
|
/*virtual*/ void result(const LLSD& content);
|
||||||
/*virtual*/ void error(U32 status, const std::string& reason);
|
/*virtual*/ void error(U32 status, const std::string& reason);
|
||||||
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return inventoryModelFetchDescendentsResponder_timeout; }
|
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return inventoryModelFetchDescendentsResponder_timeout; }
|
||||||
@@ -575,28 +592,22 @@ BOOL LLInventoryModelFetchDescendentsResponder::getIsRecursive(const LLUUID& cat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Bundle up a bunch of requests to send all at once.
|
// Bundle up a bunch of requests to send all at once.
|
||||||
// static
|
|
||||||
void LLInventoryModelBackgroundFetch::bulkFetch()
|
void LLInventoryModelBackgroundFetch::bulkFetch()
|
||||||
{
|
{
|
||||||
//Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped.
|
//Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped.
|
||||||
//If there are items in mFetchQueue, we want to check the time since the last bulkFetch was
|
//If there are items in mFetchQueue, we want to check the time since the last bulkFetch was
|
||||||
//sent. If it exceeds our retry time, go ahead and fire off another batch.
|
//sent. If it exceeds our retry time, go ahead and fire off another batch.
|
||||||
LLViewerRegion* region = gAgent.getRegion();
|
LLViewerRegion* region = gAgent.getRegion();
|
||||||
if (!region) return;
|
if (gDisconnected || !region) return;
|
||||||
|
|
||||||
S16 max_concurrent_fetches=8;
|
if (!AIPerService::wantsMoreHTTPRequestsFor(mPerServicePtr))
|
||||||
F32 new_min_time = 0.5f; //HACK! Clean this up when old code goes away entirely.
|
|
||||||
if (mMinTimeBetweenFetches < new_min_time)
|
|
||||||
{
|
{
|
||||||
mMinTimeBetweenFetches=new_min_time; //HACK! See above.
|
return; // Wait.
|
||||||
}
|
}
|
||||||
|
// If AIPerService::wantsMoreHTTPRequestsFor returns true, then it approved ONE request.
|
||||||
if (gDisconnected ||
|
// The code below might fire off zero, one or even more than one requests however!
|
||||||
(mFetchCount > max_concurrent_fetches) ||
|
// This object keeps track of that.
|
||||||
(mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches))
|
AIPerService::Approvement approvement(mPerServicePtr);
|
||||||
{
|
|
||||||
return; // just bail if we are disconnected
|
|
||||||
}
|
|
||||||
|
|
||||||
U32 item_count=0;
|
U32 item_count=0;
|
||||||
U32 folder_count=0;
|
U32 folder_count=0;
|
||||||
@@ -690,14 +701,16 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
|
|||||||
if (folder_request_body["folders"].size())
|
if (folder_request_body["folders"].size())
|
||||||
{
|
{
|
||||||
LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats);
|
LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats);
|
||||||
LLHTTPClient::post(url, folder_request_body, fetcher);
|
LLHTTPClient::post_nb(url, folder_request_body, fetcher);
|
||||||
|
approvement.honored();
|
||||||
}
|
}
|
||||||
if (folder_request_body_lib["folders"].size())
|
if (folder_request_body_lib["folders"].size())
|
||||||
{
|
{
|
||||||
std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2");
|
std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2");
|
||||||
|
|
||||||
LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats);
|
LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats);
|
||||||
LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher);
|
LLHTTPClient::post_nb(url_lib, folder_request_body_lib, fetcher);
|
||||||
|
approvement.honored();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (item_count)
|
if (item_count)
|
||||||
@@ -708,26 +721,16 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
|
|||||||
{
|
{
|
||||||
mFetchCount++;
|
mFetchCount++;
|
||||||
url = region->getCapability("FetchInventory2");
|
url = region->getCapability("FetchInventory2");
|
||||||
|
llassert(!url.empty());
|
||||||
if (!url.empty())
|
if (!url.empty())
|
||||||
{
|
{
|
||||||
LLSD body;
|
LLSD body;
|
||||||
body["agent_id"] = gAgent.getID();
|
body["agent_id"] = gAgent.getID();
|
||||||
body["items"] = item_request_body;
|
body["items"] = item_request_body;
|
||||||
|
|
||||||
LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body));
|
LLHTTPClient::post_nb(url, body, new LLInventoryModelFetchItemResponder(body));
|
||||||
|
approvement.honored();
|
||||||
}
|
}
|
||||||
//else
|
|
||||||
//{
|
|
||||||
// LLMessageSystem* msg = gMessageSystem;
|
|
||||||
// msg->newMessage("FetchInventory");
|
|
||||||
// msg->nextBlock("AgentData");
|
|
||||||
// msg->addUUID("AgentID", gAgent.getID());
|
|
||||||
// msg->addUUID("SessionID", gAgent.getSessionID());
|
|
||||||
// msg->nextBlock("InventoryData");
|
|
||||||
// msg->addUUID("OwnerID", mPermissions.getOwner());
|
|
||||||
// msg->addUUID("ItemID", mUUID);
|
|
||||||
// gAgent.sendReliableMessage();
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item_request_body_lib.size())
|
if (item_request_body_lib.size())
|
||||||
@@ -735,21 +738,23 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
|
|||||||
mFetchCount++;
|
mFetchCount++;
|
||||||
|
|
||||||
url = region->getCapability("FetchLib2");
|
url = region->getCapability("FetchLib2");
|
||||||
|
llassert(!url.empty());
|
||||||
if (!url.empty())
|
if (!url.empty())
|
||||||
{
|
{
|
||||||
LLSD body;
|
LLSD body;
|
||||||
body["agent_id"] = gAgent.getID();
|
body["agent_id"] = gAgent.getID();
|
||||||
body["items"] = item_request_body_lib;
|
body["items"] = item_request_body_lib;
|
||||||
|
|
||||||
LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body));
|
LLHTTPClient::post_nb(url, body, new LLInventoryModelFetchItemResponder(body));
|
||||||
|
approvement.honored();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mFetchTimer.reset();
|
mFetchTimer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isBulkFetchProcessingComplete())
|
else if (isBulkFetchProcessingComplete())
|
||||||
{
|
{
|
||||||
|
llinfos << "Inventory fetch completed" << llendl;
|
||||||
setAllFoldersFetched();
|
setAllFoldersFetched();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include "llsingleton.h"
|
#include "llsingleton.h"
|
||||||
#include "lluuid.h"
|
#include "lluuid.h"
|
||||||
|
#include "aicurlperservice.h"
|
||||||
|
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// Class LLInventoryModelBackgroundFetch
|
// Class LLInventoryModelBackgroundFetch
|
||||||
@@ -75,12 +76,14 @@ private:
|
|||||||
BOOL mRecursiveLibraryFetchStarted;
|
BOOL mRecursiveLibraryFetchStarted;
|
||||||
BOOL mAllFoldersFetched;
|
BOOL mAllFoldersFetched;
|
||||||
|
|
||||||
BOOL mBackgroundFetchActive;
|
BOOL mBackgroundFetchActive; // TRUE if LLInventoryModelBackgroundFetch::backgroundFetchCB is being called from idle().
|
||||||
bool mFolderFetchActive;
|
bool mFolderFetchActive;
|
||||||
S16 mFetchCount;
|
S16 mFetchCount;
|
||||||
BOOL mTimelyFetchPending;
|
BOOL mTimelyFetchPending;
|
||||||
S32 mNumFetchRetries;
|
S32 mNumFetchRetries;
|
||||||
|
|
||||||
|
AIPerServicePtr mPerServicePtr; // Pointer to the AIPerService corresponding to the FetchInventory2 capability.
|
||||||
|
|
||||||
LLFrameTimer mFetchTimer;
|
LLFrameTimer mFetchTimer;
|
||||||
F32 mMinTimeBetweenFetches;
|
F32 mMinTimeBetweenFetches;
|
||||||
F32 mMaxTimeBetweenFetches;
|
F32 mMaxTimeBetweenFetches;
|
||||||
|
|||||||
@@ -1329,9 +1329,10 @@ void LLMeshUploadThread::preStart()
|
|||||||
}
|
}
|
||||||
|
|
||||||
AIMeshUpload::AIMeshUpload(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, std::string const& upload_url, bool do_upload,
|
AIMeshUpload::AIMeshUpload(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, std::string const& upload_url, bool do_upload,
|
||||||
LLHandle<LLWholeModelFeeObserver> const& fee_observer, LLHandle<LLWholeModelUploadObserver> const& upload_observer) : mWholeModelUploadURL(upload_url)
|
LLHandle<LLWholeModelFeeObserver> const& fee_observer, LLHandle<LLWholeModelUploadObserver> const& upload_observer) :
|
||||||
|
mMeshUpload(new AIStateMachineThread<LLMeshUploadThread>), mWholeModelUploadURL(upload_url)
|
||||||
{
|
{
|
||||||
mMeshUpload->init(data, scale, upload_textures, upload_skin, upload_joints, do_upload, fee_observer, upload_observer);
|
mMeshUpload->thread_impl().init(data, scale, upload_textures, upload_skin, upload_joints, do_upload, fee_observer, upload_observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
char const* AIMeshUpload::state_str_impl(state_type run_state) const
|
char const* AIMeshUpload::state_str_impl(state_type run_state) const
|
||||||
@@ -1347,7 +1348,7 @@ char const* AIMeshUpload::state_str_impl(state_type run_state) const
|
|||||||
|
|
||||||
void AIMeshUpload::initialize_impl()
|
void AIMeshUpload::initialize_impl()
|
||||||
{
|
{
|
||||||
mMeshUpload->preStart();
|
mMeshUpload->thread_impl().preStart();
|
||||||
set_state(AIMeshUpload_start);
|
set_state(AIMeshUpload_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1356,11 +1357,11 @@ void AIMeshUpload::multiplex_impl(state_type run_state)
|
|||||||
switch (run_state)
|
switch (run_state)
|
||||||
{
|
{
|
||||||
case AIMeshUpload_start:
|
case AIMeshUpload_start:
|
||||||
mMeshUpload.run(this, AIMeshUpload_threadFinished);
|
mMeshUpload->run(this, AIMeshUpload_threadFinished);
|
||||||
idle(); // Wait till the thread finished.
|
idle(); // Wait till the thread finished.
|
||||||
break;
|
break;
|
||||||
case AIMeshUpload_threadFinished:
|
case AIMeshUpload_threadFinished:
|
||||||
mMeshUpload->postRequest(mWholeModelUploadURL, this);
|
mMeshUpload->thread_impl().postRequest(mWholeModelUploadURL, this);
|
||||||
idle(); // Wait till the responder finished.
|
idle(); // Wait till the responder finished.
|
||||||
break;
|
break;
|
||||||
case AIMeshUpload_responderFinished:
|
case AIMeshUpload_responderFinished:
|
||||||
@@ -2508,7 +2509,7 @@ void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params,
|
|||||||
}
|
}
|
||||||
|
|
||||||
S32 LLMeshRepository::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
|
S32 LLMeshRepository::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
|
||||||
{
|
{
|
||||||
return mThread->getActualMeshLOD(mesh_params, lod);
|
return mThread->getActualMeshLOD(mesh_params, lod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include "lluuid.h"
|
#include "lluuid.h"
|
||||||
#include "llviewertexture.h"
|
#include "llviewertexture.h"
|
||||||
#include "llvolume.h"
|
#include "llvolume.h"
|
||||||
|
#include "sguuidhash.h"
|
||||||
|
|
||||||
#define LLCONVEXDECOMPINTER_STATIC 1
|
#define LLCONVEXDECOMPINTER_STATIC 1
|
||||||
|
|
||||||
@@ -433,7 +434,7 @@ enum AIMeshUpload_state_type {
|
|||||||
class AIMeshUpload : public AIStateMachine
|
class AIMeshUpload : public AIStateMachine
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
AIStateMachineThread<LLMeshUploadThread> mMeshUpload;
|
LLPointer<AIStateMachineThread<LLMeshUploadThread> > mMeshUpload;
|
||||||
std::string mWholeModelUploadURL;
|
std::string mWholeModelUploadURL;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -505,8 +506,8 @@ public:
|
|||||||
|
|
||||||
typedef std::map<LLVolumeParams, std::set<LLUUID> > mesh_load_map;
|
typedef std::map<LLVolumeParams, std::set<LLUUID> > mesh_load_map;
|
||||||
mesh_load_map mLoadingMeshes[4];
|
mesh_load_map mLoadingMeshes[4];
|
||||||
|
|
||||||
typedef std::map<LLUUID, LLMeshSkinInfo> skin_map;
|
typedef boost::unordered_map<LLUUID, LLMeshSkinInfo> skin_map;
|
||||||
skin_map mSkinMap;
|
skin_map mSkinMap;
|
||||||
|
|
||||||
typedef std::map<LLUUID, LLModel::Decomposition*> decomposition_map;
|
typedef std::map<LLUUID, LLModel::Decomposition*> decomposition_map;
|
||||||
|
|||||||
@@ -885,7 +885,7 @@ void LLPanelDisplay::apply()
|
|||||||
|
|
||||||
void LLPanelDisplay::onChangeQuality(LLUICtrl* caller)
|
void LLPanelDisplay::onChangeQuality(LLUICtrl* caller)
|
||||||
{
|
{
|
||||||
LLSliderCtrl* sldr = static_cast<LLSliderCtrl*>(caller);
|
LLSlider* sldr = dynamic_cast<LLSlider*>(caller);
|
||||||
|
|
||||||
if(sldr == NULL)
|
if(sldr == NULL)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -491,7 +491,7 @@ void LLPanelFace::sendTextureInfo()
|
|||||||
return (object->mDrawable) ? object->mDrawable->getFace(te): NULL;
|
return (object->mDrawable) ? object->mDrawable->getFace(te): NULL;
|
||||||
}
|
}
|
||||||
} get_last_face_func;
|
} get_last_face_func;
|
||||||
LLFace* last_face;
|
LLFace* last_face(NULL);
|
||||||
LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_last_face_func, last_face);
|
LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_last_face_func, last_face);
|
||||||
|
|
||||||
LLPanelFaceSetAlignedTEFunctor setfunc(this, last_face);
|
LLPanelFaceSetAlignedTEFunctor setfunc(this, last_face);
|
||||||
@@ -654,7 +654,7 @@ void LLPanelFace::getState()
|
|||||||
return (object->mDrawable) ? object->mDrawable->getFace(te): NULL;
|
return (object->mDrawable) ? object->mDrawable->getFace(te): NULL;
|
||||||
}
|
}
|
||||||
} get_te_face_func;
|
} get_te_face_func;
|
||||||
LLFace* last_face;
|
LLFace* last_face(NULL);
|
||||||
LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_te_face_func, last_face);
|
LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_te_face_func, last_face);
|
||||||
LLPanelFaceGetIsAlignedTEFunctor get_is_aligend_func(last_face);
|
LLPanelFaceGetIsAlignedTEFunctor get_is_aligend_func(last_face);
|
||||||
// this will determine if the texture param controls are tentative:
|
// this will determine if the texture param controls are tentative:
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
#include "llnotificationsutil.h"
|
#include "llnotificationsutil.h"
|
||||||
#include "llviewercontrol.h"
|
#include "llviewercontrol.h"
|
||||||
#include "llviewerwindow.h"
|
#include "llviewerwindow.h"
|
||||||
|
#include "hippogridmanager.h"
|
||||||
|
|
||||||
#include "llproxy.h"
|
#include "llproxy.h"
|
||||||
|
|
||||||
@@ -74,6 +75,14 @@ BOOL LLPanelNetwork::postBuild()
|
|||||||
childSetValue("connection_port_enabled", gSavedSettings.getBOOL("ConnectionPortEnabled"));
|
childSetValue("connection_port_enabled", gSavedSettings.getBOOL("ConnectionPortEnabled"));
|
||||||
childSetValue("connection_port", (F32)gSavedSettings.getU32("ConnectionPort"));
|
childSetValue("connection_port", (F32)gSavedSettings.getU32("ConnectionPort"));
|
||||||
|
|
||||||
|
// If in Avination, hide the texture bandwidth slider, Avination throttles server-side
|
||||||
|
if (gHippoGridManager->getConnectedGrid()->isAvination())
|
||||||
|
{
|
||||||
|
childSetVisible("text_box4", FALSE);
|
||||||
|
childSetVisible("tex_bandwidth", FALSE);
|
||||||
|
childSetVisible("text_box3", FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
// Socks 5 proxy settings, commit callbacks
|
// Socks 5 proxy settings, commit callbacks
|
||||||
childSetCommitCallback("socks5_proxy_enabled", onCommitSocks5ProxyEnabled, this);
|
childSetCommitCallback("socks5_proxy_enabled", onCommitSocks5ProxyEnabled, this);
|
||||||
childSetCommitCallback("socks5_auth", onSocksAuthChanged, this);
|
childSetCommitCallback("socks5_auth", onSocksAuthChanged, this);
|
||||||
|
|||||||
@@ -772,7 +772,7 @@ void LLPanelPermissions::refresh()
|
|||||||
{
|
{
|
||||||
childSetEnabled("checkbox allow export", false);
|
childSetEnabled("checkbox allow export", false);
|
||||||
if (!gHippoGridManager->getCurrentGrid()->isSecondLife())
|
if (!gHippoGridManager->getCurrentGrid()->isSecondLife())
|
||||||
childSetVisible("checkbox allow export", false);
|
childSetVisible("checkbox allow export", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_change_sale_ability && (owner_mask_on & PERM_TRANSFER))
|
if (has_change_sale_ability && (owner_mask_on & PERM_TRANSFER))
|
||||||
|
|||||||
@@ -212,6 +212,7 @@
|
|||||||
#include "llinventorybridge.h"
|
#include "llinventorybridge.h"
|
||||||
#include "llappearancemgr.h"
|
#include "llappearancemgr.h"
|
||||||
#include "jcfloaterareasearch.h"
|
#include "jcfloaterareasearch.h"
|
||||||
|
#include "generichandlers.h"
|
||||||
|
|
||||||
// <edit>
|
// <edit>
|
||||||
#include "llpanellogin.h"
|
#include "llpanellogin.h"
|
||||||
@@ -843,6 +844,8 @@ bool idle_startup()
|
|||||||
|
|
||||||
// *NOTE: This is where gMuteList used to get allocated before becoming LLMuteList::getInstance().
|
// *NOTE: This is where gMuteList used to get allocated before becoming LLMuteList::getInstance().
|
||||||
|
|
||||||
|
gGenericHandlers = new GenericHandlers();
|
||||||
|
|
||||||
// Initialize UI
|
// Initialize UI
|
||||||
if (!gNoRender)
|
if (!gNoRender)
|
||||||
{
|
{
|
||||||
@@ -999,11 +1002,14 @@ bool idle_startup()
|
|||||||
if(!gHippoGridManager->getConnectedGrid()->isSecondLife())
|
if(!gHippoGridManager->getConnectedGrid()->isSecondLife())
|
||||||
{
|
{
|
||||||
LLTrans::setDefaultArg("[CURRENCY]",gHippoGridManager->getConnectedGrid()->getCurrencySymbol()); //replace [CURRENCY] with OS$, not L$ for instance.
|
LLTrans::setDefaultArg("[CURRENCY]",gHippoGridManager->getConnectedGrid()->getCurrencySymbol()); //replace [CURRENCY] with OS$, not L$ for instance.
|
||||||
|
LLTrans::setDefaultArg("[CURRENCY_TEXT]",gHippoGridManager->getConnectedGrid()->getCurrencyText()); //replace [CURRENCYTEXT] with OS DOllars, not Linden Dollars for instance.
|
||||||
LLTrans::setDefaultArg("[SECOND_LIFE]", gHippoGridManager->getConnectedGrid()->getGridName());
|
LLTrans::setDefaultArg("[SECOND_LIFE]", gHippoGridManager->getConnectedGrid()->getGridName());
|
||||||
LLTrans::setDefaultArg("[SECOND_LIFE_GRID]", gHippoGridManager->getConnectedGrid()->getGridName() + " Grid");
|
LLTrans::setDefaultArg("[SECOND_LIFE_GRID]", gHippoGridManager->getConnectedGrid()->getGridName() + " Grid");
|
||||||
LLTrans::setDefaultArg("[GRID_OWNER]", gHippoGridManager->getConnectedGrid()->getGridOwner());
|
LLTrans::setDefaultArg("[GRID_OWNER]", gHippoGridManager->getConnectedGrid()->getGridOwner());
|
||||||
LLScriptEdCore::parseFunctions("lsl_functions_os.xml"); //Singu Note: This appends to the base functions parsed from lsl_functions_sl.xml
|
LLScriptEdCore::parseFunctions("lsl_functions_os.xml"); //Singu Note: This appends to the base functions parsed from lsl_functions_sl.xml
|
||||||
}
|
}
|
||||||
|
// Avination doesn't want the viewer to do bandwidth throttling (it is done serverside, taking UDP into account too).
|
||||||
|
AIPerService::setNoHTTPBandwidthThrottling(gHippoGridManager->getConnectedGrid()->isAvination());
|
||||||
|
|
||||||
// create necessary directories
|
// create necessary directories
|
||||||
// *FIX: these mkdir's should error check
|
// *FIX: these mkdir's should error check
|
||||||
@@ -4375,6 +4381,8 @@ bool process_login_success_response(std::string& password)
|
|||||||
if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setSearchUrl(tmp);
|
if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setSearchUrl(tmp);
|
||||||
tmp = response["currency"].asString();
|
tmp = response["currency"].asString();
|
||||||
if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setCurrencySymbol(tmp);
|
if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setCurrencySymbol(tmp);
|
||||||
|
tmp = response["currency_text"].asString();
|
||||||
|
if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setCurrencyText(tmp);
|
||||||
tmp = response["real_currency"].asString();
|
tmp = response["real_currency"].asString();
|
||||||
if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setRealCurrencySymbol(tmp);
|
if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setRealCurrencySymbol(tmp);
|
||||||
tmp = response["directory_fee"].asString();
|
tmp = response["directory_fee"].asString();
|
||||||
@@ -4385,6 +4393,8 @@ bool process_login_success_response(std::string& password)
|
|||||||
if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setMaxAgentGroups(atoi(tmp.c_str()));
|
if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setMaxAgentGroups(atoi(tmp.c_str()));
|
||||||
tmp = response["VoiceConnector"].asString();
|
tmp = response["VoiceConnector"].asString();
|
||||||
if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setVoiceConnector(tmp);
|
if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setVoiceConnector(tmp);
|
||||||
|
tmp = response["upc_supported"].asString();
|
||||||
|
if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setUPCSupported(true);
|
||||||
gHippoGridManager->saveFile();
|
gHippoGridManager->saveFile();
|
||||||
gHippoLimits->setLimits();
|
gHippoLimits->setLimits();
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,7 @@
|
|||||||
#include "llworld.h"
|
#include "llworld.h"
|
||||||
#include "llstatgraph.h"
|
#include "llstatgraph.h"
|
||||||
#include "llviewercontrol.h"
|
#include "llviewercontrol.h"
|
||||||
|
#include "llviewergenericmessage.h"
|
||||||
#include "llviewermenu.h" // for gMenuBarView
|
#include "llviewermenu.h" // for gMenuBarView
|
||||||
#include "llviewerparcelmgr.h"
|
#include "llviewerparcelmgr.h"
|
||||||
#include "llviewerthrottle.h"
|
#include "llviewerthrottle.h"
|
||||||
@@ -137,9 +138,27 @@ std::vector<std::string> LLStatusBar::sDays;
|
|||||||
std::vector<std::string> LLStatusBar::sMonths;
|
std::vector<std::string> LLStatusBar::sMonths;
|
||||||
const U32 LLStatusBar::MAX_DATE_STRING_LENGTH = 2000;
|
const U32 LLStatusBar::MAX_DATE_STRING_LENGTH = 2000;
|
||||||
|
|
||||||
|
class LLDispatchUPCBalance : public LLDispatchHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual bool operator()(
|
||||||
|
const LLDispatcher* dispatcher,
|
||||||
|
const std::string& key,
|
||||||
|
const LLUUID& invoice,
|
||||||
|
const sparam_t& strings)
|
||||||
|
{
|
||||||
|
S32 upc = atoi(strings[0].c_str());
|
||||||
|
gStatusBar->setUPC(upc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static LLDispatchUPCBalance sDispatchUPCBalance;
|
||||||
|
|
||||||
LLStatusBar::LLStatusBar(const std::string& name, const LLRect& rect)
|
LLStatusBar::LLStatusBar(const std::string& name, const LLRect& rect)
|
||||||
: LLPanel(name, LLRect(), FALSE), // not mouse opaque
|
: LLPanel(name, LLRect(), FALSE), // not mouse opaque
|
||||||
mBalance(0),
|
mBalance(0),
|
||||||
|
mUPC(0),
|
||||||
mHealth(100),
|
mHealth(100),
|
||||||
mSquareMetersCredit(0),
|
mSquareMetersCredit(0),
|
||||||
mSquareMetersCommitted(0),
|
mSquareMetersCommitted(0),
|
||||||
@@ -147,6 +166,11 @@ mRegionCrossingSlot(),
|
|||||||
mNavMeshSlot(),
|
mNavMeshSlot(),
|
||||||
mIsNavMeshDirty(false)
|
mIsNavMeshDirty(false)
|
||||||
{
|
{
|
||||||
|
mUPCSupported = gHippoGridManager->getConnectedGrid()->getUPCSupported();
|
||||||
|
|
||||||
|
if (mUPCSupported)
|
||||||
|
gGenericDispatcher.addHandler("upcbalance", &sDispatchUPCBalance);
|
||||||
|
|
||||||
// status bar can possible overlay menus?
|
// status bar can possible overlay menus?
|
||||||
setMouseOpaque(FALSE);
|
setMouseOpaque(FALSE);
|
||||||
setIsChrome(TRUE);
|
setIsChrome(TRUE);
|
||||||
@@ -168,10 +192,14 @@ mIsNavMeshDirty(false)
|
|||||||
|
|
||||||
mTextParcelName = getChild<LLTextBox>("ParcelNameText" );
|
mTextParcelName = getChild<LLTextBox>("ParcelNameText" );
|
||||||
mTextBalance = getChild<LLTextBox>("BalanceText" );
|
mTextBalance = getChild<LLTextBox>("BalanceText" );
|
||||||
|
mTextUPC = getChild<LLTextBox>("UPCText" );
|
||||||
|
|
||||||
mTextHealth = getChild<LLTextBox>("HealthText" );
|
mTextHealth = getChild<LLTextBox>("HealthText" );
|
||||||
mTextTime = getChild<LLTextBox>("TimeText" );
|
mTextTime = getChild<LLTextBox>("TimeText" );
|
||||||
|
|
||||||
|
if (!mUPCSupported)
|
||||||
|
mTextUPC->setVisible(false);
|
||||||
|
|
||||||
childSetAction("scriptout", onClickScriptDebug, this);
|
childSetAction("scriptout", onClickScriptDebug, this);
|
||||||
childSetAction("health", onClickHealth, this);
|
childSetAction("health", onClickHealth, this);
|
||||||
childSetAction("no_fly", onClickFly, this);
|
childSetAction("no_fly", onClickFly, this);
|
||||||
@@ -595,6 +623,14 @@ void LLStatusBar::refresh()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set rects of money, buy money, time
|
// Set rects of money, buy money, time
|
||||||
|
if (mUPCSupported)
|
||||||
|
{
|
||||||
|
childGetRect("UPCText", r);
|
||||||
|
r.translate( new_right - r.mRight, 0);
|
||||||
|
childSetRect("UPCText", r);
|
||||||
|
new_right -= r.getWidth() - 18;
|
||||||
|
}
|
||||||
|
|
||||||
childGetRect("BalanceText", r);
|
childGetRect("BalanceText", r);
|
||||||
r.translate( new_right - r.mRight, 0);
|
r.translate( new_right - r.mRight, 0);
|
||||||
childSetRect("BalanceText", r);
|
childSetRect("BalanceText", r);
|
||||||
@@ -631,6 +667,8 @@ void LLStatusBar::refresh()
|
|||||||
void LLStatusBar::setVisibleForMouselook(bool visible)
|
void LLStatusBar::setVisibleForMouselook(bool visible)
|
||||||
{
|
{
|
||||||
mTextBalance->setVisible(visible);
|
mTextBalance->setVisible(visible);
|
||||||
|
if (mUPCSupported)
|
||||||
|
mTextUPC->setVisible(visible);
|
||||||
mTextTime->setVisible(visible);
|
mTextTime->setVisible(visible);
|
||||||
childSetVisible("buycurrency", visible);
|
childSetVisible("buycurrency", visible);
|
||||||
childSetVisible("search_editor", visible);
|
childSetVisible("search_editor", visible);
|
||||||
@@ -653,7 +691,7 @@ void LLStatusBar::creditBalance(S32 credit)
|
|||||||
void LLStatusBar::setBalance(S32 balance)
|
void LLStatusBar::setBalance(S32 balance)
|
||||||
{
|
{
|
||||||
mTextBalance->setText(gHippoGridManager->getConnectedGrid()->getCurrencySymbol().c_str() +
|
mTextBalance->setText(gHippoGridManager->getConnectedGrid()->getCurrencySymbol().c_str() +
|
||||||
LLResMgr::getInstance()->getMonetaryString(balance));
|
LLResMgr::getInstance()->getMonetaryString(balance - mUPC));
|
||||||
|
|
||||||
if (mBalance && (fabs((F32)(mBalance - balance)) > gSavedSettings.getF32("UISndMoneyChangeThreshold")))
|
if (mBalance && (fabs((F32)(mBalance - balance)) > gSavedSettings.getF32("UISndMoneyChangeThreshold")))
|
||||||
{
|
{
|
||||||
@@ -670,6 +708,14 @@ void LLStatusBar::setBalance(S32 balance)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LLStatusBar::setUPC(S32 upc)
|
||||||
|
{
|
||||||
|
mTextUPC->setText("UPC " + LLResMgr::getInstance()->getMonetaryString(upc));
|
||||||
|
|
||||||
|
mUPC = upc;
|
||||||
|
|
||||||
|
setBalance(mBalance);
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void LLStatusBar::sendMoneyBalanceRequest()
|
void LLStatusBar::sendMoneyBalanceRequest()
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ public:
|
|||||||
|
|
||||||
// MANIPULATORS
|
// MANIPULATORS
|
||||||
void setBalance(S32 balance);
|
void setBalance(S32 balance);
|
||||||
|
void setUPC(S32 balance);
|
||||||
void debitBalance(S32 debit);
|
void debitBalance(S32 debit);
|
||||||
void creditBalance(S32 credit);
|
void creditBalance(S32 credit);
|
||||||
|
|
||||||
@@ -99,6 +100,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
LLTextBox *mTextBalance;
|
LLTextBox *mTextBalance;
|
||||||
|
LLTextBox *mTextUPC;
|
||||||
LLTextBox *mTextHealth;
|
LLTextBox *mTextHealth;
|
||||||
LLTextBox *mTextTime;
|
LLTextBox *mTextTime;
|
||||||
|
|
||||||
@@ -110,6 +112,7 @@ private:
|
|||||||
LLButton *mBtnBuyCurrency;
|
LLButton *mBtnBuyCurrency;
|
||||||
|
|
||||||
S32 mBalance;
|
S32 mBalance;
|
||||||
|
S32 mUPC;
|
||||||
S32 mHealth;
|
S32 mHealth;
|
||||||
S32 mSquareMetersCredit;
|
S32 mSquareMetersCredit;
|
||||||
S32 mSquareMetersCommitted;
|
S32 mSquareMetersCommitted;
|
||||||
@@ -118,6 +121,7 @@ private:
|
|||||||
boost::signals2::connection mRegionCrossingSlot;
|
boost::signals2::connection mRegionCrossingSlot;
|
||||||
LLPathfindingNavMesh::navmesh_slot_t mNavMeshSlot;
|
LLPathfindingNavMesh::navmesh_slot_t mNavMeshSlot;
|
||||||
bool mIsNavMeshDirty;
|
bool mIsNavMeshDirty;
|
||||||
|
bool mUPCSupported;
|
||||||
|
|
||||||
static std::vector<std::string> sDays;
|
static std::vector<std::string> sDays;
|
||||||
static std::vector<std::string> sMonths;
|
static std::vector<std::string> sMonths;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
#include "lltexturefetch.h"
|
#include "lltexturefetch.h"
|
||||||
|
|
||||||
#include "llcurl.h"
|
#include "aicurl.h"
|
||||||
#include "lldir.h"
|
#include "lldir.h"
|
||||||
#include "llhttpclient.h"
|
#include "llhttpclient.h"
|
||||||
#include "llhttpstatuscodes.h"
|
#include "llhttpstatuscodes.h"
|
||||||
@@ -60,6 +60,7 @@
|
|||||||
#include "llstartup.h"
|
#include "llstartup.h"
|
||||||
#include "llsdserialize.h"
|
#include "llsdserialize.h"
|
||||||
#include "llbuffer.h"
|
#include "llbuffer.h"
|
||||||
|
#include "hippogridmanager.h"
|
||||||
|
|
||||||
class AIHTTPTimeoutPolicy;
|
class AIHTTPTimeoutPolicy;
|
||||||
extern AIHTTPTimeoutPolicy HTTPGetResponder_timeout;
|
extern AIHTTPTimeoutPolicy HTTPGetResponder_timeout;
|
||||||
@@ -253,6 +254,7 @@ private:
|
|||||||
LLUUID mID;
|
LLUUID mID;
|
||||||
LLHost mHost;
|
LLHost mHost;
|
||||||
std::string mUrl;
|
std::string mUrl;
|
||||||
|
AIPerServicePtr mPerServicePtr; // Pointer to the AIPerService corresponding to the host of mUrl.
|
||||||
U8 mType;
|
U8 mType;
|
||||||
F32 mImagePriority;
|
F32 mImagePriority;
|
||||||
U32 mWorkPriority;
|
U32 mWorkPriority;
|
||||||
@@ -495,30 +497,6 @@ public:
|
|||||||
|
|
||||||
SGHostBlackList::blacklist_t SGHostBlackList::blacklist;
|
SGHostBlackList::blacklist_t SGHostBlackList::blacklist;
|
||||||
|
|
||||||
#if 0
|
|
||||||
//call every time a connection is opened
|
|
||||||
//return true if connecting allowed
|
|
||||||
static bool sgConnectionThrottle() {
|
|
||||||
const U32 THROTTLE_TIMESTEPS_PER_SECOND = 10;
|
|
||||||
static const LLCachedControl<U32> max_connections_per_second("HTTPRequestRate", 30);
|
|
||||||
U32 max_connections = max_connections_per_second/THROTTLE_TIMESTEPS_PER_SECOND;
|
|
||||||
const U32 timestep = USEC_PER_SEC/THROTTLE_TIMESTEPS_PER_SECOND;
|
|
||||||
U64 now = LLTimer::getTotalTime();
|
|
||||||
std::deque<U64> timestamps;
|
|
||||||
while(!timestamps.empty() && (timestamps[0]<=now-timestep)) {
|
|
||||||
timestamps.pop_front();
|
|
||||||
}
|
|
||||||
if(timestamps.size() < max_connections) {
|
|
||||||
//llinfos << "throttle pass" << llendl;
|
|
||||||
timestamps.push_back(now);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
//llinfos << "throttle fail" << llendl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Cross-thread messaging for asset metrics.
|
// Cross-thread messaging for asset metrics.
|
||||||
@@ -819,6 +797,17 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
|
|||||||
{
|
{
|
||||||
mCanUseNET = mUrl.empty() ;
|
mCanUseNET = mUrl.empty() ;
|
||||||
|
|
||||||
|
if (!mCanUseNET)
|
||||||
|
{
|
||||||
|
// Probably a file://, but well; in that case servicename will be empty.
|
||||||
|
std::string servicename = AIPerService::extract_canonical_servicename(mUrl);
|
||||||
|
if (!servicename.empty())
|
||||||
|
{
|
||||||
|
// Make sure mPerServicePtr is up to date with mUrl.
|
||||||
|
mPerServicePtr = AIPerService::instance(servicename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
calcWorkPriority();
|
calcWorkPriority();
|
||||||
mType = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE : LLImageBase::TYPE_NORMAL;
|
mType = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE : LLImageBase::TYPE_NORMAL;
|
||||||
//llinfos << "Create: " << mID << " mHost:" << host << " Discard=" << discard << " URL:"<< mUrl << llendl;
|
//llinfos << "Create: " << mID << " mHost:" << host << " Discard=" << discard << " URL:"<< mUrl << llendl;
|
||||||
@@ -1174,6 +1163,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
|||||||
{
|
{
|
||||||
mUrl = http_url + "/?texture_id=" + mID.asString().c_str();
|
mUrl = http_url + "/?texture_id=" + mID.asString().c_str();
|
||||||
mWriteToCacheState = CAN_WRITE ; //because this texture has a fixed texture id.
|
mWriteToCacheState = CAN_WRITE ; //because this texture has a fixed texture id.
|
||||||
|
mPerServicePtr = AIPerService::instance(AIPerService::extract_canonical_servicename(http_url));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1182,7 +1172,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// This will happen if not logged in or if a region deoes not have HTTP Texture enabled
|
// This will happen if not logged in or if a region does not have HTTP Texture enabled
|
||||||
//llwarns << "Region not found for host: " << mHost << llendl;
|
//llwarns << "Region not found for host: " << mHost << llendl;
|
||||||
mCanUseHTTP = false;
|
mCanUseHTTP = false;
|
||||||
}
|
}
|
||||||
@@ -1259,29 +1249,14 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
|||||||
{
|
{
|
||||||
if(mCanUseHTTP)
|
if(mCanUseHTTP)
|
||||||
{
|
{
|
||||||
//NOTE:
|
|
||||||
//control the number of the http requests issued for:
|
|
||||||
//1, not opening too many file descriptors at the same time;
|
|
||||||
//2, control the traffic of http so udp gets bandwidth.
|
|
||||||
//
|
|
||||||
static const LLCachedControl<U32> max_http_requests("HTTPMaxRequests", 8);
|
|
||||||
static const LLCachedControl<U32> min_http_requests("HTTPMinRequests", 2);
|
|
||||||
static const LLCachedControl<F32> throttle_bandwidth("HTTPThrottleBandwidth", 2000);
|
|
||||||
if(((U32)mFetcher->getNumHTTPRequests() >= max_http_requests) ||
|
|
||||||
((mFetcher->getTextureBandwidth() > throttle_bandwidth) &&
|
|
||||||
((U32)mFetcher->getNumHTTPRequests() > min_http_requests)))
|
|
||||||
{
|
|
||||||
return false ; //wait.
|
|
||||||
}
|
|
||||||
|
|
||||||
mFetcher->removeFromNetworkQueue(this, false);
|
|
||||||
|
|
||||||
S32 cur_size = 0;
|
S32 cur_size = 0;
|
||||||
if (mFormattedImage.notNull())
|
if (mFormattedImage.notNull())
|
||||||
{
|
{
|
||||||
cur_size = mFormattedImage->getDataSize(); // amount of data we already have
|
cur_size = mFormattedImage->getDataSize(); // amount of data we already have
|
||||||
if (mFormattedImage->getDiscardLevel() == 0)
|
if (mFormattedImage->getDiscardLevel() == 0)
|
||||||
{
|
{
|
||||||
|
// Already have all data.
|
||||||
|
mFetcher->removeFromNetworkQueue(this, false); // Note sure this is necessary, but it's what the old did --Aleric
|
||||||
if(cur_size > 0)
|
if(cur_size > 0)
|
||||||
{
|
{
|
||||||
// We already have all the data, just decode it
|
// We already have all the data, just decode it
|
||||||
@@ -1295,20 +1270,30 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Let AICurl decide if we can process more HTTP requests at the moment or not.
|
||||||
|
if (!AIPerService::wantsMoreHTTPRequestsFor(mPerServicePtr))
|
||||||
|
{
|
||||||
|
return false ; //wait.
|
||||||
|
}
|
||||||
|
// If AIPerService::wantsMoreHTTPRequestsFor returns true then it approved ONE request.
|
||||||
|
// This object keeps track of whether or not that is honored.
|
||||||
|
AIPerService::Approvement approvement(mPerServicePtr);
|
||||||
|
|
||||||
|
mFetcher->removeFromNetworkQueue(this, false);
|
||||||
|
|
||||||
mRequestedSize = mDesiredSize - cur_size;
|
mRequestedSize = mDesiredSize - cur_size;
|
||||||
mRequestedDiscard = mDesiredDiscard;
|
mRequestedDiscard = mDesiredDiscard;
|
||||||
mRequestedOffset = cur_size;
|
mRequestedOffset = cur_size;
|
||||||
|
|
||||||
bool res = false;
|
bool res = false;
|
||||||
if (!mUrl.empty())
|
if (!mUrl.empty())
|
||||||
{
|
{
|
||||||
mLoaded = FALSE;
|
mLoaded = FALSE;
|
||||||
mGetStatus = 0;
|
mGetStatus = 0;
|
||||||
mGetReason.clear();
|
mGetReason.clear();
|
||||||
static const LLCachedControl<F32> throttle_bandwidth("HTTPThrottleBandwidth", 2000);
|
|
||||||
LL_DEBUGS("Texture") << "HTTP GET: " << mID << " Offset: " << mRequestedOffset
|
LL_DEBUGS("Texture") << "HTTP GET: " << mID << " Offset: " << mRequestedOffset
|
||||||
<< " Bytes: " << mRequestedSize
|
<< " Bytes: " << mRequestedSize
|
||||||
<< " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << throttle_bandwidth
|
|
||||||
<< LL_ENDL;
|
<< LL_ENDL;
|
||||||
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
|
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
|
||||||
mState = WAIT_HTTP_REQ;
|
mState = WAIT_HTTP_REQ;
|
||||||
@@ -1339,7 +1324,9 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
|||||||
}
|
}
|
||||||
LLHTTPClient::request(mUrl, LLHTTPClient::HTTP_GET, NULL,
|
LLHTTPClient::request(mUrl, LLHTTPClient::HTTP_GET, NULL,
|
||||||
new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, mRequestedOffset, true),
|
new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, mRequestedOffset, true),
|
||||||
headers/*,*/ DEBUG_CURLIO_PARAM(debug_off), keep_alive, no_does_authentication, allow_compressed_reply, NULL, 0, NULL);
|
headers/*,*/ DEBUG_CURLIO_PARAM(debug_off), keep_alive, no_does_authentication, allow_compressed_reply, NULL, 0, NULL, false);
|
||||||
|
// Now the request was added to the command queue.
|
||||||
|
approvement.honored();
|
||||||
res = true;
|
res = true;
|
||||||
}
|
}
|
||||||
if (!res)
|
if (!res)
|
||||||
@@ -2050,8 +2037,6 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
|
|||||||
mBadPacketCount(0),
|
mBadPacketCount(0),
|
||||||
mTextureCache(cache),
|
mTextureCache(cache),
|
||||||
mImageDecodeThread(imagedecodethread),
|
mImageDecodeThread(imagedecodethread),
|
||||||
mTextureBandwidth(0),
|
|
||||||
mHTTPTextureBits(0),
|
|
||||||
mTotalHTTPRequests(0),
|
mTotalHTTPRequests(0),
|
||||||
mQAMode(qa_mode),
|
mQAMode(qa_mode),
|
||||||
mTotalCacheReadCount(0U),
|
mTotalCacheReadCount(0U),
|
||||||
@@ -2203,7 +2188,6 @@ void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id, S32 received_size)
|
|||||||
{
|
{
|
||||||
LLMutexLock lock(&mNetworkQueueMutex);
|
LLMutexLock lock(&mNetworkQueueMutex);
|
||||||
mHTTPTextureQueue.erase(id);
|
mHTTPTextureQueue.erase(id);
|
||||||
mHTTPTextureBits += received_size * 8; // Approximate - does not include header bits
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLTextureFetch::deleteRequest(const LLUUID& id, bool cancel)
|
void LLTextureFetch::deleteRequest(const LLUUID& id, bool cancel)
|
||||||
@@ -2261,15 +2245,6 @@ S32 LLTextureFetch::getNumRequests()
|
|||||||
return size ;
|
return size ;
|
||||||
}
|
}
|
||||||
|
|
||||||
S32 LLTextureFetch::getNumHTTPRequests()
|
|
||||||
{
|
|
||||||
mNetworkQueueMutex.lock() ;
|
|
||||||
S32 size = (S32)mHTTPTextureQueue.size();
|
|
||||||
mNetworkQueueMutex.unlock() ;
|
|
||||||
|
|
||||||
return size ;
|
|
||||||
}
|
|
||||||
|
|
||||||
U32 LLTextureFetch::getTotalNumHTTPRequests()
|
U32 LLTextureFetch::getTotalNumHTTPRequests()
|
||||||
{
|
{
|
||||||
mNetworkQueueMutex.lock() ;
|
mNetworkQueueMutex.lock() ;
|
||||||
@@ -2425,15 +2400,6 @@ void LLTextureFetch::commonUpdate()
|
|||||||
//virtual
|
//virtual
|
||||||
S32 LLTextureFetch::update(F32 max_time_ms)
|
S32 LLTextureFetch::update(F32 max_time_ms)
|
||||||
{
|
{
|
||||||
{
|
|
||||||
mNetworkQueueMutex.lock() ;
|
|
||||||
|
|
||||||
gTextureList.sTextureBits += mHTTPTextureBits ;
|
|
||||||
mHTTPTextureBits = 0 ;
|
|
||||||
|
|
||||||
mNetworkQueueMutex.unlock() ;
|
|
||||||
}
|
|
||||||
|
|
||||||
S32 res = LLWorkerThread::update(max_time_ms);
|
S32 res = LLWorkerThread::update(max_time_ms);
|
||||||
|
|
||||||
if (!mDebugPause)
|
if (!mDebugPause)
|
||||||
|
|||||||
@@ -79,16 +79,12 @@ public:
|
|||||||
bool receiveImageHeader(const LLHost& host, const LLUUID& id, U8 codec, U16 packets, U32 totalbytes, U16 data_size, U8* data);
|
bool receiveImageHeader(const LLHost& host, const LLUUID& id, U8 codec, U16 packets, U32 totalbytes, U16 data_size, U8* data);
|
||||||
bool receiveImagePacket(const LLHost& host, const LLUUID& id, U16 packet_num, U16 data_size, U8* data);
|
bool receiveImagePacket(const LLHost& host, const LLUUID& id, U16 packet_num, U16 data_size, U8* data);
|
||||||
|
|
||||||
void setTextureBandwidth(F32 bandwidth) { mTextureBandwidth = bandwidth; }
|
|
||||||
F32 getTextureBandwidth() { return mTextureBandwidth; }
|
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
BOOL isFromLocalCache(const LLUUID& id);
|
BOOL isFromLocalCache(const LLUUID& id);
|
||||||
S32 getFetchState(const LLUUID& id, F32& decode_progress_p, F32& requested_priority_p,
|
S32 getFetchState(const LLUUID& id, F32& decode_progress_p, F32& requested_priority_p,
|
||||||
U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p, bool& can_use_http);
|
U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p, bool& can_use_http);
|
||||||
void dump();
|
void dump();
|
||||||
S32 getNumRequests() ;
|
S32 getNumRequests() ;
|
||||||
S32 getNumHTTPRequests() ;
|
|
||||||
U32 getTotalNumHTTPRequests() ;
|
U32 getTotalNumHTTPRequests() ;
|
||||||
|
|
||||||
// Public for access by callbacks
|
// Public for access by callbacks
|
||||||
@@ -165,11 +161,8 @@ private:
|
|||||||
queue_t mHTTPTextureQueue;
|
queue_t mHTTPTextureQueue;
|
||||||
typedef std::map<LLHost,std::set<LLUUID> > cancel_queue_t;
|
typedef std::map<LLHost,std::set<LLUUID> > cancel_queue_t;
|
||||||
cancel_queue_t mCancelQueue;
|
cancel_queue_t mCancelQueue;
|
||||||
F32 mTextureBandwidth;
|
|
||||||
LLTextureInfo mTextureInfo;
|
LLTextureInfo mTextureInfo;
|
||||||
|
|
||||||
U32 mHTTPTextureBits;
|
|
||||||
|
|
||||||
//debug use
|
//debug use
|
||||||
U32 mTotalHTTPRequests ;
|
U32 mTotalHTTPRequests ;
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include "llimageworker.h"
|
#include "llimageworker.h"
|
||||||
#include "llrender.h"
|
#include "llrender.h"
|
||||||
|
|
||||||
|
#include "aicurlperservice.h"
|
||||||
#include "llappviewer.h"
|
#include "llappviewer.h"
|
||||||
#include "llselectmgr.h"
|
#include "llselectmgr.h"
|
||||||
#include "llviewertexlayer.h"
|
#include "llviewertexlayer.h"
|
||||||
@@ -64,6 +65,15 @@ LLTextureSizeView *gTextureCategoryView = NULL;
|
|||||||
//static
|
//static
|
||||||
std::set<LLViewerFetchedTexture*> LLTextureView::sDebugImages;
|
std::set<LLViewerFetchedTexture*> LLTextureView::sDebugImages;
|
||||||
|
|
||||||
|
// Forward declaration.
|
||||||
|
namespace AICurlInterface {
|
||||||
|
U32 getNumHTTPCommands(void);
|
||||||
|
U32 getNumHTTPQueued(void);
|
||||||
|
U32 getNumHTTPAdded(void);
|
||||||
|
U32 getNumHTTPRunning(void);
|
||||||
|
size_t getHTTPBandwidth(void);
|
||||||
|
} // namespace AICurlInterface
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static std::string title_string1a("Tex UUID Area DDis(Req) DecodePri(Fetch) [download] pk/max");
|
static std::string title_string1a("Tex UUID Area DDis(Req) DecodePri(Fetch) [download] pk/max");
|
||||||
@@ -593,7 +603,7 @@ void LLGLTexMemBar::draw()
|
|||||||
#endif
|
#endif
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
text = llformat("Textures: %d Fetch: %d(%d) Pkts:%d(%d) Cache R/W: %d/%d LFS:%d IW:%d RAW:%d(%d) HTP:%d DEC:%d CRE:%d ",
|
text = llformat("Textures: %d Fetch: %d(%d) Pkts:%d(%d) Cache R/W: %d/%d LFS:%d IW:%d RAW:%d(%d) HTTP:%d/%d/%d/%d DEC:%d CRE:%d ",
|
||||||
gTextureList.getNumImages(),
|
gTextureList.getNumImages(),
|
||||||
LLAppViewer::getTextureFetch()->getNumRequests(), LLAppViewer::getTextureFetch()->getNumDeletes(),
|
LLAppViewer::getTextureFetch()->getNumRequests(), LLAppViewer::getTextureFetch()->getNumDeletes(),
|
||||||
LLAppViewer::getTextureFetch()->mPacketCount, LLAppViewer::getTextureFetch()->mBadPacketCount,
|
LLAppViewer::getTextureFetch()->mPacketCount, LLAppViewer::getTextureFetch()->mBadPacketCount,
|
||||||
@@ -601,7 +611,10 @@ void LLGLTexMemBar::draw()
|
|||||||
LLLFSThread::sLocal->getPending(),
|
LLLFSThread::sLocal->getPending(),
|
||||||
LLAppViewer::getImageDecodeThread()->getPending(),
|
LLAppViewer::getImageDecodeThread()->getPending(),
|
||||||
LLImageRaw::sRawImageCount, LLImageRaw::sRawImageCachedCount,
|
LLImageRaw::sRawImageCount, LLImageRaw::sRawImageCachedCount,
|
||||||
LLAppViewer::getTextureFetch()->getNumHTTPRequests(),
|
AICurlInterface::getNumHTTPCommands(),
|
||||||
|
AICurlInterface::getNumHTTPQueued(),
|
||||||
|
AICurlInterface::getNumHTTPAdded(),
|
||||||
|
AICurlInterface::getNumHTTPRunning(),
|
||||||
LLAppViewer::getImageDecodeThread()->getPending(),
|
LLAppViewer::getImageDecodeThread()->getPending(),
|
||||||
gTextureList.mCreateTextureList.size());
|
gTextureList.mCreateTextureList.size());
|
||||||
|
|
||||||
@@ -609,14 +622,15 @@ void LLGLTexMemBar::draw()
|
|||||||
text_color, LLFontGL::LEFT, LLFontGL::TOP);
|
text_color, LLFontGL::LEFT, LLFontGL::TOP);
|
||||||
|
|
||||||
left += LLFontGL::getFontMonospace()->getWidth(text);
|
left += LLFontGL::getFontMonospace()->getWidth(text);
|
||||||
F32 bandwidth = LLAppViewer::getTextureFetch()->getTextureBandwidth();
|
// This bandwidth is averaged over 1 seconds (in bytes/s).
|
||||||
F32 max_bandwidth = gSavedSettings.getF32("HTTPThrottleBandwidth");
|
size_t const bandwidth = AICurlInterface::getHTTPBandwidth();
|
||||||
color = bandwidth > max_bandwidth ? LLColor4::red : bandwidth > max_bandwidth*.75f ? LLColor4::yellow : text_color;
|
size_t const max_bandwidth = AIPerService::getHTTPThrottleBandwidth125();
|
||||||
|
color = (bandwidth > max_bandwidth) ? LLColor4::red : ((bandwidth > max_bandwidth * .75f) ? LLColor4::yellow : text_color);
|
||||||
color[VALPHA] = text_color[VALPHA];
|
color[VALPHA] = text_color[VALPHA];
|
||||||
text = llformat("BW:%.0f/%.0f",bandwidth, max_bandwidth);
|
text = llformat("BW:%lu/%lu", bandwidth / 125, max_bandwidth / 125);
|
||||||
LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, v_offset + line_height*2,
|
LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, v_offset + line_height*2,
|
||||||
color, LLFontGL::LEFT, LLFontGL::TOP);
|
color, LLFontGL::LEFT, LLFontGL::TOP);
|
||||||
|
|
||||||
S32 dx1 = 0;
|
S32 dx1 = 0;
|
||||||
if (LLAppViewer::getTextureFetch()->mDebugPause)
|
if (LLAppViewer::getTextureFetch()->mDebugPause)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -84,7 +84,6 @@
|
|||||||
#include "aicurl.h"
|
#include "aicurl.h"
|
||||||
#include "aihttptimeoutpolicy.h"
|
#include "aihttptimeoutpolicy.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
|
#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
|
||||||
BOOL gHackGodmode = FALSE;
|
BOOL gHackGodmode = FALSE;
|
||||||
#endif
|
#endif
|
||||||
@@ -330,6 +329,12 @@ static bool handleBandwidthChanged(const LLSD& newvalue)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool handleHTTPBandwidthChanged(const LLSD& newvalue)
|
||||||
|
{
|
||||||
|
AIPerService::setHTTPThrottleBandwidth((F32) newvalue.asReal());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool handleChatFontSizeChanged(const LLSD& newvalue)
|
static bool handleChatFontSizeChanged(const LLSD& newvalue)
|
||||||
{
|
{
|
||||||
if(gConsole)
|
if(gConsole)
|
||||||
@@ -666,6 +671,7 @@ void settings_setup_listeners()
|
|||||||
gSavedSettings.getControl("RenderTreeLODFactor")->getSignal()->connect(boost::bind(&handleTreeLODChanged, _2));
|
gSavedSettings.getControl("RenderTreeLODFactor")->getSignal()->connect(boost::bind(&handleTreeLODChanged, _2));
|
||||||
gSavedSettings.getControl("RenderFlexTimeFactor")->getSignal()->connect(boost::bind(&handleFlexLODChanged, _2));
|
gSavedSettings.getControl("RenderFlexTimeFactor")->getSignal()->connect(boost::bind(&handleFlexLODChanged, _2));
|
||||||
gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()->connect(boost::bind(&handleBandwidthChanged, _2));
|
gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()->connect(boost::bind(&handleBandwidthChanged, _2));
|
||||||
|
gSavedSettings.getControl("HTTPThrottleBandwidth")->getSignal()->connect(boost::bind(&handleHTTPBandwidthChanged, _2));
|
||||||
gSavedSettings.getControl("RenderGamma")->getSignal()->connect(boost::bind(&handleGammaChanged, _2));
|
gSavedSettings.getControl("RenderGamma")->getSignal()->connect(boost::bind(&handleGammaChanged, _2));
|
||||||
gSavedSettings.getControl("RenderFogRatio")->getSignal()->connect(boost::bind(&handleFogRatioChanged, _2));
|
gSavedSettings.getControl("RenderFogRatio")->getSignal()->connect(boost::bind(&handleFogRatioChanged, _2));
|
||||||
gSavedSettings.getControl("RenderMaxPartCount")->getSignal()->connect(boost::bind(&handleMaxPartCountChanged, _2));
|
gSavedSettings.getControl("RenderMaxPartCount")->getSignal()->connect(boost::bind(&handleMaxPartCountChanged, _2));
|
||||||
@@ -792,7 +798,7 @@ void settings_setup_listeners()
|
|||||||
gSavedSettings.getControl("AscentAvatarZModifier")->getSignal()->connect(boost::bind(&handleAscentAvatarModifier, _2));
|
gSavedSettings.getControl("AscentAvatarZModifier")->getSignal()->connect(boost::bind(&handleAscentAvatarModifier, _2));
|
||||||
|
|
||||||
gSavedSettings.getControl("CurlMaxTotalConcurrentConnections")->getSignal()->connect(boost::bind(&AICurlInterface::handleCurlMaxTotalConcurrentConnections, _2));
|
gSavedSettings.getControl("CurlMaxTotalConcurrentConnections")->getSignal()->connect(boost::bind(&AICurlInterface::handleCurlMaxTotalConcurrentConnections, _2));
|
||||||
gSavedSettings.getControl("CurlConcurrentConnectionsPerHost")->getSignal()->connect(boost::bind(&AICurlInterface::handleCurlConcurrentConnectionsPerHost, _2));
|
gSavedSettings.getControl("CurlConcurrentConnectionsPerService")->getSignal()->connect(boost::bind(&AICurlInterface::handleCurlConcurrentConnectionsPerService, _2));
|
||||||
gSavedSettings.getControl("NoVerifySSLCert")->getSignal()->connect(boost::bind(&AICurlInterface::handleNoVerifySSLCert, _2));
|
gSavedSettings.getControl("NoVerifySSLCert")->getSignal()->connect(boost::bind(&AICurlInterface::handleNoVerifySSLCert, _2));
|
||||||
|
|
||||||
gSavedSettings.getControl("CurlTimeoutDNSLookup")->getValidateSignal()->connect(boost::bind(&validateCurlTimeoutDNSLookup, _2));
|
gSavedSettings.getControl("CurlTimeoutDNSLookup")->getValidateSignal()->connect(boost::bind(&validateCurlTimeoutDNSLookup, _2));
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ void process_generic_message(LLMessageSystem* msg, void**)
|
|||||||
}
|
}
|
||||||
else if (agent_id != gAgent.getID())
|
else if (agent_id != gAgent.getID())
|
||||||
{
|
{
|
||||||
llwarns << "GenericMessage for wrong agent" << llendl;
|
llwarns << "GenericMessage for wrong agent " << agent_id << llendl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -353,22 +353,25 @@ void LLViewerInventoryItem::fetchFromServer(void) const
|
|||||||
{
|
{
|
||||||
std::string url;
|
std::string url;
|
||||||
|
|
||||||
LLViewerRegion* region = gAgent.getRegion();
|
if (gSavedSettings.getBOOL("UseHTTPInventory"))
|
||||||
// we have to check region. It can be null after region was destroyed. See EXT-245
|
|
||||||
if (region)
|
|
||||||
{
|
{
|
||||||
if(gAgent.getID() != mPermissions.getOwner())
|
LLViewerRegion* region = gAgent.getRegion();
|
||||||
{
|
// we have to check region. It can be null after region was destroyed. See EXT-245
|
||||||
url = region->getCapability("FetchLib2");
|
if (region)
|
||||||
}
|
{
|
||||||
else
|
if(gAgent.getID() != mPermissions.getOwner())
|
||||||
{
|
{
|
||||||
url = region->getCapability("FetchInventory2");
|
url = region->getCapability("FetchLib2");
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
url = region->getCapability("FetchInventory2");
|
||||||
llwarns << "Agent Region is absent" << llendl;
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
llwarns << "Agent Region is absent" << llendl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!url.empty())
|
if (!url.empty())
|
||||||
|
|||||||
@@ -63,7 +63,6 @@
|
|||||||
#include "llfirstuse.h"
|
#include "llfirstuse.h"
|
||||||
#include "llfloaterabout.h"
|
#include "llfloaterabout.h"
|
||||||
#include "llfloateractivespeakers.h"
|
#include "llfloateractivespeakers.h"
|
||||||
#include "llfloateranimpreview.h"
|
|
||||||
#include "llfloateravatarinfo.h"
|
#include "llfloateravatarinfo.h"
|
||||||
#include "llfloateravatarlist.h"
|
#include "llfloateravatarlist.h"
|
||||||
#include "llfloateravatartextures.h"
|
#include "llfloateravatartextures.h"
|
||||||
@@ -358,7 +357,6 @@ void handle_singleton_toggle(void *)
|
|||||||
|
|
||||||
// <edit>
|
// <edit>
|
||||||
void handle_fake_away_status(void*);
|
void handle_fake_away_status(void*);
|
||||||
void handle_area_search(void*);
|
|
||||||
|
|
||||||
// <dogmode> for pose stand
|
// <dogmode> for pose stand
|
||||||
LLUUID current_pose = LLUUID::null;
|
LLUUID current_pose = LLUUID::null;
|
||||||
@@ -404,13 +402,8 @@ BOOL handle_check_pose(void* userdata) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void handle_force_ground_sit(void*);
|
|
||||||
void handle_hide_typing_notification(void*);
|
|
||||||
void handle_close_all_notifications(void*);
|
void handle_close_all_notifications(void*);
|
||||||
void handle_open_message_log(void*);
|
void handle_open_message_log(void*);
|
||||||
void handle_edit_ao(void*);
|
|
||||||
void handle_sounds_explorer(void*);
|
|
||||||
void handle_blacklist(void*);
|
|
||||||
// </edit>
|
// </edit>
|
||||||
|
|
||||||
void handle_reset_view();
|
void handle_reset_view();
|
||||||
@@ -517,6 +510,12 @@ void region_change();
|
|||||||
void parse_simulator_features();
|
void parse_simulator_features();
|
||||||
void custom_selected(void* user_data);
|
void custom_selected(void* user_data);
|
||||||
|
|
||||||
|
void reset_vertex_buffers(void *user_data)
|
||||||
|
{
|
||||||
|
gPipeline.clearRebuildGroups();
|
||||||
|
gPipeline.resetVertexBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
class LLMenuParcelObserver : public LLParcelObserver
|
class LLMenuParcelObserver : public LLParcelObserver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -700,32 +699,6 @@ void init_menus()
|
|||||||
// TomY TODO convert these two
|
// TomY TODO convert these two
|
||||||
LLMenuGL*menu;
|
LLMenuGL*menu;
|
||||||
|
|
||||||
menu = new LLMenuGL("Singularity");
|
|
||||||
menu->setCanTearOff(TRUE);
|
|
||||||
menu->addChild(new LLMenuItemCallGL( "Close All Dialogs",
|
|
||||||
&handle_close_all_notifications, NULL, NULL, 'D', MASK_CONTROL | MASK_ALT | MASK_SHIFT));
|
|
||||||
menu->addSeparator();
|
|
||||||
menu->addChild(new LLMenuItemCallGL( "Fake Away Status", &handle_fake_away_status, NULL));
|
|
||||||
menu->addChild(new LLMenuItemCallGL( "Force Ground Sit", &handle_force_ground_sit, NULL));
|
|
||||||
|
|
||||||
menu->addSeparator();
|
|
||||||
menu->addChild(new LLMenuItemCallGL( "Animation Override...",
|
|
||||||
&handle_edit_ao, NULL));
|
|
||||||
menu->addChild(new LLMenuItemCheckGL( "Nimble",
|
|
||||||
&menu_toggle_control,
|
|
||||||
NULL,
|
|
||||||
&menu_check_control,
|
|
||||||
(void*)"Nimble"));
|
|
||||||
menu->addSeparator();
|
|
||||||
menu->addChild(new LLMenuItemCallGL( "Object Area Search", &handle_area_search, NULL));
|
|
||||||
|
|
||||||
menu->addChild(new LLMenuItemCallGL( "Sound Explorer",
|
|
||||||
&handle_sounds_explorer, NULL));
|
|
||||||
menu->addChild(new LLMenuItemCallGL( "Asset Blacklist",
|
|
||||||
&handle_blacklist, NULL));
|
|
||||||
menu->addChild(new LLMenuItemCheckGL( "Streaming Audio Display",
|
|
||||||
&handle_ticker_toggle, &handle_ticker_enabled, &handle_singleton_check<SHFloaterMediaTicker>, NULL ));
|
|
||||||
|
|
||||||
// <dogmode>
|
// <dogmode>
|
||||||
// Add in the pose stand -------------------------------------------
|
// Add in the pose stand -------------------------------------------
|
||||||
/*LLMenuGL* sub = new LLMenuGL("Pose Stand...");
|
/*LLMenuGL* sub = new LLMenuGL("Pose Stand...");
|
||||||
@@ -740,12 +713,6 @@ void init_menus()
|
|||||||
sub->addChild(new LLMenuItemCallGL( "Stop Pose Stand", &handle_pose_stand_stop, NULL));
|
sub->addChild(new LLMenuItemCallGL( "Stop Pose Stand", &handle_pose_stand_stop, NULL));
|
||||||
// </dogmode> ------------------------------------------------------*/
|
// </dogmode> ------------------------------------------------------*/
|
||||||
|
|
||||||
menu->addChild(new LLMenuItemCheckGL("Pose Stand",&handle_toggle_pose, NULL, &handle_check_pose, NULL));
|
|
||||||
|
|
||||||
//these should always be last in a sub menu
|
|
||||||
menu->createJumpKeys();
|
|
||||||
gMenuBarView->addChild( menu );
|
|
||||||
|
|
||||||
menu = new LLMenuGL(CLIENT_MENU_NAME);
|
menu = new LLMenuGL(CLIENT_MENU_NAME);
|
||||||
menu->setCanTearOff(TRUE);
|
menu->setCanTearOff(TRUE);
|
||||||
init_client_menu(menu);
|
init_client_menu(menu);
|
||||||
@@ -793,8 +760,10 @@ void init_menus()
|
|||||||
ins->setVisible(false);
|
ins->setVisible(false);
|
||||||
ins = gMenuBarView->getChildView("insert_tools", true, false);
|
ins = gMenuBarView->getChildView("insert_tools", true, false);
|
||||||
ins->setVisible(false);
|
ins->setVisible(false);
|
||||||
/* Singu Note: When the advanced menu is made xml, this should be uncommented.
|
/* Singu Note: When the advanced and/or admin menus are made xml, these should be uncommented.
|
||||||
ins = gMenuBarView->getChildView("insert_advanced", true, false);
|
ins = gMenuBarView->getChildView("insert_advanced", true, false);
|
||||||
|
ins->setVisible(false);
|
||||||
|
ins = gMenuBarView->getChildView("insert_admin", true, false);
|
||||||
ins->setVisible(false);*/
|
ins->setVisible(false);*/
|
||||||
|
|
||||||
LLEnvManagerNew::instance().setRegionChangeCallback(®ion_change);
|
LLEnvManagerNew::instance().setRegionChangeCallback(®ion_change);
|
||||||
@@ -1483,6 +1452,8 @@ void init_debug_rendering_menu(LLMenuGL* menu)
|
|||||||
item = new LLMenuItemCheckGL("Aggressive Alpha Masking", menu_toggle_control, NULL, menu_check_control, (void*)"SHUseRMSEAutoMask");
|
item = new LLMenuItemCheckGL("Aggressive Alpha Masking", menu_toggle_control, NULL, menu_check_control, (void*)"SHUseRMSEAutoMask");
|
||||||
menu->addChild(item);
|
menu->addChild(item);
|
||||||
|
|
||||||
|
menu->addChild(new LLMenuItemCallGL("Rebuild Vertex Buffers", reset_vertex_buffers, NULL, NULL, 'V', MASK_CONTROL | MASK_SHIFT));
|
||||||
|
|
||||||
item = new LLMenuItemCheckGL("Animate Textures", menu_toggle_control, NULL, menu_check_control, (void*)"AnimateTextures");
|
item = new LLMenuItemCheckGL("Animate Textures", menu_toggle_control, NULL, menu_check_control, (void*)"AnimateTextures");
|
||||||
menu->addChild(item);
|
menu->addChild(item);
|
||||||
|
|
||||||
@@ -1578,7 +1549,7 @@ void init_debug_avatar_menu(LLMenuGL* menu)
|
|||||||
(void*)LLPipeline::RENDER_DEBUG_ATTACHMENT_BYTES));
|
(void*)LLPipeline::RENDER_DEBUG_ATTACHMENT_BYTES));
|
||||||
menu->addChild(new LLMenuItemToggleGL( "Debug Rotation", &LLVOAvatar::sDebugAvatarRotation));
|
menu->addChild(new LLMenuItemToggleGL( "Debug Rotation", &LLVOAvatar::sDebugAvatarRotation));
|
||||||
menu->addChild(new LLMenuItemCallGL("Dump Attachments", handle_dump_attachments));
|
menu->addChild(new LLMenuItemCallGL("Dump Attachments", handle_dump_attachments));
|
||||||
menu->addChild(new LLMenuItemCallGL("Rebake Textures", handle_rebake_textures, NULL, NULL, 'R', MASK_ALT | MASK_CONTROL ));
|
menu->addChild(new LLMenuItemCallGL("Rebake Textures", handle_rebake_textures));
|
||||||
#ifndef LL_RELEASE_FOR_DOWNLOAD
|
#ifndef LL_RELEASE_FOR_DOWNLOAD
|
||||||
menu->addChild(new LLMenuItemCallGL("Debug Avatar Textures", handle_debug_avatar_textures, NULL, NULL, 'A', MASK_SHIFT|MASK_CONTROL|MASK_ALT));
|
menu->addChild(new LLMenuItemCallGL("Debug Avatar Textures", handle_debug_avatar_textures, NULL, NULL, 'A', MASK_SHIFT|MASK_CONTROL|MASK_ALT));
|
||||||
menu->addChild(new LLMenuItemCallGL("Dump Local Textures", handle_dump_avatar_local_textures, NULL, NULL, 'M', MASK_SHIFT|MASK_ALT ));
|
menu->addChild(new LLMenuItemCallGL("Dump Local Textures", handle_dump_avatar_local_textures, NULL, NULL, 'M', MASK_SHIFT|MASK_ALT ));
|
||||||
@@ -1703,6 +1674,12 @@ void init_server_menu(LLMenuGL* menu)
|
|||||||
menu->addChild(new LLMenuItemCallGL( "God Tools...",
|
menu->addChild(new LLMenuItemCallGL( "God Tools...",
|
||||||
&LLFloaterGodTools::show, &enable_god_basic, NULL));
|
&LLFloaterGodTools::show, &enable_god_basic, NULL));
|
||||||
|
|
||||||
|
{
|
||||||
|
LLMenuItemCallGL* item = new LLMenuItemCallGL("insert_admin", NULL);
|
||||||
|
item->setVisible(false);
|
||||||
|
menu->addChild(item);
|
||||||
|
}
|
||||||
|
|
||||||
menu->addSeparator();
|
menu->addSeparator();
|
||||||
|
|
||||||
menu->addChild(new LLMenuItemCallGL("Save Region State",
|
menu->addChild(new LLMenuItemCallGL("Save Region State",
|
||||||
@@ -3720,21 +3697,6 @@ void handle_open_message_log(void*)
|
|||||||
LLFloaterMessageLog::show();
|
LLFloaterMessageLog::show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_edit_ao(void*)
|
|
||||||
{
|
|
||||||
LLFloaterAO::show(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_sounds_explorer(void*)
|
|
||||||
{
|
|
||||||
LLFloaterExploreSounds::toggle();
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_blacklist(void*)
|
|
||||||
{
|
|
||||||
LLFloaterBlacklist::show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_close_all_notifications(void*)
|
void handle_close_all_notifications(void*)
|
||||||
{
|
{
|
||||||
LLView::child_list_t child_list(*(gNotifyBoxView->getChildList()));
|
LLView::child_list_t child_list(*(gNotifyBoxView->getChildList()));
|
||||||
@@ -3758,21 +3720,6 @@ void handle_fake_away_status(void*)
|
|||||||
gSavedSettings.setBOOL("FakeAway", !fake_away);
|
gSavedSettings.setBOOL("FakeAway", !fake_away);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_force_ground_sit(void*)
|
|
||||||
{
|
|
||||||
if (isAgentAvatarValid())
|
|
||||||
{
|
|
||||||
if (!gAgentAvatarp->isSitting())
|
|
||||||
{
|
|
||||||
gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// </edit>
|
// </edit>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -6685,6 +6632,14 @@ class LLFloaterVisible : public view_listener_t
|
|||||||
{
|
{
|
||||||
new_value = LLFloaterPathfindingCharacters::instanceVisible(LLSD());
|
new_value = LLFloaterPathfindingCharacters::instanceVisible(LLSD());
|
||||||
}
|
}
|
||||||
|
else if (floater_name == "sound_explorer")
|
||||||
|
{
|
||||||
|
new_value = LLFloaterExploreSounds::visible();
|
||||||
|
}
|
||||||
|
else if (floater_name == "asset_blacklist")
|
||||||
|
{
|
||||||
|
new_value = LLFloaterBlacklist::visible();
|
||||||
|
}
|
||||||
gMenuHolder->findControl(control_name)->setValue(new_value);
|
gMenuHolder->findControl(control_name)->setValue(new_value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -9250,6 +9205,153 @@ class LLWorldDayCycle : public view_listener_t
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SinguCloseAllDialogs : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
|
||||||
|
{
|
||||||
|
handle_close_all_notifications(NULL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinguAnimationOverride : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
|
||||||
|
{
|
||||||
|
LLFloaterAO::show(NULL);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinguNimble : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
|
||||||
|
{
|
||||||
|
gSavedSettings.setBOOL("Nimble", !gSavedSettings.getBOOL("Nimble"));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinguCheckNimble : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
|
||||||
|
{
|
||||||
|
gMenuHolder->findControl(userdata["control"].asString())->setValue(gSavedSettings.getBOOL("Nimble"));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinguSoundExplorer : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
|
||||||
|
{
|
||||||
|
LLFloaterExploreSounds::toggle();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinguAssetBlacklist : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
|
||||||
|
{
|
||||||
|
LLFloaterBlacklist::toggle();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinguStreamingAudioDisplay : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
|
||||||
|
{
|
||||||
|
handle_ticker_toggle(NULL);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinguCheckStreamingAudioDisplay : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
|
||||||
|
{
|
||||||
|
gMenuHolder->findControl(userdata["control"].asString())->setValue(handle_singleton_check<SHFloaterMediaTicker>(NULL));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinguEnableStreamingAudioDisplay : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
|
||||||
|
{
|
||||||
|
return handle_ticker_enabled(NULL);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinguPoseStand : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
|
||||||
|
{
|
||||||
|
handle_toggle_pose(NULL);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinguCheckPoseStand : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
|
||||||
|
{
|
||||||
|
gMenuHolder->findControl(userdata["control"].asString())->setValue(handle_check_pose(NULL));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinguRebake : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
|
||||||
|
{
|
||||||
|
handle_rebake_textures(NULL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinguDebugConsole : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
|
||||||
|
{
|
||||||
|
handle_singleton_toggle<LLFloaterRegionDebugConsole>(NULL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinguCheckDebugConsole : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
|
||||||
|
{
|
||||||
|
gMenuHolder->findControl(userdata["control"].asString())->setValue(handle_singleton_check<LLFloaterRegionDebugConsole>(NULL));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinguVisibleDebugConsole : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
|
||||||
|
{
|
||||||
|
if (LLViewerRegion* region = gAgent.getRegion())
|
||||||
|
{
|
||||||
|
if (LLView* item = gMenuBarView->getChildView("Region Debug Console", true, false))
|
||||||
|
item->setVisible(!(region->getCapability("SimConsoleAsync").empty() || region->getCapability("SimConsole").empty()));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void addMenu(view_listener_t *menu, const std::string& name)
|
void addMenu(view_listener_t *menu, const std::string& name)
|
||||||
{
|
{
|
||||||
sMenus.push_back(menu);
|
sMenus.push_back(menu);
|
||||||
@@ -9525,6 +9627,24 @@ void initialize_menus()
|
|||||||
addMenu(new LLEditableSelected(), "EditableSelected");
|
addMenu(new LLEditableSelected(), "EditableSelected");
|
||||||
addMenu(new LLEditableSelectedMono(), "EditableSelectedMono");
|
addMenu(new LLEditableSelectedMono(), "EditableSelectedMono");
|
||||||
|
|
||||||
|
// Singularity menu
|
||||||
|
addMenu(new SinguCloseAllDialogs(), "CloseAllDialogs");
|
||||||
|
// ---- Fake away handled elsewhere
|
||||||
|
addMenu(new SinguAnimationOverride(), "AnimationOverride");
|
||||||
|
addMenu(new SinguNimble(), "Nimble");
|
||||||
|
addMenu(new SinguCheckNimble(), "CheckNimble");
|
||||||
|
addMenu(new SinguSoundExplorer(), "SoundExplorer");
|
||||||
|
addMenu(new SinguAssetBlacklist(), "AssetBlacklist");
|
||||||
|
addMenu(new SinguStreamingAudioDisplay(), "StreamingAudioDisplay");
|
||||||
|
addMenu(new SinguEnableStreamingAudioDisplay(), "EnableStreamingAudioDisplay");
|
||||||
|
addMenu(new SinguCheckStreamingAudioDisplay(), "CheckStreamingAudioDisplay");
|
||||||
|
addMenu(new SinguPoseStand(), "PoseStand");
|
||||||
|
addMenu(new SinguCheckPoseStand(), "CheckPoseStand");
|
||||||
|
addMenu(new SinguRebake(), "Rebake");
|
||||||
|
addMenu(new SinguDebugConsole(), "RegionDebugConsole");
|
||||||
|
addMenu(new SinguCheckDebugConsole(), "CheckRegionDebugConsole");
|
||||||
|
addMenu(new SinguVisibleDebugConsole(), "VisibleRegionDebugConsole");
|
||||||
|
|
||||||
// [RLVa:KB] - Checked: 2010-01-18 (RLVa-1.1.0m) | Added: RLVa-1.1.0m | OK
|
// [RLVa:KB] - Checked: 2010-01-18 (RLVa-1.1.0m) | Added: RLVa-1.1.0m | OK
|
||||||
if (rlv_handler_t::isEnabled())
|
if (rlv_handler_t::isEnabled())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
#include "llagentcamera.h"
|
#include "llagentcamera.h"
|
||||||
#include "statemachine/aifilepicker.h"
|
#include "statemachine/aifilepicker.h"
|
||||||
#include "llfloateranimpreview.h"
|
#include "llfloateranimpreview.h"
|
||||||
|
#include "llfloaterbvhpreview.h"
|
||||||
#include "llfloaterimagepreview.h"
|
#include "llfloaterimagepreview.h"
|
||||||
#include "llfloatermodelpreview.h"
|
#include "llfloatermodelpreview.h"
|
||||||
#include "llfloaternamedesc.h"
|
#include "llfloaternamedesc.h"
|
||||||
@@ -348,8 +349,17 @@ class LLFileUploadAnim : public view_listener_t, public AIFileUpload
|
|||||||
// Inherited from AIFileUpload.
|
// Inherited from AIFileUpload.
|
||||||
/*virtual*/ void handle_event(std::string const& filename)
|
/*virtual*/ void handle_event(std::string const& filename)
|
||||||
{
|
{
|
||||||
LLFloaterAnimPreview* floaterp = new LLFloaterAnimPreview(filename);
|
int len = filename.size();
|
||||||
LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_animation_preview.xml");
|
if (len >= 5 && filename.substr(len - 5, 5) == ".anim")
|
||||||
|
{
|
||||||
|
LLFloaterAnimPreview* floaterp = new LLFloaterAnimPreview(filename);
|
||||||
|
LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_animation_anim_preview.xml");
|
||||||
|
floaterp->childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%s%d", gHippoGridManager->getConnectedGrid()->getCurrencySymbol().c_str(), LLGlobalEconomy::Singleton::getInstance()->getPriceUpload()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLUICtrlFactory::getInstance()->buildFloater(new LLFloaterBvhPreview(filename), "floater_animation_bvh_preview.xml");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -871,8 +881,8 @@ void upload_new_resource(const std::string& src_filename, std::string name,
|
|||||||
}
|
}
|
||||||
else if (exten == "bvh")
|
else if (exten == "bvh")
|
||||||
{
|
{
|
||||||
error_message = llformat("We do not currently support bulk upload of animation files\n");
|
error_message = llformat("We do not currently support bulk upload of BVH animation files\n");
|
||||||
upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args);
|
upload_error(error_message, "DoNotSupportBulkBVHAnimationUpload", filename, args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// <edit>
|
// <edit>
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
#include "llagentcamera.h"
|
#include "llagentcamera.h"
|
||||||
#include "llcallingcard.h"
|
#include "llcallingcard.h"
|
||||||
#include "llfirstuse.h"
|
#include "llfirstuse.h"
|
||||||
#include "llfloateranimpreview.h"
|
#include "llfloaterbvhpreview.h"
|
||||||
#include "llfloaterbump.h"
|
#include "llfloaterbump.h"
|
||||||
#include "llfloaterbuycurrency.h"
|
#include "llfloaterbuycurrency.h"
|
||||||
#include "llfloaterbuyland.h"
|
#include "llfloaterbuyland.h"
|
||||||
@@ -1239,6 +1239,7 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (gSavedSettings.getBOOL("ShowInInventory") &&
|
if (gSavedSettings.getBOOL("ShowInInventory") &&
|
||||||
|
objects.size() == 1 && item != NULL &&
|
||||||
asset_type != LLAssetType::AT_CALLINGCARD &&
|
asset_type != LLAssetType::AT_CALLINGCARD &&
|
||||||
item->getInventoryType() != LLInventoryType::IT_ATTACHMENT &&
|
item->getInventoryType() != LLInventoryType::IT_ATTACHMENT &&
|
||||||
!from_name.empty())
|
!from_name.empty())
|
||||||
@@ -6495,7 +6496,7 @@ void process_economy_data(LLMessageSystem *msg, void** /*user_data*/)
|
|||||||
LL_INFOS_ONCE("Messaging") << "EconomyData message arrived; upload cost is L$" << upload_cost << LL_ENDL;
|
LL_INFOS_ONCE("Messaging") << "EconomyData message arrived; upload cost is L$" << upload_cost << LL_ENDL;
|
||||||
|
|
||||||
LLFloaterImagePreview::setUploadAmount(upload_cost);
|
LLFloaterImagePreview::setUploadAmount(upload_cost);
|
||||||
LLFloaterAnimPreview::setUploadAmount(upload_cost);
|
LLFloaterBvhPreview::setUploadAmount(upload_cost);
|
||||||
|
|
||||||
std::string fee = gHippoGridManager->getConnectedGrid()->getUploadFee();
|
std::string fee = gHippoGridManager->getConnectedGrid()->getUploadFee();
|
||||||
gMenuHolder->childSetLabelArg("Upload Image", "[UPLOADFEE]", fee);
|
gMenuHolder->childSetLabelArg("Upload Image", "[UPLOADFEE]", fee);
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
#include "llappviewer.h"
|
#include "llappviewer.h"
|
||||||
#include "llassetuploadresponders.h"
|
#include "llassetuploadresponders.h"
|
||||||
#include "statemachine/aifilepicker.h"
|
#include "statemachine/aifilepicker.h"
|
||||||
#include "llfloateranimpreview.h"
|
#include "llfloaterbvhpreview.h"
|
||||||
#include "llfloaterbuycurrency.h"
|
#include "llfloaterbuycurrency.h"
|
||||||
#include "llfloaterimagepreview.h"
|
#include "llfloaterimagepreview.h"
|
||||||
#include "llfloaternamedesc.h"
|
#include "llfloaternamedesc.h"
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
// common includes
|
// common includes
|
||||||
#include "llstat.h"
|
#include "llstat.h"
|
||||||
#include "llstring.h"
|
#include "llstring.h"
|
||||||
|
#include "sguuidhash.h"
|
||||||
|
|
||||||
// project includes
|
// project includes
|
||||||
#include "llviewerobject.h"
|
#include "llviewerobject.h"
|
||||||
@@ -216,8 +217,8 @@ public:
|
|||||||
|
|
||||||
std::set<LLUUID> mDeadObjects;
|
std::set<LLUUID> mDeadObjects;
|
||||||
|
|
||||||
std::map<LLUUID, LLPointer<LLViewerObject> > mUUIDObjectMap;
|
boost::unordered_map<LLUUID, LLPointer<LLViewerObject> > mUUIDObjectMap;
|
||||||
std::map<LLUUID, LLPointer<LLVOAvatar> > mUUIDAvatarMap;
|
boost::unordered_map<LLUUID, LLPointer<LLVOAvatar> > mUUIDAvatarMap;
|
||||||
|
|
||||||
//set of objects that need to update their cost
|
//set of objects that need to update their cost
|
||||||
std::set<LLUUID> mStaleObjectCost;
|
std::set<LLUUID> mStaleObjectCost;
|
||||||
@@ -269,7 +270,7 @@ extern LLViewerObjectList gObjectList;
|
|||||||
// Inlines
|
// Inlines
|
||||||
inline LLViewerObject *LLViewerObjectList::findObject(const LLUUID &id) const
|
inline LLViewerObject *LLViewerObjectList::findObject(const LLUUID &id) const
|
||||||
{
|
{
|
||||||
std::map<LLUUID, LLPointer<LLViewerObject> >::const_iterator iter = mUUIDObjectMap.find(id);
|
boost::unordered_map<LLUUID, LLPointer<LLViewerObject> >::const_iterator iter = mUUIDObjectMap.find(id);
|
||||||
if(iter != mUUIDObjectMap.end())
|
if(iter != mUUIDObjectMap.end())
|
||||||
{
|
{
|
||||||
return iter->second;
|
return iter->second;
|
||||||
@@ -282,7 +283,7 @@ inline LLViewerObject *LLViewerObjectList::findObject(const LLUUID &id) const
|
|||||||
|
|
||||||
inline LLVOAvatar *LLViewerObjectList::findAvatar(const LLUUID &id) const
|
inline LLVOAvatar *LLViewerObjectList::findAvatar(const LLUUID &id) const
|
||||||
{
|
{
|
||||||
std::map<LLUUID, LLPointer<LLVOAvatar> >::const_iterator iter = mUUIDAvatarMap.find(id);
|
boost::unordered_map<LLUUID, LLPointer<LLVOAvatar> >::const_iterator iter = mUUIDAvatarMap.find(id);
|
||||||
return (iter != mUUIDAvatarMap.end()) ? iter->second.get() : NULL;
|
return (iter != mUUIDAvatarMap.end()) ? iter->second.get() : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,6 @@
|
|||||||
#include "llsys.h"
|
#include "llsys.h"
|
||||||
#include "llthread.h"
|
#include "llthread.h"
|
||||||
#include "lltimer.h"
|
#include "lltimer.h"
|
||||||
#include "lluuidhashmap.h"
|
|
||||||
//#include "processor.h"
|
//#include "processor.h"
|
||||||
#include "stdenums.h"
|
#include "stdenums.h"
|
||||||
#include "stdtypes.h"
|
#include "stdtypes.h"
|
||||||
|
|||||||
@@ -1597,8 +1597,9 @@ void LLViewerRegion::unpackRegionHandshake()
|
|||||||
// all of our terrain stuff, by
|
// all of our terrain stuff, by
|
||||||
if (compp->getParamsReady())
|
if (compp->getParamsReady())
|
||||||
{
|
{
|
||||||
//this line creates frame stalls on region crossing and removing it appears to have no effect
|
// The following line was commented out in http://hg.secondlife.com/viewer-development/commits/448b02f5b56f9e608952c810df5454f83051a992
|
||||||
//getLand().dirtyAllPatches();
|
// by davep. However, this is needed to see changes in region/estate texture elevation ranges, and to update the terrain textures after terraforming.
|
||||||
|
getLand().dirtyAllPatches();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1638,15 +1639,10 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
|
|||||||
capabilityNames.append("EnvironmentSettings");
|
capabilityNames.append("EnvironmentSettings");
|
||||||
capabilityNames.append("EstateChangeInfo");
|
capabilityNames.append("EstateChangeInfo");
|
||||||
capabilityNames.append("EventQueueGet");
|
capabilityNames.append("EventQueueGet");
|
||||||
|
capabilityNames.append("FetchLib2");
|
||||||
if (gSavedSettings.getBOOL("UseHTTPInventory")) //Caps suffixed with 2 by LL. Don't update until rest of fetch system is updated first.
|
capabilityNames.append("FetchLibDescendents2");
|
||||||
{
|
capabilityNames.append("FetchInventory2");
|
||||||
capabilityNames.append("FetchLib2");
|
capabilityNames.append("FetchInventoryDescendents2");
|
||||||
capabilityNames.append("FetchLibDescendents2");
|
|
||||||
capabilityNames.append("FetchInventory2");
|
|
||||||
capabilityNames.append("FetchInventoryDescendents2");
|
|
||||||
}
|
|
||||||
|
|
||||||
capabilityNames.append("GamingData"); //Used by certain grids.
|
capabilityNames.append("GamingData"); //Used by certain grids.
|
||||||
capabilityNames.append("GetDisplayNames");
|
capabilityNames.append("GetDisplayNames");
|
||||||
capabilityNames.append("GetMesh");
|
capabilityNames.append("GetMesh");
|
||||||
@@ -1701,6 +1697,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
|
|||||||
capabilityNames.append("ViewerMetrics");
|
capabilityNames.append("ViewerMetrics");
|
||||||
capabilityNames.append("ViewerStartAuction");
|
capabilityNames.append("ViewerStartAuction");
|
||||||
capabilityNames.append("ViewerStats");
|
capabilityNames.append("ViewerStats");
|
||||||
|
capabilityNames.append("WearablesLoaded");
|
||||||
|
|
||||||
// Please add new capabilities alphabetically to reduce
|
// Please add new capabilities alphabetically to reduce
|
||||||
// merge conflicts.
|
// merge conflicts.
|
||||||
|
|||||||
@@ -67,6 +67,10 @@
|
|||||||
class AIHTTPTimeoutPolicy;
|
class AIHTTPTimeoutPolicy;
|
||||||
extern AIHTTPTimeoutPolicy viewerStatsResponder_timeout;
|
extern AIHTTPTimeoutPolicy viewerStatsResponder_timeout;
|
||||||
|
|
||||||
|
namespace AICurlInterface {
|
||||||
|
size_t getHTTPBandwidth(void);
|
||||||
|
}
|
||||||
|
|
||||||
class StatAttributes
|
class StatAttributes
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -210,7 +214,8 @@ LLViewerStats::LLViewerStats() :
|
|||||||
mLayersKBitStat("layerskbitstat"),
|
mLayersKBitStat("layerskbitstat"),
|
||||||
mObjectKBitStat("objectkbitstat"),
|
mObjectKBitStat("objectkbitstat"),
|
||||||
mAssetKBitStat("assetkbitstat"),
|
mAssetKBitStat("assetkbitstat"),
|
||||||
mTextureKBitStat("texturekbitstat"),
|
mHTTPTextureKBitStat("httptexturekbitstat"),
|
||||||
|
mUDPTextureKBitStat("udptexturekbitstat"),
|
||||||
mMallocStat("mallocstat"),
|
mMallocStat("mallocstat"),
|
||||||
mVFSPendingOperations("vfspendingoperations"),
|
mVFSPendingOperations("vfspendingoperations"),
|
||||||
mObjectsDrawnStat("objectsdrawnstat"),
|
mObjectsDrawnStat("objectsdrawnstat"),
|
||||||
@@ -300,7 +305,8 @@ void LLViewerStats::resetStats()
|
|||||||
stats.mKBitStat.reset();
|
stats.mKBitStat.reset();
|
||||||
stats.mLayersKBitStat.reset();
|
stats.mLayersKBitStat.reset();
|
||||||
stats.mObjectKBitStat.reset();
|
stats.mObjectKBitStat.reset();
|
||||||
stats.mTextureKBitStat.reset();
|
stats.mHTTPTextureKBitStat.reset();
|
||||||
|
stats.mUDPTextureKBitStat.reset();
|
||||||
stats.mVFSPendingOperations.reset();
|
stats.mVFSPendingOperations.reset();
|
||||||
stats.mAssetKBitStat.reset();
|
stats.mAssetKBitStat.reset();
|
||||||
stats.mPacketsInStat.reset();
|
stats.mPacketsInStat.reset();
|
||||||
@@ -673,13 +679,13 @@ void update_statistics()
|
|||||||
|
|
||||||
// Only update texture stats periodically so that they are less noisy
|
// Only update texture stats periodically so that they are less noisy
|
||||||
{
|
{
|
||||||
static const F32 texture_stats_freq = 10.f;
|
static const F32 texture_stats_freq = 0.25f;
|
||||||
static LLFrameTimer texture_stats_timer;
|
static LLFrameTimer texture_stats_timer;
|
||||||
if (texture_stats_timer.getElapsedTimeF32() >= texture_stats_freq)
|
if (texture_stats_timer.getElapsedTimeF32() >= texture_stats_freq)
|
||||||
{
|
{
|
||||||
stats.mTextureKBitStat.addValue(LLViewerTextureList::sTextureBits/1024.f);
|
stats.mHTTPTextureKBitStat.addValue(AICurlInterface::getHTTPBandwidth()/125.f);
|
||||||
|
stats.mUDPTextureKBitStat.addValue(LLViewerTextureList::sTextureBits/1024.f);
|
||||||
stats.mTexturePacketsStat.addValue(LLViewerTextureList::sTexturePackets);
|
stats.mTexturePacketsStat.addValue(LLViewerTextureList::sTexturePackets);
|
||||||
LLAppViewer::getTextureFetch()->setTextureBandwidth(LLViewerTextureList::sTextureBits/1024.f/texture_stats_timer.getElapsedTimeF32());
|
|
||||||
gTotalTextureBytes += LLViewerTextureList::sTextureBits / 8;
|
gTotalTextureBytes += LLViewerTextureList::sTextureBits / 8;
|
||||||
LLViewerTextureList::sTextureBits = 0;
|
LLViewerTextureList::sTextureBits = 0;
|
||||||
LLViewerTextureList::sTexturePackets = 0;
|
LLViewerTextureList::sTexturePackets = 0;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user