Merge git://github.com/AlericInglewood/SingularityViewer
Conflicts: indra/newview/llpaneldisplay.cpp indra/newview/skins/default/xui/en-us/panel_preferences_ascent_system.xml
This commit is contained in:
@@ -72,8 +72,10 @@ Aleric Inglewood
|
||||
VWR-14914
|
||||
VWR-24247
|
||||
VWR-24312
|
||||
VWR-24315
|
||||
VWR-24320
|
||||
VWR-24333
|
||||
VWR-24334
|
||||
SNOW-47
|
||||
SNOW-84
|
||||
SNOW-86
|
||||
@@ -112,7 +114,9 @@ Aleric Inglewood
|
||||
IMP-664
|
||||
IMP-670
|
||||
IMP-701
|
||||
IMP-702
|
||||
IMP-734
|
||||
IMP-735
|
||||
Alissa Sabre
|
||||
VWR-81
|
||||
VWR-83
|
||||
|
||||
@@ -673,9 +673,6 @@
|
||||
<key>FetchInventoryDescendents</key>
|
||||
<boolean>false</boolean>
|
||||
|
||||
<key>WebFetchInventoryDescendents</key>
|
||||
<boolean>true</boolean>
|
||||
|
||||
<key>FetchInventory</key>
|
||||
<boolean>true</boolean>
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ endif(NOT STANDALONE)
|
||||
add_custom_target(prepare DEPENDS ${prepare_depends})
|
||||
|
||||
add_subdirectory(cmake)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}cwdebug)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llaudio)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llcharacter)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llcommon)
|
||||
@@ -75,8 +76,8 @@ if (VIEWER)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llplugin)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llui)
|
||||
|
||||
# viewer media plugins
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins)
|
||||
# viewer plugins directory
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}plugins)
|
||||
|
||||
# llplugin testbed code (is this the right way to include it?)
|
||||
#if (NOT LINUX)
|
||||
@@ -105,6 +106,7 @@ if (VIEWER)
|
||||
add_dependencies(viewer solaris-crash-logger)
|
||||
endif (LINUX)
|
||||
|
||||
add_subdirectory(${VIEWER_PREFIX}newview/statemachine)
|
||||
add_subdirectory(${VIEWER_PREFIX}newview)
|
||||
add_dependencies(viewer secondlife-bin)
|
||||
endif (VIEWER)
|
||||
|
||||
4
indra/cmake/AIStateMachine.cmake
Normal file
4
indra/cmake/AIStateMachine.cmake
Normal file
@@ -0,0 +1,4 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
set(AISTATEMACHINE_INCLUDE_DIRS statemachine)
|
||||
set(AISTATEMACHINE_LIBRARIES statemachine)
|
||||
8
indra/cmake/BasicPluginBase.cmake
Normal file
8
indra/cmake/BasicPluginBase.cmake
Normal file
@@ -0,0 +1,8 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
|
||||
set(BASIC_PLUGIN_BASE_INCLUDE_DIRS
|
||||
${LIBS_OPEN_DIR}/plugins/base_basic/
|
||||
)
|
||||
|
||||
set(BASIC_PLUGIN_BASE_LIBRARIES basic_plugin_base)
|
||||
1
indra/cmake/Cwdebug.cmake
Normal file
1
indra/cmake/Cwdebug.cmake
Normal file
@@ -0,0 +1 @@
|
||||
set(CWDEBUG_LIBRARIES cwdebug)
|
||||
@@ -1,46 +0,0 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
# - Find zlib
|
||||
# Find the ZLIB includes and library
|
||||
# This module defines
|
||||
# ZLIB_INCLUDE_DIRS, where to find zlib.h, etc.
|
||||
# ZLIB_LIBRARIES, the libraries needed to use zlib.
|
||||
# ZLIB_FOUND, If false, do not try to use zlib.
|
||||
#
|
||||
# This FindZLIB is about 43 times as fast the one provided with cmake (2.8.x),
|
||||
# because it doesn't look up the version of zlib, resulting in a dramatic
|
||||
# speed up for configure (from 4 minutes 22 seconds to 6 seconds).
|
||||
#
|
||||
# Note: Since this file is only used for standalone, the windows
|
||||
# specific parts were left out.
|
||||
|
||||
FIND_PATH(ZLIB_INCLUDE_DIR zlib.h
|
||||
NO_SYSTEM_ENVIRONMENT_PATH
|
||||
)
|
||||
|
||||
FIND_LIBRARY(ZLIB_LIBRARY z)
|
||||
|
||||
if (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
|
||||
SET(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR})
|
||||
SET(ZLIB_LIBRARIES ${ZLIB_LIBRARY})
|
||||
SET(ZLIB_FOUND "YES")
|
||||
else (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
|
||||
SET(ZLIB_FOUND "NO")
|
||||
endif (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
|
||||
|
||||
if (ZLIB_FOUND)
|
||||
if (NOT ZLIB_FIND_QUIETLY)
|
||||
message(STATUS "Found ZLIB: ${ZLIB_LIBRARIES}")
|
||||
SET(ZLIB_FIND_QUIETLY TRUE)
|
||||
endif (NOT ZLIB_FIND_QUIETLY)
|
||||
else (ZLIB_FOUND)
|
||||
if (ZLIB_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Could not find ZLIB library")
|
||||
endif (ZLIB_FIND_REQUIRED)
|
||||
endif (ZLIB_FOUND)
|
||||
|
||||
mark_as_advanced(
|
||||
ZLIB_LIBRARY
|
||||
ZLIB_INCLUDE_DIR
|
||||
)
|
||||
|
||||
@@ -6,11 +6,13 @@ if (STANDALONE)
|
||||
|
||||
pkg_check_modules(GSTREAMER010 REQUIRED gstreamer-0.10)
|
||||
pkg_check_modules(GSTREAMER010_PLUGINS_BASE REQUIRED gstreamer-plugins-base-0.10)
|
||||
elseif (LINUX)
|
||||
|
||||
else (STANDALONE)
|
||||
|
||||
# Possibly libxml and glib should have their own .cmake file instead...
|
||||
use_prebuilt_binary(glib) # gstreamer needs glib
|
||||
use_prebuilt_binary(gstreamer)
|
||||
# possible libxml should have its own .cmake file instead
|
||||
use_prebuilt_binary(libxml)
|
||||
use_prebuilt_binary(gstreamer)
|
||||
set(GSTREAMER010_FOUND ON FORCE BOOL)
|
||||
set(GSTREAMER010_PLUGINS_BASE_FOUND ON FORCE BOOL)
|
||||
set(GSTREAMER010_INCLUDE_DIRS
|
||||
@@ -18,23 +20,47 @@ elseif (LINUX)
|
||||
${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/glib-2.0
|
||||
${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/libxml2
|
||||
)
|
||||
|
||||
endif (STANDALONE)
|
||||
|
||||
if (WINDOWS)
|
||||
# We don't need to explicitly link against gstreamer itself, because
|
||||
# LLMediaImplGStreamer probes for the system's copy at runtime.
|
||||
set(GSTREAMER010_LIBRARIES
|
||||
gobject-2.0
|
||||
gmodule-2.0
|
||||
dl
|
||||
gthread-2.0
|
||||
rt
|
||||
glib-2.0
|
||||
)
|
||||
endif (STANDALONE)
|
||||
set(GSTREAMER010_LIBRARIES
|
||||
libgstvideo
|
||||
libgstaudio
|
||||
libgstbase-0.10
|
||||
libgstreamer-0.10
|
||||
gobject-2.0
|
||||
gmodule-2.0
|
||||
gthread-2.0
|
||||
glib-2.0
|
||||
)
|
||||
else (WINDOWS)
|
||||
# We don't need to explicitly link against gstreamer itself, because
|
||||
# LLMediaImplGStreamer probes for the system's copy at runtime.
|
||||
set(GSTREAMER010_LIBRARIES
|
||||
gstvideo-0.10
|
||||
gstaudio-0.10
|
||||
gstbase-0.10
|
||||
gstreamer-0.10
|
||||
gobject-2.0
|
||||
gmodule-2.0
|
||||
dl
|
||||
gthread-2.0
|
||||
rt
|
||||
glib-2.0
|
||||
)
|
||||
|
||||
|
||||
endif (WINDOWS)
|
||||
|
||||
|
||||
if (GSTREAMER010_FOUND AND GSTREAMER010_PLUGINS_BASE_FOUND)
|
||||
set(GSTREAMER010 ON CACHE BOOL "Build with GStreamer-0.10 streaming media support.")
|
||||
add_definitions(-DLL_GSTREAMER010_ENABLED=1)
|
||||
endif (GSTREAMER010_FOUND AND GSTREAMER010_PLUGINS_BASE_FOUND)
|
||||
|
||||
if (GSTREAMER010)
|
||||
add_definitions(-DLL_GSTREAMER010_ENABLED=1)
|
||||
endif (GSTREAMER010)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
INCLUDE(APR)
|
||||
INCLUDE(LLMath)
|
||||
INCLUDE(Tut)
|
||||
INCLUDE(Cwdebug)
|
||||
|
||||
MACRO(ADD_BUILD_TEST_NO_COMMON name parent)
|
||||
# MESSAGE("${CMAKE_CURRENT_SOURCE_DIR}/tests/${name}_test.cpp")
|
||||
|
||||
@@ -6,6 +6,7 @@ include(EXPAT)
|
||||
include(ZLIB)
|
||||
|
||||
set(LLCOMMON_INCLUDE_DIRS
|
||||
${LIBS_OPEN_DIR}/cwdebug
|
||||
${LIBS_OPEN_DIR}/llcommon
|
||||
${APR_INCLUDE_DIR}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
|
||||
@@ -42,6 +42,7 @@ if (WINDOWS)
|
||||
wldap32
|
||||
gdi32
|
||||
user32
|
||||
dbghelp
|
||||
)
|
||||
else (WINDOWS)
|
||||
set(WINDOWS_LIBRARIES "")
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
include(BasicPluginBase)
|
||||
|
||||
set(MEDIA_PLUGIN_BASE_INCLUDE_DIRS
|
||||
${LIBS_OPEN_DIR}/media_plugins/base/
|
||||
)
|
||||
|
||||
set(MEDIA_PLUGIN_BASE_LIBRARIES media_plugin_base)
|
||||
set(MEDIA_PLUGIN_BASE_INCLUDE_DIRS ${LIBS_OPEN_DIR}/plugins/base_media ${BASIC_PLUGIN_BASE_INCLUDE_DIRS})
|
||||
set(MEDIA_PLUGIN_BASE_LIBRARIES media_plugin_base ${BASIC_PLUGIN_BASE_LIBRARIES})
|
||||
|
||||
39
indra/cwdebug/CMakeLists.txt
Normal file
39
indra/cwdebug/CMakeLists.txt
Normal file
@@ -0,0 +1,39 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
project(cwdebug)
|
||||
|
||||
include(00-Common)
|
||||
include(LLCommon)
|
||||
include(LLMath)
|
||||
include(LLMessage)
|
||||
include(LLVFS)
|
||||
|
||||
include_directories (${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
set(cwdebug_SOURCE_FILES
|
||||
debug.cc
|
||||
)
|
||||
|
||||
set(cwdebug_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
cwdebug.h
|
||||
sys.h
|
||||
debug.h
|
||||
debug_ostream_operators.h
|
||||
)
|
||||
|
||||
set_source_files_properties(${cwdebug_HEADER_FILES}
|
||||
PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
|
||||
if(NOT WORD_SIZE EQUAL 32)
|
||||
if(WINDOWS)
|
||||
add_definitions(/FIXED:NO)
|
||||
else(WINDOWS) # not windows therefore gcc LINUX and DARWIN
|
||||
add_definitions(-fPIC)
|
||||
endif(WINDOWS)
|
||||
endif (NOT WORD_SIZE EQUAL 32)
|
||||
|
||||
list(APPEND cwdebug_SOURCE_FILES ${cwdebug_HEADER_FILES})
|
||||
|
||||
add_library (cwdebug ${cwdebug_SOURCE_FILES})
|
||||
9
indra/cwdebug/cwdebug.h
Normal file
9
indra/cwdebug/cwdebug.h
Normal file
@@ -0,0 +1,9 @@
|
||||
// We support compiling C++ source files that are not
|
||||
// thread-safe, but in that case we assume that they
|
||||
// will not be linked with libcwd_r.
|
||||
#if !defined(_REENTRANT) || !defined(__linux__)
|
||||
#undef CWDEBUG
|
||||
#endif
|
||||
|
||||
#include "sys.h"
|
||||
#include "debug.h"
|
||||
413
indra/cwdebug/debug.cc
Normal file
413
indra/cwdebug/debug.cc
Normal file
@@ -0,0 +1,413 @@
|
||||
// slviewer -- Second Life Viewer Source Code
|
||||
//
|
||||
//! @file debug.cc
|
||||
//! @brief This file contains the definitions of debug related objects and functions.
|
||||
//
|
||||
// Copyright (C) 2008, by
|
||||
//
|
||||
// Carlo Wood, Run on IRC <carlo@alinoe.com>
|
||||
// RSA-1024 0x624ACAD5 1997-01-26 Sign & Encrypt
|
||||
// Fingerprint16 = 32 EC A7 B6 AC DB 65 A6 F6 F6 55 DD 1C DC FF 61
|
||||
//
|
||||
// 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/>.
|
||||
|
||||
#ifndef USE_PCH
|
||||
#include "sys.h" // Needed for platform-specific code
|
||||
#endif
|
||||
|
||||
#ifdef CWDEBUG
|
||||
|
||||
#ifndef USE_PCH
|
||||
#include <cctype> // Needed for std::isprint
|
||||
#include <iomanip> // Needed for setfill and setw
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include "debug.h"
|
||||
#ifdef USE_LIBCW
|
||||
#include <libcw/memleak.h> // memleak_filter
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif // USE_PCH
|
||||
|
||||
#define BACKTRACE_AQUIRE_LOCK libcwd::_private_::mutex_tct<libcwd::_private_::backtrace_instance>::lock()
|
||||
#define BACKTRACE_RELEASE_LOCK libcwd::_private_::mutex_tct<libcwd::_private_::backtrace_instance>::unlock()
|
||||
|
||||
namespace debug {
|
||||
|
||||
#if CWDEBUG_LOCATION
|
||||
void BackTrace::dump_backtrace(void) const
|
||||
{
|
||||
for (int frame = 0; frame < frames(); ++frame)
|
||||
{
|
||||
libcwd::location_ct loc((char*)buffer()[frame] + libcwd::builtin_return_address_offset);
|
||||
Dout(dc::notice|continued_cf, '#' << std::left << std::setw(3) << frame <<
|
||||
std::left << std::setw(16) << buffer()[frame] << ' ' << loc << "\n in ");
|
||||
char const* mangled_function_name = loc.mangled_function_name();
|
||||
if (mangled_function_name != libcwd::unknown_function_c)
|
||||
{
|
||||
std::string demangled_function_name;
|
||||
libcwd::demangle_symbol(mangled_function_name, demangled_function_name);
|
||||
Dout(dc::finish, demangled_function_name);
|
||||
}
|
||||
else
|
||||
Dout(dc::finish, mangled_function_name);
|
||||
}
|
||||
}
|
||||
#endif // CWDEBUG_LOCATION
|
||||
|
||||
#if CWDEBUG_ALLOC && CWDEBUG_LOCATION
|
||||
typedef std::map<BackTrace, int, std::less<BackTrace>, libcwd::_private_::internal_allocator> backtrace_map_t;
|
||||
backtrace_map_t* backtrace_map;
|
||||
static int total_calls = 0;
|
||||
static int number_of_stack_traces = 0;
|
||||
|
||||
void my_backtrace_hook(void** buffer, int frames LIBCWD_COMMA_TSD_PARAM)
|
||||
{
|
||||
++total_calls;
|
||||
|
||||
backtrace_map_t::iterator iter;
|
||||
|
||||
set_alloc_checking_off(__libcwd_tsd);
|
||||
{
|
||||
BackTrace backtrace(buffer, frames);
|
||||
std::pair<backtrace_map_t::iterator, bool> res = backtrace_map->insert(backtrace_map_t::value_type(backtrace, 0));
|
||||
if (res.second)
|
||||
++number_of_stack_traces;
|
||||
++res.first->second;
|
||||
iter = res.first;
|
||||
}
|
||||
set_alloc_checking_on(__libcwd_tsd);
|
||||
#if 0
|
||||
// Dump the stack trace.
|
||||
iter->first.dump_backtrace();
|
||||
#endif
|
||||
}
|
||||
|
||||
void start_recording_backtraces(void)
|
||||
{
|
||||
BACKTRACE_AQUIRE_LOCK;
|
||||
libcwd::backtrace_hook = my_backtrace_hook;
|
||||
BACKTRACE_RELEASE_LOCK;
|
||||
//Debug(dc::malloc.on());
|
||||
LIBCWD_TSD_DECLARATION;
|
||||
set_alloc_checking_off(__libcwd_tsd);
|
||||
backtrace_map = new backtrace_map_t;
|
||||
set_alloc_checking_on(__libcwd_tsd);
|
||||
}
|
||||
|
||||
struct Compare {
|
||||
bool operator()(backtrace_map_t::const_iterator const& iter1, backtrace_map_t::const_iterator const& iter2)
|
||||
{
|
||||
return iter1->second > iter2->second;
|
||||
}
|
||||
};
|
||||
|
||||
void stop_recording_backtraces(void)
|
||||
{
|
||||
//Debug(dc::malloc.off());
|
||||
BACKTRACE_AQUIRE_LOCK;
|
||||
libcwd::backtrace_hook = NULL;
|
||||
|
||||
if (!backtrace_map)
|
||||
{
|
||||
Dout(dc::notice, "Not recording; call cwdebug_start() first.");
|
||||
return;
|
||||
}
|
||||
|
||||
Dout(dc::notice, "Total number of calls: " << total_calls);
|
||||
Dout(dc::notice, "Number of different stack traces: " << number_of_stack_traces);
|
||||
Dout(dc::notice, "First 10 stack traces:");
|
||||
std::list<backtrace_map_t::const_iterator> entries;
|
||||
for (backtrace_map_t::const_iterator iter = backtrace_map->begin(); iter != backtrace_map->end(); ++iter)
|
||||
entries.push_back(iter);
|
||||
entries.sort(Compare());
|
||||
int count = 0;
|
||||
for (std::list<backtrace_map_t::const_iterator>::iterator iter = entries.begin(); iter != entries.end(); ++iter, ++count)
|
||||
{
|
||||
Dout(dc::notice, "Used: " << (*iter)->second);
|
||||
// Dump the stack trace.
|
||||
(*iter)->first.dump_backtrace();
|
||||
if (count == 10)
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear all data.
|
||||
LIBCWD_TSD_DECLARATION;
|
||||
set_alloc_checking_off(__libcwd_tsd);
|
||||
delete backtrace_map;
|
||||
set_alloc_checking_on(__libcwd_tsd);
|
||||
backtrace_map = NULL;
|
||||
total_calls = 0;
|
||||
number_of_stack_traces = 0;
|
||||
|
||||
BACKTRACE_RELEASE_LOCK;
|
||||
}
|
||||
#endif // CWDEBUG_ALLOC && CWDEBUG_LOCATION
|
||||
|
||||
namespace channels { // namespace DEBUGCHANNELS
|
||||
namespace dc {
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#define DDCN(x) (x)
|
||||
#endif
|
||||
// Add new debug channels here.
|
||||
|
||||
channel_ct viewer DDCN("VIEWER"); //!< This debug channel is used for the normal debugging out of the viewer.
|
||||
channel_ct primbackup DDCN("PRIMBACKUP"); //!< This debug channel is used for output related to primbackup.
|
||||
channel_ct gtk DDCN("GTK"); //!< This debug channel is used for output related to gtk.
|
||||
channel_ct sdl DDCN("SDL"); //!< This debug channel is used for output related to sdl locking.
|
||||
channel_ct backtrace DDCN("BACKTRACE"); //!< This debug channel is used for backtraces.
|
||||
channel_ct statemachine DDCN("STATEMACHINE"); //!< This debug channel is used class AIStateMachine.
|
||||
|
||||
} // namespace dc
|
||||
} // namespace DEBUGCHANNELS
|
||||
|
||||
// Anonymous namespace, this map and its initialization functions are private to this file
|
||||
// for Thead-safeness reasons.
|
||||
namespace {
|
||||
|
||||
/*! @brief The type of rcfile_dc_states.
|
||||
* @internal
|
||||
*/
|
||||
typedef std::map<std::string, bool> rcfile_dc_states_type;
|
||||
|
||||
/*! @brief Map containing the default debug channel states used at the start of each new thread.
|
||||
* @internal
|
||||
*
|
||||
* The first thread calls main, which calls debug::init which will initialize this
|
||||
* map with all debug channel labels and whether or not they were turned on in the
|
||||
* rcfile or not.
|
||||
*/
|
||||
rcfile_dc_states_type rcfile_dc_states;
|
||||
|
||||
/*! @brief Set the default state of debug channel \a dc_label.
|
||||
* @internal
|
||||
*
|
||||
* This function is called once for each debug channel.
|
||||
*/
|
||||
void set_state(char const* dc_label, bool is_on)
|
||||
{
|
||||
std::pair<rcfile_dc_states_type::iterator, bool> res =
|
||||
rcfile_dc_states.insert(rcfile_dc_states_type::value_type(std::string(dc_label), is_on));
|
||||
if (!res.second)
|
||||
Dout(dc::warning, "Calling set_state() more than once for the same label!");
|
||||
return;
|
||||
}
|
||||
|
||||
/*! @brief Save debug channel states.
|
||||
* @internal
|
||||
*
|
||||
* One time initialization function of rcfile_dc_state.
|
||||
* This must be called from debug::init after reading the rcfile.
|
||||
*/
|
||||
void save_dc_states(void)
|
||||
{
|
||||
// We may only call this function once: it reflects the states as stored
|
||||
// in the rcfile and that won't change. Therefore it is not needed to
|
||||
// lock `rcfile_dc_states', it is only written to by the first thread
|
||||
// (once, via main -> init) when there are no other threads yet.
|
||||
static bool second_time = false;
|
||||
if (second_time)
|
||||
{
|
||||
Dout(dc::warning, "Calling save_dc_states() more than once!");
|
||||
return;
|
||||
}
|
||||
second_time = true;
|
||||
ForAllDebugChannels( set_state(debugChannel.get_label(), debugChannel.is_on()) );
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/*! @brief Returns the the original state of a debug channel.
|
||||
* @internal
|
||||
*
|
||||
* For a given \a dc_label, which must be the exact name (<tt>channel_ct::get_label</tt>) of an
|
||||
* existing debug channel, this function returns \c true when the corresponding debug channel was
|
||||
* <em>on</em> at the startup of the application, directly after reading the libcwd runtime
|
||||
* configuration file (.libcwdrc).
|
||||
*
|
||||
* If the label/channel did not exist at the start of the application, it will return \c false
|
||||
* (note that libcwd disallows adding debug channels to modules - so this would probably
|
||||
* a bug).
|
||||
*/
|
||||
bool is_on_in_rcfile(char const* dc_label)
|
||||
{
|
||||
rcfile_dc_states_type::const_iterator iter = rcfile_dc_states.find(std::string(dc_label));
|
||||
if (iter == rcfile_dc_states.end())
|
||||
{
|
||||
Dout(dc::warning, "is_on_in_rcfile(\"" << dc_label << "\"): \"" << dc_label << "\" is an unknown label!");
|
||||
return false;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
#if LIBCWD_THREAD_SAFE
|
||||
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
// I can cause I'm the maintainer of libcwd ;).
|
||||
libcwd::_private_::pthread_lock_interface_ct cout_mutex(&mutex);
|
||||
libcwd::_private_::lock_interface_base_ct* cout_mutex_ptr(&cout_mutex);
|
||||
#endif
|
||||
|
||||
/*! @brief Initialize debugging code from new threads.
|
||||
*
|
||||
* This function needs to be called at the start of each new thread,
|
||||
* because a new thread starts in a completely reset state.
|
||||
*
|
||||
* The function turns on all debug channels that were turned on
|
||||
* after reading the rcfile at the start of the application.
|
||||
* Furthermore it initializes the debug ostream, its mutex and the
|
||||
* margin of the default debug object (Dout).
|
||||
*/
|
||||
void init_thread(void)
|
||||
{
|
||||
// Turn on all debug channels that are turned on as per rcfile configuration.
|
||||
ForAllDebugChannels(
|
||||
if (!debugChannel.is_on() && is_on_in_rcfile(debugChannel.get_label()))
|
||||
debugChannel.on();
|
||||
);
|
||||
|
||||
// Turn on debug output.
|
||||
Debug( libcw_do.on() );
|
||||
static std::ofstream debug_file;
|
||||
static bool debug_out_opened = false;
|
||||
if (!debug_out_opened)
|
||||
{
|
||||
debug_out_opened = true; // Thread-safe, cause the main thread calls this first while it's still alone.
|
||||
std::ostringstream os;
|
||||
os << "debug.out." << getpid();
|
||||
debug_file.open(os.str().c_str());
|
||||
}
|
||||
static debug::TeeStream debug_stream(std::cout, debug_file);
|
||||
#if LIBCWD_THREAD_SAFE
|
||||
Debug( libcw_do.set_ostream(&debug_stream, cout_mutex_ptr) );
|
||||
#else
|
||||
Debug( libcw_do.set_ostream(&debug_stream) );
|
||||
#endif
|
||||
|
||||
static bool first_thread = true;
|
||||
if (!first_thread) // So far, the application has only one thread. So don't add a thread id.
|
||||
{
|
||||
// Set the thread id in the margin.
|
||||
char margin[18];
|
||||
sprintf(margin, "0x%-14lx ", pthread_self());
|
||||
Debug( libcw_do.margin().assign(margin, 17) );
|
||||
}
|
||||
first_thread = false;
|
||||
}
|
||||
|
||||
/*! @brief Initialize debugging code from main.
|
||||
*
|
||||
* This function initializes the debug code.
|
||||
*/
|
||||
void init(void)
|
||||
{
|
||||
#if CWDEBUG_ALLOC && defined(USE_LIBCW)
|
||||
// Tell the memory leak detector which parts of the code are
|
||||
// expected to leak so that we won't get an alarm for those.
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string> > hide_list;
|
||||
hide_list.push_back(std::pair<std::string, std::string>("libdl.so.2", "_dlerror_run"));
|
||||
hide_list.push_back(std::pair<std::string, std::string>("libstdc++.so.6", "__cxa_get_globals"));
|
||||
// The following is actually necessary because of a bug in glibc
|
||||
// (see http://sources.redhat.com/bugzilla/show_bug.cgi?id=311).
|
||||
hide_list.push_back(std::pair<std::string, std::string>("libc.so.6", "dl_open_worker"));
|
||||
memleak_filter().hide_functions_matching(hide_list);
|
||||
}
|
||||
{
|
||||
std::vector<std::string> hide_list;
|
||||
// Also because of http://sources.redhat.com/bugzilla/show_bug.cgi?id=311
|
||||
hide_list.push_back(std::string("ld-linux.so.2"));
|
||||
memleak_filter().hide_objectfiles_matching(hide_list);
|
||||
}
|
||||
memleak_filter().set_flags(libcwd::show_objectfile|libcwd::show_function);
|
||||
#endif
|
||||
|
||||
// The following call allocated the filebuf's of cin, cout, cerr, wcin, wcout and wcerr.
|
||||
// Because this causes a memory leak being reported, make them invisible.
|
||||
Debug(set_invisible_on());
|
||||
|
||||
// You want this, unless you mix streams output with C output.
|
||||
// Read http://gcc.gnu.org/onlinedocs/libstdc++/27_io/howto.html#8 for an explanation.
|
||||
//std::ios::sync_with_stdio(false);
|
||||
|
||||
// Cancel previous call to set_invisible_on.
|
||||
Debug(set_invisible_off());
|
||||
|
||||
// This will warn you when you are using header files that do not belong to the
|
||||
// shared libcwd object that you linked with.
|
||||
Debug( check_configuration() );
|
||||
|
||||
Debug(
|
||||
libcw_do.on(); // Show which rcfile we are reading!
|
||||
ForAllDebugChannels(
|
||||
while (debugChannel.is_on())
|
||||
debugChannel.off() // Print as little as possible though.
|
||||
);
|
||||
read_rcfile(); // Put 'silent = on' in the rcfile to suppress most of the output here.
|
||||
libcw_do.off()
|
||||
);
|
||||
save_dc_states();
|
||||
|
||||
init_thread();
|
||||
}
|
||||
|
||||
#if CWDEBUG_LOCATION
|
||||
/*! @brief Return call location.
|
||||
*
|
||||
* @param return_addr The return address of the call.
|
||||
*/
|
||||
std::string call_location(void const* return_addr)
|
||||
{
|
||||
libcwd::location_ct loc((char*)return_addr + libcwd::builtin_return_address_offset);
|
||||
std::ostringstream convert;
|
||||
convert << loc;
|
||||
return convert.str();
|
||||
}
|
||||
|
||||
std::vector<BackTrace> __attribute__ ((visibility("default"))) backtraces;
|
||||
pthread_mutex_t __attribute__ ((visibility("default"))) backtrace_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
|
||||
} // namespace debug
|
||||
|
||||
#if CWDEBUG_ALLOC
|
||||
// These can be called from gdb.
|
||||
void cwdebug_start()
|
||||
{
|
||||
debug::start_recording_backtraces();
|
||||
}
|
||||
|
||||
void cwdebug_stop()
|
||||
{
|
||||
debug::stop_recording_backtraces();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CWDEBUG_LOCATION
|
||||
void cwdebug_backtrace(int n)
|
||||
{
|
||||
if (0 < n && n <= debug::backtraces.size())
|
||||
{
|
||||
Dout(dc::backtrace, "Backtrace #" << n << ":");
|
||||
debug::backtraces[n - 1].dump_backtrace();
|
||||
}
|
||||
else
|
||||
std::cout << "No such backtrace nr. Max is " << debug::backtraces.size() << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // CWDEBUG
|
||||
257
indra/cwdebug/debug.h
Normal file
257
indra/cwdebug/debug.h
Normal file
@@ -0,0 +1,257 @@
|
||||
// slviewer -- Second Life Viewer Source Code
|
||||
//
|
||||
//! @file debug.h
|
||||
//! @brief This file contains the declaration of debug related macros, objects and functions.
|
||||
//
|
||||
// Copyright (C) 2008, by
|
||||
//
|
||||
// Carlo Wood, Run on IRC <carlo@alinoe.com>
|
||||
// RSA-1024 0x624ACAD5 1997-01-26 Sign & Encrypt
|
||||
// Fingerprint16 = 32 EC A7 B6 AC DB 65 A6 F6 F6 55 DD 1C DC FF 61
|
||||
//
|
||||
// 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/>.
|
||||
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#ifndef CWDEBUG
|
||||
|
||||
#ifndef DOXYGEN // No need to document this. See http://libcwd.sourceforge.net/ for more info.
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib> // std::exit, EXIT_FAILURE
|
||||
|
||||
#define AllocTag1(p)
|
||||
#define AllocTag2(p, desc)
|
||||
#define AllocTag_dynamic_description(p, x)
|
||||
#define AllocTag(p, x)
|
||||
#define Debug(x)
|
||||
#define Dout(a, b)
|
||||
#define DoutEntering(a, b)
|
||||
#define DoutFatal(a, b) LibcwDoutFatal(::std, , a, b)
|
||||
#define ForAllDebugChannels(STATEMENT)
|
||||
#define ForAllDebugObjects(STATEMENT)
|
||||
#define LibcwDebug(dc_namespace, x)
|
||||
#define LibcwDout(a, b, c, d)
|
||||
#define LibcwDoutFatal(a, b, c, d) do { ::std::cerr << d << ::std::endl; ::std::exit(EXIT_FAILURE); } while (1)
|
||||
#define NEW(x) new x
|
||||
#define CWDEBUG_ALLOC 0
|
||||
#define CWDEBUG_MAGIC 0
|
||||
#define CWDEBUG_LOCATION 0
|
||||
#define CWDEBUG_LIBBFD 0
|
||||
#define CWDEBUG_DEBUG 0
|
||||
#define CWDEBUG_DEBUGOUTPUT 0
|
||||
#define CWDEBUG_DEBUGM 0
|
||||
#define CWDEBUG_DEBUGT 0
|
||||
#define CWDEBUG_MARKER 0
|
||||
|
||||
#define BACKTRACE do { } while(0)
|
||||
|
||||
#endif // !DOXYGEN
|
||||
|
||||
#include <cassert>
|
||||
#ifdef DEBUG
|
||||
#define ASSERT(x) assert(x)
|
||||
#else
|
||||
#define ASSERT(x)
|
||||
#endif
|
||||
|
||||
#else // CWDEBUG
|
||||
|
||||
//! Assert \a x, if debugging is turned on.
|
||||
#define ASSERT(x) LIBCWD_ASSERT(x)
|
||||
#define builtin_return_address(addr) ((char*)__builtin_return_address(addr) + libcwd::builtin_return_address_offset)
|
||||
|
||||
#ifndef DEBUGCHANNELS
|
||||
//! @brief The namespace in which the \c dc namespace is declared.
|
||||
//
|
||||
// <A HREF="http://libcwd.sourceforge.net/">Libcwd</A> demands that this macro is defined
|
||||
// before <libcwd/debug.h> is included and must be the name of the namespace containing
|
||||
// the \c dc (Debug Channels) namespace.
|
||||
//
|
||||
// @sa debug::channels::dc
|
||||
|
||||
#define DEBUGCHANNELS ::debug::channels
|
||||
#endif
|
||||
#include <libcwd/debug.h>
|
||||
#include <boost/shared_array.hpp>
|
||||
#if CWDEBUG_LOCATION
|
||||
#include <execinfo.h> // Needed for 'backtrace'.
|
||||
#endif
|
||||
|
||||
#define CWD_API __attribute__ ((visibility("default")))
|
||||
|
||||
//! Debug specific code.
|
||||
namespace debug {
|
||||
|
||||
void CWD_API init(void); // Initialize debugging code, called once from main.
|
||||
void CWD_API init_thread(void); // Initialize debugging code, called once for each thread.
|
||||
|
||||
//! @brief Debug Channels (dc) namespace.
|
||||
//
|
||||
// @sa debug::channels::dc
|
||||
namespace channels { // namespace DEBUGCHANNELS
|
||||
|
||||
//! The namespace containing the actual debug channels.
|
||||
namespace dc {
|
||||
using namespace libcwd::channels::dc;
|
||||
using libcwd::channel_ct;
|
||||
|
||||
#ifndef DOXYGEN // Doxygen bug causes a warning here.
|
||||
// Add the declaration of new debug channels here
|
||||
// and add their definition in a custom debug.cc file.
|
||||
extern CWD_API channel_ct viewer; // The normal logging output of the viewer (normally to stderr).
|
||||
extern CWD_API channel_ct primbackup;
|
||||
extern CWD_API channel_ct gtk;
|
||||
extern CWD_API channel_ct sdl;
|
||||
extern CWD_API channel_ct backtrace;
|
||||
extern CWD_API channel_ct statemachine;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace dc
|
||||
} // namespace DEBUGCHANNELS
|
||||
|
||||
#if CWDEBUG_LOCATION
|
||||
std::string call_location(void const* return_addr);
|
||||
#endif
|
||||
|
||||
//! @brief Interface for marking scopes of invisible memory allocations.
|
||||
//
|
||||
// Creation of the object does nothing, you have to explicitly call
|
||||
// InvisibleAllocations::on. Destruction of the object automatically
|
||||
// cancels any call to \c on of this object. This makes it exception-
|
||||
// (stack unwinding) and recursive-safe.
|
||||
struct InvisibleAllocations {
|
||||
int M_on; //!< The number of times that InvisibleAllocations::on() was called.
|
||||
//! Constructor.
|
||||
InvisibleAllocations() : M_on(0) { }
|
||||
//! Destructor.
|
||||
~InvisibleAllocations() { while (M_on > 0) off(); }
|
||||
//! Set invisible allocations on. Can be called recursively.
|
||||
void on(void) { libcwd::set_invisible_on(); ++M_on; }
|
||||
//! Cancel one call to on().
|
||||
void off(void) { assert(M_on > 0); --M_on; libcwd::set_invisible_off(); }
|
||||
};
|
||||
|
||||
//! @brief Interface for marking scopes with indented debug output.
|
||||
//
|
||||
// Creation of the object increments the debug indentation. Destruction
|
||||
// of the object automatically decrements the indentation again.
|
||||
struct Indent {
|
||||
int M_indent; //!< The extra number of spaces that were added to the indentation.
|
||||
//! Construct an Indent object.
|
||||
Indent(int indent) : M_indent(indent) { if (M_indent > 0) libcwd::libcw_do.inc_indent(M_indent); }
|
||||
//! Destructor.
|
||||
~Indent() { if (M_indent > 0) libcwd::libcw_do.dec_indent(M_indent); }
|
||||
};
|
||||
|
||||
// A class streambuf that splits what is written to two streambufs.
|
||||
class TeeBuf : public std::streambuf {
|
||||
private:
|
||||
std::streambuf* M_sb1;
|
||||
std::streambuf* M_sb2;
|
||||
|
||||
public:
|
||||
TeeBuf(std::streambuf* sb1, std::streambuf* sb2) : M_sb1(sb1), M_sb2(sb2) { }
|
||||
|
||||
protected:
|
||||
virtual int sync(void) { M_sb2->pubsync(); return M_sb1->pubsync(); }
|
||||
virtual std::streamsize xsputn(char_type const* p, std::streamsize n) { M_sb2->sputn(p, n); return M_sb1->sputn(p, n); }
|
||||
virtual int_type overflow(int_type c = traits_type::eof()) { M_sb2->sputc(c); return M_sb1->sputc(c); }
|
||||
};
|
||||
|
||||
// An ostream that passes what is written to it on to two other ostreams.
|
||||
class TeeStream : public std::ostream {
|
||||
private:
|
||||
TeeBuf M_teebuf;
|
||||
public:
|
||||
TeeStream(std::ostream& os1, std::ostream& os2) : std::ostream(&M_teebuf), M_teebuf(os1.rdbuf(), os2.rdbuf()) { }
|
||||
};
|
||||
|
||||
#if CWDEBUG_LOCATION
|
||||
class BackTrace {
|
||||
private:
|
||||
boost::shared_array<void*> M_buffer;
|
||||
int M_frames;
|
||||
public:
|
||||
BackTrace(void** buffer, int frames) : M_buffer(new void* [frames]), M_frames(frames) { std::memcpy(M_buffer.get(), buffer, sizeof(void*) * frames); }
|
||||
|
||||
friend bool operator<(BackTrace const& bt1, BackTrace const& bt2)
|
||||
{
|
||||
if (bt1.M_frames != bt2.M_frames)
|
||||
return bt1.M_frames < bt2.M_frames;
|
||||
for (int frame = 0; frame < bt1.M_frames; ++frame)
|
||||
if (bt1.M_buffer[frame] < bt2.M_buffer[frame])
|
||||
return true;
|
||||
else if (bt1.M_buffer[frame] > bt2.M_buffer[frame])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void dump_backtrace(void) const;
|
||||
|
||||
int frames(void) const { return M_frames; }
|
||||
boost::shared_array<void*> const& buffer(void) const { return M_buffer; }
|
||||
};
|
||||
extern std::vector<BackTrace> backtraces;
|
||||
extern pthread_mutex_t backtrace_mutex;
|
||||
#define BACKTRACE do { \
|
||||
using namespace debug; \
|
||||
void* buffer[32]; \
|
||||
int frames = backtrace(buffer, 32); \
|
||||
size_t size; \
|
||||
{ \
|
||||
pthread_mutex_lock(&backtrace_mutex); \
|
||||
backtraces.push_back(BackTrace(buffer, frames)); \
|
||||
size = backtraces.size(); \
|
||||
pthread_mutex_unlock(&backtrace_mutex); \
|
||||
} \
|
||||
Dout(dc::backtrace, "Stored backtrace #" << size); \
|
||||
} while(0)
|
||||
#else
|
||||
#define BACKTRACE do { } while(0)
|
||||
#endif // CWDEBUG_LOCATION
|
||||
|
||||
} // namespace debug
|
||||
|
||||
//! Debugging macro.
|
||||
//
|
||||
// Print "Entering " << \a data to channel \a cntrl and increment
|
||||
// debugging output indentation until the end of the current scope.
|
||||
#define DoutEntering(cntrl, data) \
|
||||
int __slviewer_debug_indentation = 2; \
|
||||
{ \
|
||||
LIBCWD_TSD_DECLARATION; \
|
||||
if (LIBCWD_DO_TSD_MEMBER_OFF(::libcwd::libcw_do) < 0) \
|
||||
{ \
|
||||
::libcwd::channel_set_bootstrap_st __libcwd_channel_set(LIBCWD_DO_TSD(::libcwd::libcw_do) LIBCWD_COMMA_TSD); \
|
||||
bool on; \
|
||||
{ \
|
||||
using namespace LIBCWD_DEBUGCHANNELS; \
|
||||
on = (__libcwd_channel_set|cntrl).on; \
|
||||
} \
|
||||
if (on) \
|
||||
Dout(cntrl, "Entering " << data); \
|
||||
else \
|
||||
__slviewer_debug_indentation = 0; \
|
||||
} \
|
||||
} \
|
||||
debug::Indent __slviewer_debug_indent(__slviewer_debug_indentation);
|
||||
|
||||
#endif // CWDEBUG
|
||||
|
||||
#include "debug_ostream_operators.h"
|
||||
|
||||
#endif // DEBUG_H
|
||||
1
indra/cwdebug/debug_ostream_operators.h
Normal file
1
indra/cwdebug/debug_ostream_operators.h
Normal file
@@ -0,0 +1 @@
|
||||
// Empty so far...
|
||||
9
indra/cwdebug/sys.h
Normal file
9
indra/cwdebug/sys.h
Normal file
@@ -0,0 +1,9 @@
|
||||
// The following is the libcwd related mandatory part.
|
||||
// It must be included before any system header file is included.
|
||||
#ifdef CWDEBUG
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <libcwd/sys.h>
|
||||
#endif
|
||||
|
||||
@@ -1336,16 +1336,17 @@ LLAudioSource::LLAudioSource(const LLUUID& id, const LLUUID& owner_id, const F32
|
||||
|
||||
LLAudioSource::~LLAudioSource()
|
||||
{
|
||||
// <edit>
|
||||
// Record destruction of LLAudioSource object.
|
||||
if(mType != LLAudioEngine::AUDIO_TYPE_UI)
|
||||
logSoundStop(mLogID, true);
|
||||
// </edit>
|
||||
if (mChannelp)
|
||||
{
|
||||
// Stop playback of this sound
|
||||
mChannelp->setSource(NULL);
|
||||
mChannelp = NULL;
|
||||
setChannel(NULL);
|
||||
}
|
||||
// <edit>
|
||||
if(mType != LLAudioEngine::AUDIO_TYPE_UI) // && mSourceID.notNull())
|
||||
logSoundStop(mLogID);
|
||||
// </edit>
|
||||
}
|
||||
|
||||
|
||||
@@ -1356,10 +1357,17 @@ void LLAudioSource::setChannel(LLAudioChannel *channelp)
|
||||
return;
|
||||
}
|
||||
|
||||
// <edit>
|
||||
if (!channelp)
|
||||
{
|
||||
if(mType != LLAudioEngine::AUDIO_TYPE_UI)
|
||||
logSoundStop(mLogID, false);
|
||||
}
|
||||
// </edit>
|
||||
|
||||
mChannelp = channelp;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioSource::update()
|
||||
{
|
||||
if (!getCurrentBuffer())
|
||||
@@ -1434,10 +1442,6 @@ bool LLAudioSource::setupChannel()
|
||||
|
||||
bool LLAudioSource::play(const LLUUID &audio_uuid)
|
||||
{
|
||||
// <edit>
|
||||
if(mType != LLAudioEngine::AUDIO_TYPE_UI) //&& mSourceID.notNull())
|
||||
logSoundPlay(mLogID, this, mPositionGlobal, mType, audio_uuid, mOwnerID, mSourceID, mIsTrigger, mLoop); // is mID okay for source id?
|
||||
// </edit>
|
||||
// Special abuse of play(); don't play a sound, but kill it.
|
||||
if (audio_uuid.isNull())
|
||||
{
|
||||
@@ -1453,6 +1457,11 @@ bool LLAudioSource::play(const LLUUID &audio_uuid)
|
||||
return false;
|
||||
}
|
||||
|
||||
// <edit>
|
||||
if(mType != LLAudioEngine::AUDIO_TYPE_UI) //&& mSourceID.notNull())
|
||||
logSoundPlay(this, audio_uuid);
|
||||
// </edit>
|
||||
|
||||
// Reset our age timeout if someone attempts to play the source.
|
||||
mAgeTimer.reset();
|
||||
|
||||
@@ -1846,36 +1855,38 @@ bool LLAudioData::load()
|
||||
std::map<LLUUID, LLSoundHistoryItem> gSoundHistory;
|
||||
|
||||
// static
|
||||
void logSoundPlay(LLUUID id, LLAudioSource* audio_source, LLVector3d position, S32 type, LLUUID assetid, LLUUID ownerid, LLUUID sourceid, bool is_trigger, bool is_looped)
|
||||
void logSoundPlay(LLAudioSource* audio_source, LLUUID const& assetid)
|
||||
{
|
||||
LLSoundHistoryItem item;
|
||||
item.mID = id;
|
||||
item.mID = audio_source->getLogID();
|
||||
item.mAudioSource = audio_source;
|
||||
item.mPosition = position;
|
||||
item.mType = type;
|
||||
item.mPosition = audio_source->getPositionGlobal();
|
||||
item.mType = audio_source->getType();
|
||||
item.mAssetID = assetid;
|
||||
item.mOwnerID = ownerid;
|
||||
item.mSourceID = sourceid;
|
||||
item.mOwnerID = audio_source->getOwnerID();
|
||||
item.mSourceID = audio_source->getSourceID();
|
||||
item.mPlaying = true;
|
||||
item.mTimeStarted = LLTimer::getElapsedSeconds();
|
||||
item.mTimeStopped = F64_MAX;
|
||||
item.mIsTrigger = is_trigger;
|
||||
item.mIsLooped = is_looped;
|
||||
item.mIsTrigger = audio_source->getIsTrigger();
|
||||
item.mIsLooped = audio_source->isLoop();
|
||||
|
||||
item.mReviewed = false;
|
||||
item.mReviewedCollision = false;
|
||||
|
||||
gSoundHistory[id] = item;
|
||||
gSoundHistory[item.mID] = item;
|
||||
}
|
||||
|
||||
//static
|
||||
void logSoundStop(LLUUID id)
|
||||
void logSoundStop(LLUUID const& id, bool destructed)
|
||||
{
|
||||
if(gSoundHistory.find(id) != gSoundHistory.end())
|
||||
std::map<LLUUID, LLSoundHistoryItem>::iterator iter = gSoundHistory.find(id);
|
||||
if(iter != gSoundHistory.end() && iter->second.mAudioSource)
|
||||
{
|
||||
gSoundHistory[id].mPlaying = false;
|
||||
gSoundHistory[id].mTimeStopped = LLTimer::getElapsedSeconds();
|
||||
gSoundHistory[id].mAudioSource = NULL; // just in case
|
||||
iter->second.mPlaying = false;
|
||||
iter->second.mTimeStopped = LLTimer::getElapsedSeconds();
|
||||
if (destructed)
|
||||
iter->second.mAudioSource = NULL;
|
||||
pruneSoundLog();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +306,11 @@ public:
|
||||
void setPlayedOnce(const bool played_once) { mPlayedOnce = played_once; }
|
||||
|
||||
void setType(S32 type) { mType = type; }
|
||||
S32 getType() { return mType; }
|
||||
S32 getType(void) const { return mType; }
|
||||
|
||||
LLUUID const& getOwnerID(void) const { return mOwnerID; }
|
||||
LLUUID const& getSourceID(void) const { return mSourceID; }
|
||||
bool getIsTrigger(void) const { return mIsTrigger; }
|
||||
|
||||
void setPositionGlobal(const LLVector3d &position_global) { mPositionGlobal = position_global; }
|
||||
LLVector3d getPositionGlobal() const { return mPositionGlobal; }
|
||||
@@ -337,6 +341,7 @@ public:
|
||||
friend class LLAudioChannel;
|
||||
protected:
|
||||
void setChannel(LLAudioChannel *channelp);
|
||||
public:
|
||||
LLAudioChannel *getChannel() const { return mChannelp; }
|
||||
|
||||
protected:
|
||||
@@ -430,17 +435,22 @@ public:
|
||||
|
||||
friend class LLAudioEngine;
|
||||
friend class LLAudioSource;
|
||||
|
||||
protected:
|
||||
virtual void play() = 0;
|
||||
virtual void playSynced(LLAudioChannel *channelp) = 0;
|
||||
virtual void cleanup() = 0;
|
||||
void setWaiting(bool waiting) { mWaiting = waiting; }
|
||||
|
||||
public:
|
||||
virtual bool isPlaying() = 0;
|
||||
void setWaiting(const bool waiting) { mWaiting = waiting; }
|
||||
bool isWaiting() const { return mWaiting; }
|
||||
|
||||
protected:
|
||||
virtual bool updateBuffer(); // Check to see if the buffer associated with the source changed, and update if necessary.
|
||||
virtual void update3DPosition() = 0;
|
||||
virtual void updateLoop() = 0; // Update your loop/completion status, for use by queueing/syncing.
|
||||
|
||||
protected:
|
||||
LLAudioSource *mCurrentSourcep;
|
||||
LLAudioBuffer *mCurrentBufferp;
|
||||
@@ -498,12 +508,23 @@ struct LLSoundHistoryItem
|
||||
LLSoundHistoryItem() : mType(0), mPlaying(false), mIsTrigger(false),
|
||||
mIsLooped(false), mReviewed(false), mReviewedCollision(false),
|
||||
mTimeStarted(0), mTimeStopped(0), mAudioSource(0) {}
|
||||
|
||||
bool isPlaying(void) const
|
||||
{
|
||||
return mPlaying && mAudioSource && mAudioSource->getChannel()
|
||||
// It's only REALLY playing if the following also returns true,
|
||||
// but it's too hard detect when that part is starting/stopping,
|
||||
// so in the sound explorer we call "playing" (or "looping")
|
||||
// those audio source that have a channel assigned and call
|
||||
// it a day.
|
||||
/*&& mAudioSource->getChannel()->isPlaying()*/ ;
|
||||
}
|
||||
};
|
||||
|
||||
extern std::map<LLUUID, LLSoundHistoryItem> gSoundHistory;
|
||||
|
||||
extern void logSoundPlay(LLUUID id, LLAudioSource* audio_source, LLVector3d position, S32 type, LLUUID assetid, LLUUID ownerid, LLUUID sourceid, bool is_trigger, bool is_looped);
|
||||
extern void logSoundStop(LLUUID id);
|
||||
extern void logSoundPlay(LLAudioSource* audio_source, LLUUID const& assetid);
|
||||
extern void logSoundStop(LLUUID const& id, bool destructed);
|
||||
extern void pruneSoundLog();
|
||||
extern int gSoundHistoryPruneCounter;
|
||||
|
||||
|
||||
@@ -48,10 +48,10 @@ using namespace std;
|
||||
|
||||
#define INCHES_TO_METERS 0.02540005f
|
||||
|
||||
const F32 POSITION_KEYFRAME_THRESHOLD = 0.03f;
|
||||
const F32 POSITION_KEYFRAME_THRESHOLD_SQUARED = 0.03f * 0.03f;
|
||||
const F32 ROTATION_KEYFRAME_THRESHOLD = 0.01f;
|
||||
|
||||
const F32 POSITION_MOTION_THRESHOLD = 0.001f;
|
||||
const F32 POSITION_MOTION_THRESHOLD_SQUARED = 0.001f * 0.001f;
|
||||
const F32 ROTATION_MOTION_THRESHOLD = 0.001f;
|
||||
|
||||
char gInFile[1024]; /* Flawfinder: ignore */
|
||||
@@ -1202,7 +1202,7 @@ void LLBVHLoader::optimize()
|
||||
if (ki_prev == ki_last_good_pos)
|
||||
{
|
||||
joint->mNumPosKeys++;
|
||||
if (dist_vec(LLVector3(ki_prev->mPos), first_frame_pos) > POSITION_MOTION_THRESHOLD)
|
||||
if (dist_vec_squared(LLVector3(ki_prev->mPos), first_frame_pos) > POSITION_MOTION_THRESHOLD_SQUARED)
|
||||
{
|
||||
pos_changed = TRUE;
|
||||
}
|
||||
@@ -1215,12 +1215,12 @@ void LLBVHLoader::optimize()
|
||||
LLVector3 current_pos(ki->mPos);
|
||||
LLVector3 interp_pos = lerp(current_pos, last_good_pos, 1.f / (F32)numPosFramesConsidered);
|
||||
|
||||
if (dist_vec(current_pos, first_frame_pos) > POSITION_MOTION_THRESHOLD)
|
||||
if (dist_vec_squared(current_pos, first_frame_pos) > POSITION_MOTION_THRESHOLD_SQUARED)
|
||||
{
|
||||
pos_changed = TRUE;
|
||||
}
|
||||
|
||||
if (dist_vec(interp_pos, test_pos) < POSITION_KEYFRAME_THRESHOLD)
|
||||
if (dist_vec_squared(interp_pos, test_pos) < POSITION_KEYFRAME_THRESHOLD_SQUARED)
|
||||
{
|
||||
ki_prev->mIgnorePos = TRUE;
|
||||
numPosFramesConsidered++;
|
||||
|
||||
@@ -261,7 +261,7 @@ public:
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
S32 getVisualParamCount() { return (S32)mVisualParamIndexMap.size(); }
|
||||
S32 getVisualParamCount() const { return (S32)mVisualParamIndexMap.size(); }
|
||||
LLVisualParam* getVisualParam(const char *name);
|
||||
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@
|
||||
#include "llquaternion.h"
|
||||
#include "v3dmath.h"
|
||||
#include "v3math.h"
|
||||
#include "llapr.h"
|
||||
#include "llbvhconsts.h"
|
||||
|
||||
class LLKeyframeDataCache;
|
||||
|
||||
@@ -190,7 +190,7 @@ BOOL LLKeyframeStandMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
if (dot(mPelvisState->getJoint()->getWorldRotation(), mLastGoodPelvisRotation) < ROTATION_THRESHOLD)
|
||||
{
|
||||
mLastGoodPelvisRotation = mPelvisState->getJoint()->getWorldRotation();
|
||||
mLastGoodPelvisRotation.normQuat();
|
||||
mLastGoodPelvisRotation.normalize();
|
||||
mTrackAnkles = TRUE;
|
||||
}
|
||||
else if ((mCharacter->getCharacterPosition() - mLastGoodPosition).magVecSquared() > POSITION_THRESHOLD)
|
||||
|
||||
@@ -36,12 +36,12 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Header Files
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <string>
|
||||
|
||||
#include "llmap.h"
|
||||
#include "lljointstate.h"
|
||||
#include "lljoint.h"
|
||||
#include "llmap.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
project(llcommon)
|
||||
|
||||
include(Cwdebug)
|
||||
include(00-Common)
|
||||
include(LLCommon)
|
||||
include(Linking)
|
||||
@@ -32,6 +33,7 @@ set(llcommon_SOURCE_FILES
|
||||
llerror.cpp
|
||||
llerrorthread.cpp
|
||||
llevent.cpp
|
||||
lleventtimer.cpp
|
||||
llfasttimer.cpp
|
||||
llfile.cpp
|
||||
llfindlocale.cpp
|
||||
@@ -39,6 +41,7 @@ set(llcommon_SOURCE_FILES
|
||||
llformat.cpp
|
||||
llframetimer.cpp
|
||||
llheartbeat.cpp
|
||||
llinstancetracker.cpp
|
||||
llindraconfigfile.cpp
|
||||
llliveappconfig.cpp
|
||||
lllivefile.cpp
|
||||
@@ -60,6 +63,7 @@ set(llcommon_SOURCE_FILES
|
||||
llsdutil.cpp
|
||||
llsecondlifeurls.cpp
|
||||
llstat.cpp
|
||||
llstacktrace.cpp
|
||||
llstreamtools.cpp
|
||||
llstring.cpp
|
||||
llstringtable.cpp
|
||||
@@ -89,12 +93,12 @@ set(llcommon_HEADER_FILES
|
||||
linden_common.h
|
||||
linked_lists.h
|
||||
llagentconstants.h
|
||||
llavatarname.h
|
||||
llapp.h
|
||||
llapr.h
|
||||
llassettype.h
|
||||
llassoclist.h
|
||||
llavatarconstants.h
|
||||
llavatarname.h
|
||||
llbase32.h
|
||||
llbase64.h
|
||||
llboost.h
|
||||
@@ -122,6 +126,7 @@ set(llcommon_HEADER_FILES
|
||||
llevent.h
|
||||
lleventemitter.h
|
||||
llextendedstatus.h
|
||||
lleventtimer.h
|
||||
llfasttimer.h
|
||||
llfile.h
|
||||
llfindlocale.h
|
||||
@@ -132,6 +137,7 @@ set(llcommon_HEADER_FILES
|
||||
llheartbeat.h
|
||||
llhttpstatuscodes.h
|
||||
llindexedqueue.h
|
||||
llinstancetracker.h
|
||||
llindraconfigfile.h
|
||||
llkeythrottle.h
|
||||
lllinkedqueue.h
|
||||
@@ -168,6 +174,7 @@ set(llcommon_HEADER_FILES
|
||||
llskiplist.h
|
||||
llskipmap.h
|
||||
llstack.h
|
||||
llstacktrace.h
|
||||
llstat.h
|
||||
llstatenums.h
|
||||
llstl.h
|
||||
@@ -188,7 +195,6 @@ set(llcommon_HEADER_FILES
|
||||
metaclasst.h
|
||||
metaproperty.h
|
||||
metapropertyt.h
|
||||
processor.h
|
||||
reflective.h
|
||||
reflectivet.h
|
||||
roles_constants.h
|
||||
@@ -214,8 +220,14 @@ target_link_libraries(
|
||||
${EXPAT_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${WINDOWS_LIBRARIES}
|
||||
${CWDEBUG_LIBRARIES}
|
||||
)
|
||||
|
||||
if (LINUX)
|
||||
# When linking with llcommon later, we do not want to link with cwdebug.a again.
|
||||
set_property(TARGET llcommon PROPERTY LINK_INTERFACE_LIBRARIES "-lapr-1 -laprutil-1 -lz")
|
||||
endif (LINUX)
|
||||
|
||||
if (DARWIN)
|
||||
# Don't embed a full path in the library's install name
|
||||
set_target_properties(
|
||||
|
||||
@@ -51,6 +51,14 @@ template<typename T> struct AIReadAccess;
|
||||
template<typename T> struct AIWriteAccess;
|
||||
template<typename T> struct AIAccess;
|
||||
|
||||
#if LL_WINDOWS
|
||||
template<typename T> class AIThreadSafeBits;
|
||||
template<typename T>
|
||||
struct AIThreadSafeWindowsHack {
|
||||
AIThreadSafeWindowsHack(AIThreadSafeBits<T>& var, T* object);
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
class AIThreadSafeBits
|
||||
{
|
||||
@@ -73,6 +81,9 @@ public:
|
||||
void* memory() const { return const_cast<long*>(&mMemory[0]); }
|
||||
|
||||
protected:
|
||||
#if LL_WINDOWS
|
||||
template<typename T2> friend struct AIThreadSafeWindowsHack;
|
||||
#endif
|
||||
// Accessors.
|
||||
T const* ptr() const { return reinterpret_cast<T const*>(mMemory); }
|
||||
T* ptr() { return reinterpret_cast<T*>(mMemory); }
|
||||
@@ -168,7 +179,12 @@ protected:
|
||||
|
||||
public:
|
||||
// Only for use by AITHREADSAFE, see below.
|
||||
AIThreadSafe(T* object) { llassert(object == AIThreadSafeBits<T>::ptr()); }
|
||||
AIThreadSafe(T* object)
|
||||
{
|
||||
#if !LL_WINDOWS
|
||||
llassert(object == AIThreadSafeBits<T>::ptr());
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -191,7 +207,18 @@ public:
|
||||
* Note: This macro does not allow to allocate such object on the heap.
|
||||
* If that is needed, have a look at AIThreadSafeDC.
|
||||
*/
|
||||
#if LL_WINDOWS
|
||||
template<typename T>
|
||||
AIThreadSafeWindowsHack<T>::AIThreadSafeWindowsHack(AIThreadSafeBits<T>& var, T* object)
|
||||
{
|
||||
llassert(object == var.ptr());
|
||||
}
|
||||
#define AITHREADSAFE(type, var, paramlist) \
|
||||
AIThreadSafe<type> var(NULL); \
|
||||
AIThreadSafeWindowsHack<type> dummy_##var(var, new (var.memory()) type paramlist)
|
||||
#else
|
||||
#define AITHREADSAFE(type, var, paramlist) AIThreadSafe<type> var(new (var.memory()) type paramlist)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief A wrapper class for objects that need to be accessed by more than one thread.
|
||||
@@ -278,11 +305,11 @@ struct AIReadAccessConst
|
||||
protected:
|
||||
//! Constructor used by AIReadAccess.
|
||||
AIReadAccessConst(AIThreadSafe<T>& wrapper, state_type state)
|
||||
: mWrapper(wrapper), mState(state)
|
||||
: mWrapper(wrapper), mState(state)
|
||||
#if AI_NEED_ACCESS_CC
|
||||
, mIsCopyConstructed(false)
|
||||
#endif
|
||||
{ }
|
||||
{ }
|
||||
|
||||
AIThreadSafe<T>& mWrapper; //!< Reference to the object that we provide access to.
|
||||
state_type const mState; //!< The lock state that mWrapper is in.
|
||||
@@ -376,7 +403,8 @@ protected:
|
||||
// Locking control.
|
||||
LLMutex mMutex;
|
||||
|
||||
// For use by AIThreadSafeSimpleDC
|
||||
friend struct AIRegisteredStateMachinesList;
|
||||
// For use by AIThreadSafeSimpleDC and AIRegisteredStateMachinesList.
|
||||
AIThreadSafeSimple(void) { }
|
||||
AIThreadSafeSimple(AIAPRPool& parent) : mMutex(parent) { }
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class LLUUID;
|
||||
#define PHYSICS_TIMESTEP (1.f / 45.f)
|
||||
|
||||
const F32 COLLISION_TOLERANCE = 0.1f;
|
||||
const F32 HALF_COLLISION_TOLERANCE = COLLISION_TOLERANCE * 0.5f;
|
||||
const F32 HALF_COLLISION_TOLERANCE = 0.05f;
|
||||
|
||||
// Time constants
|
||||
const U32 HOURS_PER_LINDEN_DAY = 4;
|
||||
@@ -99,9 +99,9 @@ const F32 MIN_AGENT_WIDTH = 0.40f;
|
||||
const F32 DEFAULT_AGENT_WIDTH = 0.60f;
|
||||
const F32 MAX_AGENT_WIDTH = 0.80f;
|
||||
|
||||
const F32 MIN_AGENT_HEIGHT = 1.3f - 2.0f * COLLISION_TOLERANCE;
|
||||
const F32 MIN_AGENT_HEIGHT = 1.1f;
|
||||
const F32 DEFAULT_AGENT_HEIGHT = 1.9f;
|
||||
const F32 MAX_AGENT_HEIGHT = 2.65f - 2.0f * COLLISION_TOLERANCE;
|
||||
const F32 MAX_AGENT_HEIGHT = 2.45f;
|
||||
|
||||
// For linked sets
|
||||
const S32 MAX_CHILDREN_PER_TASK = 255;
|
||||
@@ -252,9 +252,6 @@ const U8 SIM_ACCESS_ADULT = 42; // Seriously Adult Only
|
||||
const U8 SIM_ACCESS_DOWN = 254;
|
||||
const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT;
|
||||
|
||||
// group constants
|
||||
const S32 DEFAULT_MAX_AGENT_GROUPS = 25;
|
||||
|
||||
// attachment constants
|
||||
const S32 MAX_AGENT_ATTACHMENTS = 38;
|
||||
const U8 ATTACHMENT_ADD = 0x80;
|
||||
@@ -293,6 +290,7 @@ const U8 UPD_UNIFORM = 0x10; // used with UPD_SCALE
|
||||
// Agent Update Flags (U8)
|
||||
const U8 AU_FLAGS_NONE = 0x00;
|
||||
const U8 AU_FLAGS_HIDETITLE = 0x01;
|
||||
const U8 AU_FLAGS_CLIENT_AUTOPILOT = 0x02;
|
||||
|
||||
// start location constants
|
||||
const U32 START_LOCATION_ID_LAST = 0;
|
||||
@@ -306,6 +304,14 @@ const U32 START_LOCATION_ID_COUNT = 6;
|
||||
// group constants
|
||||
const U32 GROUP_MIN_SIZE = 2;
|
||||
|
||||
// gMaxAgentGroups is now sent by login.cgi, which
|
||||
// looks it up from globals.xml.
|
||||
//
|
||||
// For now we need an old default value however,
|
||||
// so the viewer can be deployed ahead of login.cgi.
|
||||
//
|
||||
const S32 DEFAULT_MAX_AGENT_GROUPS = 25;
|
||||
|
||||
// radius within which a chat message is fully audible
|
||||
const F32 CHAT_WHISPER_RADIUS = 10.f;
|
||||
const F32 CHAT_NORMAL_RADIUS = 20.f;
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
#ifndef LL_LINDEN_COMMON_H
|
||||
#define LL_LINDEN_COMMON_H
|
||||
|
||||
#include "cwdebug.h"
|
||||
|
||||
#if defined(LL_WINDOWS) && defined(_DEBUG)
|
||||
# if _MSC_VER >= 1400 // Visual C++ 2005 or later
|
||||
# define _CRTDBG_MAP_ALLOC
|
||||
|
||||
@@ -38,8 +38,10 @@
|
||||
#include "llerrorcontrol.h"
|
||||
#include "llerrorthread.h"
|
||||
#include "llframetimer.h"
|
||||
#include "lllivefile.h"
|
||||
#include "llmemory.h"
|
||||
#include "lltimer.h"
|
||||
#include "llstl.h" // for DeletePointer()
|
||||
#include "lleventtimer.h"
|
||||
|
||||
//
|
||||
// Signal handling
|
||||
@@ -139,6 +141,11 @@ LLApp::~LLApp()
|
||||
delete sSigChildCount;
|
||||
sSigChildCount = NULL;
|
||||
#endif
|
||||
|
||||
// reclaim live file memory
|
||||
std::for_each(mLiveFiles.begin(), mLiveFiles.end(), DeletePointer());
|
||||
mLiveFiles.clear();
|
||||
|
||||
setStopped();
|
||||
// HACK: wait for the error thread to clean itself
|
||||
ms_sleep(20);
|
||||
@@ -212,6 +219,15 @@ bool LLApp::parseCommandOptions(int argc, char** argv)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void LLApp::manageLiveFile(LLLiveFile* livefile)
|
||||
{
|
||||
if(!livefile) return;
|
||||
livefile->checkAndReload();
|
||||
livefile->addToEventTimer();
|
||||
mLiveFiles.push_back(livefile);
|
||||
}
|
||||
|
||||
bool LLApp::setOptionData(OptionPriority level, LLSD data)
|
||||
{
|
||||
if((level < 0)
|
||||
|
||||
@@ -131,6 +131,19 @@ public:
|
||||
*/
|
||||
bool parseCommandOptions(int argc, char** argv);
|
||||
|
||||
/**
|
||||
* @brief Keep track of live files automatically.
|
||||
*
|
||||
* *TODO: it currently uses the <code>addToEventTimer()</code> API
|
||||
* instead of the runner. I should probalby use the runner.
|
||||
*
|
||||
* *NOTE: DO NOT add the livefile instance to any kind of check loop.
|
||||
*
|
||||
* @param livefile A valid instance of an LLLiveFile. This LLApp
|
||||
* instance will delete the livefile instance.
|
||||
*/
|
||||
void manageLiveFile(LLLiveFile* livefile);
|
||||
|
||||
/**
|
||||
* @brief Set the options at the specified priority.
|
||||
*
|
||||
@@ -285,6 +298,8 @@ private:
|
||||
// The application options.
|
||||
LLSD mOptions;
|
||||
|
||||
// The live files for this application
|
||||
std::vector<LLLiveFile*> mLiveFiles;
|
||||
//@}
|
||||
|
||||
private:
|
||||
|
||||
@@ -81,7 +81,7 @@ bool ll_apr_warn_status(apr_status_t status)
|
||||
{
|
||||
if(APR_SUCCESS == status) return false;
|
||||
char buf[MAX_STRING]; /* Flawfinder: ignore */
|
||||
apr_strerror(status, buf, MAX_STRING);
|
||||
apr_strerror(status, buf, sizeof(buf));
|
||||
LL_WARNS("APR") << "APR: " << buf << LL_ENDL;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -33,207 +33,115 @@
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llassettype.h"
|
||||
#include "lldictionary.h"
|
||||
#include "llmemory.h"
|
||||
|
||||
#include "llstring.h"
|
||||
#include "lltimer.h"
|
||||
|
||||
// I added lookups for exact text of asset type enums in addition to the ones below, so shoot me. -Steve
|
||||
|
||||
struct asset_info_t
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLAssetType
|
||||
///----------------------------------------------------------------------------
|
||||
struct AssetEntry : public LLDictionaryEntry
|
||||
{
|
||||
LLAssetType::EType type;
|
||||
const char* desc;
|
||||
AssetEntry(const char *desc_name,
|
||||
const char *type_name, // 8 character limit!
|
||||
const char *human_name, // for decoding to human readable form; put any and as many printable characters you want in each one
|
||||
bool can_link, // can you create a link to this type?
|
||||
bool can_fetch, // can you fetch this asset by ID?
|
||||
bool can_know) // can you see this asset's ID?
|
||||
:
|
||||
LLDictionaryEntry(desc_name),
|
||||
mTypeName(type_name),
|
||||
mHumanName(human_name),
|
||||
mCanLink(can_link),
|
||||
mCanFetch(can_fetch),
|
||||
mCanKnow(can_know)
|
||||
{
|
||||
llassert(strlen(mTypeName) <= 8);
|
||||
}
|
||||
|
||||
const char *mTypeName;
|
||||
const char *mHumanName;
|
||||
bool mCanLink;
|
||||
bool mCanFetch;
|
||||
bool mCanKnow;
|
||||
};
|
||||
|
||||
asset_info_t asset_types[] =
|
||||
class LLAssetDictionary : public LLSingleton<LLAssetDictionary>,
|
||||
public LLDictionary<LLAssetType::EType, AssetEntry>
|
||||
{
|
||||
{ LLAssetType::AT_TEXTURE, "TEXTURE" },
|
||||
{ LLAssetType::AT_SOUND, "SOUND" },
|
||||
{ LLAssetType::AT_CALLINGCARD, "CALLINGCARD" },
|
||||
{ LLAssetType::AT_LANDMARK, "LANDMARK" },
|
||||
{ LLAssetType::AT_SCRIPT, "SCRIPT" },
|
||||
{ LLAssetType::AT_CLOTHING, "CLOTHING" },
|
||||
{ LLAssetType::AT_OBJECT, "OBJECT" },
|
||||
{ LLAssetType::AT_NOTECARD, "NOTECARD" },
|
||||
{ LLAssetType::AT_CATEGORY, "CATEGORY" },
|
||||
{ LLAssetType::AT_ROOT_CATEGORY, "ROOT_CATEGORY" },
|
||||
{ LLAssetType::AT_LSL_TEXT, "LSL_TEXT" },
|
||||
{ LLAssetType::AT_LSL_BYTECODE, "LSL_BYTECODE" },
|
||||
{ LLAssetType::AT_TEXTURE_TGA, "TEXTURE_TGA" },
|
||||
{ LLAssetType::AT_BODYPART, "BODYPART" },
|
||||
{ LLAssetType::AT_TRASH, "TRASH" },
|
||||
{ LLAssetType::AT_SNAPSHOT_CATEGORY, "SNAPSHOT_CATEGORY" },
|
||||
{ LLAssetType::AT_LOST_AND_FOUND, "LOST_AND_FOUND" },
|
||||
{ LLAssetType::AT_SOUND_WAV, "SOUND_WAV" },
|
||||
{ LLAssetType::AT_IMAGE_TGA, "IMAGE_TGA" },
|
||||
{ LLAssetType::AT_IMAGE_JPEG, "IMAGE_JPEG" },
|
||||
{ LLAssetType::AT_ANIMATION, "ANIMATION" },
|
||||
{ LLAssetType::AT_GESTURE, "GESTURE" },
|
||||
{ LLAssetType::AT_SIMSTATE, "SIMSTATE" },
|
||||
{ LLAssetType::AT_FAVORITE, "FAVORITE" },
|
||||
{ LLAssetType::AT_LINK, "LINK" },
|
||||
{ LLAssetType::AT_LINK_FOLDER, "CURRENT" },
|
||||
{ LLAssetType::AT_CURRENT_OUTFIT, "FOLDER_LINK" },
|
||||
{ LLAssetType::AT_OUTFIT, "OUTFIT" },
|
||||
{ LLAssetType::AT_MY_OUTFITS, "MY_OUTFITS" },
|
||||
{ LLAssetType::AT_NONE, "NONE" }
|
||||
public:
|
||||
LLAssetDictionary();
|
||||
};
|
||||
|
||||
LLAssetType::EType LLAssetType::getType(const std::string& sin)
|
||||
LLAssetDictionary::LLAssetDictionary()
|
||||
{
|
||||
std::string s = sin;
|
||||
// DESCRIPTION TYPE NAME HUMAN NAME CAN LINK? CAN FETCH? CAN KNOW?
|
||||
// |--------------------|-----------|-------------------|-----------|-----------|---------|
|
||||
addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", true, false, true));
|
||||
addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", true, true, true));
|
||||
addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", true, false, false));
|
||||
addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", true, true, true));
|
||||
addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", true, false, false));
|
||||
addEntry(LLAssetType::AT_CLOTHING, new AssetEntry("CLOTHING", "clothing", "clothing", true, true, true));
|
||||
addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", true, false, false));
|
||||
addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", true, false, true));
|
||||
addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", true, false, false));
|
||||
addEntry(LLAssetType::AT_ROOT_CATEGORY, new AssetEntry("ROOT_CATEGORY", "root", "root", false, false, false));
|
||||
addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", true, false, false));
|
||||
addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", true, false, false));
|
||||
addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", true, false, false));
|
||||
addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", true, true, true));
|
||||
addEntry(LLAssetType::AT_TRASH, new AssetEntry("TRASH", "trash", "trash", false, false, false));
|
||||
addEntry(LLAssetType::AT_SNAPSHOT_CATEGORY, new AssetEntry("SNAPSHOT_CATEGORY", "snapshot", "snapshot", false, false, false));
|
||||
addEntry(LLAssetType::AT_LOST_AND_FOUND, new AssetEntry("LOST_AND_FOUND", "lstndfnd", "lost and found", false, false, false));
|
||||
addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", true, false, false));
|
||||
addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", true, false, false));
|
||||
addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", true, false, false));
|
||||
addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", true, true, true));
|
||||
addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", true, true, true));
|
||||
addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", false, false, false));
|
||||
addEntry(LLAssetType::AT_FAVORITE, new AssetEntry("FAVORITE", "favorite", "", false, false, false));
|
||||
addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "sym link", false, false, true));
|
||||
addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true));
|
||||
addEntry(LLAssetType::AT_CURRENT_OUTFIT, new AssetEntry("FOLDER_LINK", "current", "current outfit", false, false, false));
|
||||
addEntry(LLAssetType::AT_OUTFIT, new AssetEntry("OUTFIT", "outfit", "outfit", false, false, false));
|
||||
addEntry(LLAssetType::AT_MY_OUTFITS, new AssetEntry("MY_OUTFITS", "my_otfts", "my outfits", false, false, false));
|
||||
addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, false, false, false));
|
||||
};
|
||||
|
||||
// static
|
||||
LLAssetType::EType LLAssetType::getType(const std::string& desc_name)
|
||||
{
|
||||
std::string s = desc_name;
|
||||
LLStringUtil::toUpper(s);
|
||||
for (S32 idx = 0; ;idx++)
|
||||
{
|
||||
asset_info_t* info = asset_types + idx;
|
||||
if (info->type == LLAssetType::AT_NONE)
|
||||
break;
|
||||
if (s == info->desc)
|
||||
return info->type;
|
||||
}
|
||||
return LLAssetType::AT_NONE;
|
||||
return LLAssetDictionary::getInstance()->lookup(s);
|
||||
}
|
||||
|
||||
std::string LLAssetType::getDesc(LLAssetType::EType type)
|
||||
{
|
||||
for (S32 idx = 0; ;idx++)
|
||||
{
|
||||
asset_info_t* info = asset_types + idx;
|
||||
if (type == info->type)
|
||||
return info->desc;
|
||||
if (info->type == LLAssetType::AT_NONE)
|
||||
break;
|
||||
}
|
||||
return "BAD TYPE";
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
// The asset type names are limited to 8 characters.
|
||||
// static
|
||||
const char* LLAssetType::mAssetTypeNames[LLAssetType::AT_COUNT] =
|
||||
{
|
||||
"texture",
|
||||
"sound",
|
||||
"callcard",
|
||||
"landmark",
|
||||
"script",
|
||||
"clothing",
|
||||
"object",
|
||||
"notecard",
|
||||
"category",
|
||||
"root",
|
||||
"lsltext",
|
||||
"lslbyte",
|
||||
"txtr_tga",// Intentionally spelled this way. Limited to eight characters.
|
||||
"bodypart",
|
||||
"trash",
|
||||
"snapshot",
|
||||
"lstndfnd",
|
||||
"snd_wav",
|
||||
"img_tga",
|
||||
"jpeg",
|
||||
"animatn",
|
||||
"gesture",
|
||||
"simstate",
|
||||
"favorite",
|
||||
"link",
|
||||
"link_f",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"current",
|
||||
"outfit",
|
||||
"my_otfts"
|
||||
};
|
||||
|
||||
// This table is meant for decoding to human readable form. Put any
|
||||
// and as many printable characters you want in each one.
|
||||
// See also llinventory.cpp INVENTORY_TYPE_HUMAN_NAMES
|
||||
const char* LLAssetType::mAssetTypeHumanNames[LLAssetType::AT_COUNT] =
|
||||
{
|
||||
"texture",
|
||||
"sound",
|
||||
"calling card",
|
||||
"landmark",
|
||||
"legacy script",
|
||||
"clothing",
|
||||
"object",
|
||||
"note card",
|
||||
"folder",
|
||||
"root",
|
||||
"lsl2 script",
|
||||
"lsl bytecode",
|
||||
"tga texture",
|
||||
"body part",
|
||||
"trash",
|
||||
"snapshot",
|
||||
"lost and found",
|
||||
"sound",
|
||||
"targa image",
|
||||
"jpeg image",
|
||||
"animation",
|
||||
"gesture",
|
||||
"simstate",
|
||||
"",
|
||||
"symbolic link",
|
||||
"symbolic folder link"
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"current outfit",
|
||||
"outfit",
|
||||
"my outfits"
|
||||
};
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// class LLAssetType
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
// static
|
||||
const char* LLAssetType::lookup( LLAssetType::EType type )
|
||||
const std::string &LLAssetType::getDesc(LLAssetType::EType asset_type)
|
||||
{
|
||||
if( (type >= 0) && (type < AT_COUNT ))
|
||||
const AssetEntry *entry = LLAssetDictionary::getInstance()->lookup(asset_type);
|
||||
if (entry)
|
||||
{
|
||||
return mAssetTypeNames[ S32( type ) ];
|
||||
return entry->mName;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "-1";
|
||||
return badLookup();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
const char *LLAssetType::lookup(LLAssetType::EType asset_type)
|
||||
{
|
||||
const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
|
||||
const AssetEntry *entry = dict->lookup(asset_type);
|
||||
if (entry)
|
||||
{
|
||||
return entry->mTypeName;
|
||||
}
|
||||
else
|
||||
{
|
||||
return badLookup().c_str();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,29 +151,35 @@ LLAssetType::EType LLAssetType::lookup( const char* name )
|
||||
return lookup(ll_safe_string(name));
|
||||
}
|
||||
|
||||
LLAssetType::EType LLAssetType::lookup( const std::string& name )
|
||||
// static
|
||||
LLAssetType::EType LLAssetType::lookup(const std::string& type_name)
|
||||
{
|
||||
for( S32 i = 0; i < AT_COUNT; i++ )
|
||||
const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
|
||||
for (LLAssetDictionary::const_iterator iter = dict->begin();
|
||||
iter != dict->end();
|
||||
iter++)
|
||||
{
|
||||
if( name == mAssetTypeNames[i] )
|
||||
const AssetEntry *entry = iter->second;
|
||||
if (type_name == entry->mTypeName)
|
||||
{
|
||||
// match
|
||||
return (EType)i;
|
||||
return iter->first;
|
||||
}
|
||||
}
|
||||
return AT_NONE;
|
||||
}
|
||||
|
||||
// static
|
||||
const char* LLAssetType::lookupHumanReadable(LLAssetType::EType type)
|
||||
const char *LLAssetType::lookupHumanReadable(LLAssetType::EType asset_type)
|
||||
{
|
||||
if( (type >= 0) && (type < AT_COUNT ))
|
||||
const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
|
||||
const AssetEntry *entry = dict->lookup(asset_type);
|
||||
if (entry)
|
||||
{
|
||||
return mAssetTypeHumanNames[S32(type)];
|
||||
return entry->mHumanName;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
return badLookup().c_str();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,14 +189,18 @@ LLAssetType::EType LLAssetType::lookupHumanReadable( const char* name )
|
||||
return lookupHumanReadable(ll_safe_string(name));
|
||||
}
|
||||
|
||||
LLAssetType::EType LLAssetType::lookupHumanReadable( const std::string& name )
|
||||
// static
|
||||
LLAssetType::EType LLAssetType::lookupHumanReadable(const std::string& readable_name)
|
||||
{
|
||||
for( S32 i = 0; i < AT_COUNT; i++ )
|
||||
const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
|
||||
for (LLAssetDictionary::const_iterator iter = dict->begin();
|
||||
iter != dict->end();
|
||||
iter++)
|
||||
{
|
||||
if( name == mAssetTypeHumanNames[i] )
|
||||
const AssetEntry *entry = iter->second;
|
||||
if (entry->mHumanName && (readable_name == entry->mHumanName))
|
||||
{
|
||||
// match
|
||||
return (EType)i;
|
||||
return iter->first;
|
||||
}
|
||||
}
|
||||
return AT_NONE;
|
||||
@@ -333,6 +251,16 @@ void LLAssetType::generateDescriptionFor(LLAssetType::EType type,
|
||||
// static
|
||||
bool LLAssetType::lookupCanLink(EType asset_type)
|
||||
{
|
||||
//Check that enabling all these other types as linkable doesn't break things.
|
||||
/*const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
|
||||
const AssetEntry *entry = dict->lookup(asset_type);
|
||||
if (entry)
|
||||
{
|
||||
return entry->mCanLink;
|
||||
}
|
||||
return false;
|
||||
*/
|
||||
|
||||
return (asset_type == AT_CLOTHING || asset_type == AT_OBJECT || asset_type == AT_CATEGORY ||
|
||||
asset_type == AT_BODYPART || asset_type == AT_GESTURE);
|
||||
}
|
||||
@@ -341,45 +269,42 @@ bool LLAssetType::lookupCanLink(EType asset_type)
|
||||
// Not adding this to dictionary since we probably will only have these two types
|
||||
bool LLAssetType::lookupIsLinkType(EType asset_type)
|
||||
{
|
||||
return (asset_type == AT_LINK || asset_type == AT_LINK_FOLDER);
|
||||
if (asset_type == AT_LINK || asset_type == AT_LINK_FOLDER)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
const std::string &LLAssetType::badLookup()
|
||||
{
|
||||
static const std::string sBadLookup = "llassettype_bad_lookup";
|
||||
return sBadLookup;
|
||||
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLAssetType::lookupIsAssetFetchByIDAllowed(EType asset_type)
|
||||
{
|
||||
// *FIX: Make this list smaller.
|
||||
switch(asset_type)
|
||||
const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
|
||||
const AssetEntry *entry = dict->lookup(asset_type);
|
||||
if (entry)
|
||||
{
|
||||
case LLAssetType::AT_SOUND:
|
||||
case LLAssetType::AT_LANDMARK:
|
||||
case LLAssetType::AT_CLOTHING:
|
||||
case LLAssetType::AT_BODYPART:
|
||||
case LLAssetType::AT_ANIMATION:
|
||||
case LLAssetType::AT_GESTURE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
return entry->mCanFetch;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLAssetType::lookupIsAssetIDKnowable(EType asset_type)
|
||||
{
|
||||
switch(asset_type)
|
||||
const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
|
||||
const AssetEntry *entry = dict->lookup(asset_type);
|
||||
if (entry)
|
||||
{
|
||||
case LLAssetType::AT_TEXTURE:
|
||||
case LLAssetType::AT_SOUND:
|
||||
case LLAssetType::AT_LANDMARK:
|
||||
case LLAssetType::AT_CLOTHING:
|
||||
case LLAssetType::AT_NOTECARD:
|
||||
case LLAssetType::AT_BODYPART:
|
||||
case LLAssetType::AT_ANIMATION:
|
||||
case LLAssetType::AT_GESTURE:
|
||||
case LLAssetType::AT_LINK:
|
||||
case LLAssetType::AT_LINK_FOLDER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
return entry->mCanKnow;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -160,39 +160,41 @@ public:
|
||||
};
|
||||
|
||||
// machine transation between type and strings
|
||||
static EType lookup(const char* name); // safe conversion to std::string, *TODO: deprecate
|
||||
static EType lookup(const std::string& name);
|
||||
static const char* lookup(EType type);
|
||||
static EType lookup(const char* name); // safe conversion to std::string, *TODO: deprecate
|
||||
static EType lookup(const std::string& type_name);
|
||||
static const char* lookup(EType asset_type);
|
||||
|
||||
// translation from a type to a human readable form.
|
||||
static EType lookupHumanReadable( const char* name ); // safe conversion to std::string, *TODO: deprecate
|
||||
static EType lookupHumanReadable( const std::string& name );
|
||||
static const char* lookupHumanReadable(EType type);
|
||||
static EType lookupHumanReadable(const char* desc_name); // safe conversion to std::string, *TODO: deprecate
|
||||
static EType lookupHumanReadable(const std::string& readable_name);
|
||||
static const char* lookupHumanReadable(EType asset_type);
|
||||
|
||||
static EDragAndDropType lookupDragAndDropType( EType );
|
||||
static EDragAndDropType lookupDragAndDropType( EType );
|
||||
|
||||
// Generate a good default description. You may want to add a verb
|
||||
// or agent name after this depending on your application.
|
||||
static void generateDescriptionFor(LLAssetType::EType type,
|
||||
std::string& desc);
|
||||
|
||||
static EType getType(const std::string& sin);
|
||||
static std::string getDesc(EType type);
|
||||
|
||||
static EType getType(const std::string& desc_name);
|
||||
static const std::string& getDesc(EType asset_type);
|
||||
|
||||
static bool lookupCanLink(EType asset_type);
|
||||
static bool lookupIsLinkType(EType asset_type);
|
||||
|
||||
static bool lookupIsAssetFetchByIDAllowed(EType asset_type); // the asset allows direct download
|
||||
static bool lookupIsAssetIDKnowable(EType asset_type); // asset data can be known by the viewer
|
||||
|
||||
private:
|
||||
// don't instantiate or derive one of these objects
|
||||
LLAssetType( void ) {}
|
||||
~LLAssetType( void ) {}
|
||||
static const std::string& badLookup(); // error string when a lookup fails
|
||||
|
||||
private:
|
||||
static const char* mAssetTypeNames[];
|
||||
static const char* mAssetTypeHumanNames[];
|
||||
protected:
|
||||
LLAssetType() {}
|
||||
~LLAssetType() {}
|
||||
};
|
||||
|
||||
#ifdef CWDEBUG
|
||||
#include <iosfwd>
|
||||
inline std::ostream& operator<<(std::ostream& os, LLAssetType::EType type) { return os << LLAssetType::getDesc(type); }
|
||||
#endif
|
||||
|
||||
#endif // LL_LLASSETTYPE
|
||||
|
||||
@@ -46,4 +46,18 @@
|
||||
*/
|
||||
typedef boost::tokenizer<boost::char_separator<char> > boost_tokenizer;
|
||||
|
||||
// Useful combiner for boost signals that return a bool (e.g. validation)
|
||||
// returns false if any of the callbacks return false
|
||||
struct boost_boolean_combiner
|
||||
{
|
||||
typedef bool result_type;
|
||||
template<typename InputIterator>
|
||||
bool operator()(InputIterator first, InputIterator last) const
|
||||
{
|
||||
bool res = true;
|
||||
while (first != last)
|
||||
res &= *first++;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
#endif // LL_LLBOOST_H
|
||||
|
||||
@@ -38,10 +38,13 @@
|
||||
#include "apr_time.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <locale.h>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#include "lltimer.h"
|
||||
#include "llstring.h"
|
||||
|
||||
static const F64 DATE_EPOCH = 0.0;
|
||||
|
||||
@@ -88,47 +91,40 @@ std::string LLDate::asString() const
|
||||
// is one of the standards used and the prefered format
|
||||
std::string LLDate::asRFC1123() const
|
||||
{
|
||||
std::ostringstream stream;
|
||||
toHTTPDateStream(stream);
|
||||
return stream.str();
|
||||
return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT"));
|
||||
}
|
||||
|
||||
void LLDate::toHTTPDateStream(std::ostream& s) const
|
||||
|
||||
std::string LLDate::toHTTPDateString (std::string fmt) const
|
||||
{
|
||||
// http://apr.apache.org/docs/apr/0.9/group__apr__time.html
|
||||
apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC);
|
||||
|
||||
time_t locSeconds = (time_t) mSecondsSinceEpoch;
|
||||
struct tm * gmt = gmtime (&locSeconds);
|
||||
return toHTTPDateString(gmt, fmt);
|
||||
}
|
||||
|
||||
apr_time_exp_t exp_time ; //Apache time module
|
||||
|
||||
if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS)
|
||||
{
|
||||
std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt)
|
||||
{
|
||||
// Return Epoch UTC date
|
||||
s << "Thursday, 01 Jan 1970 00:00:00 GMT" ;
|
||||
return;
|
||||
}
|
||||
|
||||
s << std::dec << std::setfill('0');
|
||||
#if( LL_WINDOWS || __GNUC__ > 2)
|
||||
s << std::right ;
|
||||
#else
|
||||
s.setf(ios::right);
|
||||
#endif
|
||||
static char const* const weekdays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
|
||||
static char const* const months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
std::string day = weekdays[exp_time.tm_wday];
|
||||
std::string month = months[exp_time.tm_mon];
|
||||
// avoid calling setlocale() unnecessarily - it's expensive.
|
||||
static std::string prev_locale = "";
|
||||
std::string this_locale = LLStringUtil::getLocale();
|
||||
if (this_locale != prev_locale)
|
||||
{
|
||||
setlocale(LC_TIME, this_locale.c_str());
|
||||
prev_locale = this_locale;
|
||||
}
|
||||
|
||||
s << std::setw(day.length()) << (day)
|
||||
<< ", " << std::setw(2) << (exp_time.tm_mday)
|
||||
<< ' ' << std::setw(month.length()) << (month)
|
||||
<< ' ' << std::setw(4) << (exp_time.tm_year + 1900)
|
||||
<< ' ' << std::setw(2) << (exp_time.tm_hour)
|
||||
<< ':' << std::setw(2) << (exp_time.tm_min)
|
||||
<< ':' << std::setw(2) << (exp_time.tm_sec)
|
||||
<< " GMT";
|
||||
|
||||
// RFC 1123 date does not use microseconds
|
||||
//llinfos << "Date in RFC 1123 format is " << s << llendl;
|
||||
// use strftime() as it appears to be faster than std::time_put
|
||||
char buffer[128];
|
||||
strftime(buffer, 128, fmt.c_str(), gmt);
|
||||
std::string res(buffer);
|
||||
#if LL_WINDOWS
|
||||
// Convert from locale-dependant charset to UTF-8 (EXT-8524).
|
||||
res = ll_convert_string_to_utf8_string(res);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
void LLDate::toStream(std::ostream& s) const
|
||||
@@ -159,7 +155,39 @@ void LLDate::toStream(std::ostream& s) const
|
||||
s << '.' << std::setw(2)
|
||||
<< (int)(exp_time.tm_usec / (LL_APR_USEC_PER_SEC / 100));
|
||||
}
|
||||
s << 'Z';
|
||||
s << 'Z'
|
||||
<< std::setfill(' ');
|
||||
}
|
||||
|
||||
bool LLDate::split(S32 *year, S32 *month, S32 *day, S32 *hour, S32 *min, S32 *sec) const
|
||||
{
|
||||
apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC);
|
||||
|
||||
apr_time_exp_t exp_time;
|
||||
if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (year)
|
||||
*year = exp_time.tm_year + 1900;
|
||||
|
||||
if (month)
|
||||
*month = exp_time.tm_mon + 1;
|
||||
|
||||
if (day)
|
||||
*day = exp_time.tm_mday;
|
||||
|
||||
if (hour)
|
||||
*hour = exp_time.tm_hour;
|
||||
|
||||
if (min)
|
||||
*min = exp_time.tm_min;
|
||||
|
||||
if (sec)
|
||||
*sec = exp_time.tm_sec;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLDate::fromString(const std::string& iso8601_date)
|
||||
@@ -223,13 +251,62 @@ bool LLDate::fromStream(std::istream& s)
|
||||
s >> fractional;
|
||||
seconds_since_epoch += fractional;
|
||||
}
|
||||
c = s.get(); // skip the Z
|
||||
if (c != 'Z') { return false; }
|
||||
|
||||
c = s.peek(); // check for offset
|
||||
if (c == '+' || c == '-')
|
||||
{
|
||||
S32 offset_sign = (c == '+') ? 1 : -1;
|
||||
S32 offset_hours = 0;
|
||||
S32 offset_minutes = 0;
|
||||
S32 offset_in_seconds = 0;
|
||||
|
||||
s >> offset_hours;
|
||||
|
||||
c = s.get(); // skip the colon a get the minutes if there are any
|
||||
if (c == ':')
|
||||
{
|
||||
s >> offset_minutes;
|
||||
}
|
||||
|
||||
offset_in_seconds = (offset_hours * 60 + offset_sign * offset_minutes) * 60;
|
||||
seconds_since_epoch -= offset_in_seconds;
|
||||
}
|
||||
else if (c != 'Z') { return false; } // skip the Z
|
||||
|
||||
mSecondsSinceEpoch = seconds_since_epoch;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLDate::fromYMDHMS(S32 year, S32 month, S32 day, S32 hour, S32 min, S32 sec)
|
||||
{
|
||||
struct apr_time_exp_t exp_time;
|
||||
|
||||
exp_time.tm_year = year - 1900;
|
||||
exp_time.tm_mon = month - 1;
|
||||
exp_time.tm_mday = day;
|
||||
exp_time.tm_hour = hour;
|
||||
exp_time.tm_min = min;
|
||||
exp_time.tm_sec = sec;
|
||||
|
||||
// zero out the unused fields
|
||||
exp_time.tm_usec = 0;
|
||||
exp_time.tm_wday = 0;
|
||||
exp_time.tm_yday = 0;
|
||||
exp_time.tm_isdst = 0;
|
||||
exp_time.tm_gmtoff = 0;
|
||||
|
||||
// generate a time_t from that
|
||||
apr_time_t time;
|
||||
if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mSecondsSinceEpoch = time / LL_APR_USEC_PER_SEC;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
F64 LLDate::secondsSinceEpoch() const
|
||||
{
|
||||
return mSecondsSinceEpoch;
|
||||
|
||||
@@ -84,7 +84,9 @@ public:
|
||||
std::string asString() const;
|
||||
std::string asRFC1123() const;
|
||||
void toStream(std::ostream&) const;
|
||||
void toHTTPDateStream(std::ostream&) const;
|
||||
bool split(S32 *year, S32 *month = NULL, S32 *day = NULL, S32 *hour = NULL, S32 *min = NULL, S32 *sec = NULL) const;
|
||||
std::string toHTTPDateString (std::string fmt) const;
|
||||
static std::string toHTTPDateString (tm * gmt, std::string fmt);
|
||||
/**
|
||||
* @brief Set the date from an ISO-8601 string.
|
||||
*
|
||||
@@ -99,6 +101,7 @@ public:
|
||||
*/
|
||||
bool fromString(const std::string& iso8601_date);
|
||||
bool fromStream(std::istream&);
|
||||
bool fromYMDHMS(S32 year, S32 month = 1, S32 day = 0, S32 hour = 0, S32 min = 0, S32 sec = 0);
|
||||
|
||||
/**
|
||||
* @brief Return the date in seconds since epoch.
|
||||
|
||||
@@ -242,5 +242,13 @@ inline LLDATATYPE llclampb(const LLDATATYPE& a)
|
||||
return llmin(llmax(a, (LLDATATYPE)0), (LLDATATYPE)255);
|
||||
}
|
||||
|
||||
template <class LLDATATYPE>
|
||||
inline void llswap(LLDATATYPE& lhs, LLDATATYPE& rhs)
|
||||
{
|
||||
LLDATATYPE tmp = lhs;
|
||||
lhs = rhs;
|
||||
rhs = tmp;
|
||||
}
|
||||
|
||||
#endif // LL_LLDEFS_H
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
# include <unistd.h>
|
||||
#endif // !LL_WINDOWS
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
#include "llapp.h"
|
||||
#include "llapr.h"
|
||||
@@ -162,7 +163,15 @@ namespace {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef CWDEBUG
|
||||
// Include normal logging in libcwd's message processing.
|
||||
// This takes care of prefixing with thread ID's, locking
|
||||
// and allows us to (temporarily) turn off normal logging
|
||||
// output.
|
||||
Dout(dc::viewer, message);
|
||||
#else
|
||||
fprintf(stderr, "%s\n", message.c_str());
|
||||
#endif
|
||||
#if LL_WINDOWS
|
||||
fflush(stderr); //Now using a buffer. flush is required.
|
||||
#endif
|
||||
@@ -1068,28 +1077,49 @@ namespace LLError
|
||||
|
||||
switch (site.mLevel)
|
||||
{
|
||||
case LEVEL_DEBUG: prefix << "DEBUG: "; break;
|
||||
case LEVEL_INFO: prefix << "INFO: "; break;
|
||||
case LEVEL_WARN: prefix << "WARNING: "; break;
|
||||
case LEVEL_ERROR: prefix << "ERROR: "; break;
|
||||
default: prefix << "XXX: "; break;
|
||||
case LEVEL_DEBUG: prefix << "DEBUG"; break;
|
||||
case LEVEL_INFO: prefix << "INFO"; break;
|
||||
case LEVEL_WARN: prefix << "WARNING"; break;
|
||||
case LEVEL_ERROR: prefix << "ERROR"; break;
|
||||
default: prefix << "XXX"; break;
|
||||
};
|
||||
|
||||
if (settings_w->printLocation)
|
||||
|
||||
bool need_function = true;
|
||||
if (site.mBroadTag && *site.mBroadTag != '\0')
|
||||
{
|
||||
prefix << abbreviateFile(site.mFile)
|
||||
<< "(" << site.mLine << ") : ";
|
||||
prefix << "(\"" << site.mBroadTag << "\")";
|
||||
#if LL_DEBUG
|
||||
// Suppress printing mFunction if mBroadTag is set, starts with
|
||||
// "Plugin " and ends with "child": a debug message from a plugin.
|
||||
size_t taglen = strlen(site.mBroadTag);
|
||||
if (taglen >= 12 && strncmp(site.mBroadTag, "Plugin ", 7) == 0 &&
|
||||
strcmp(site.mBroadTag + taglen - 5, "child") == 0)
|
||||
{
|
||||
need_function = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
prefix << ": ";
|
||||
|
||||
#if LL_WINDOWS
|
||||
// DevStudio: __FUNCTION__ already includes the full class name
|
||||
#else
|
||||
if (site.mClassInfo != typeid(NoClassInfo))
|
||||
if (need_function)
|
||||
{
|
||||
prefix << className(site.mClassInfo) << "::";
|
||||
if (settings_w->printLocation)
|
||||
{
|
||||
prefix << abbreviateFile(site.mFile)
|
||||
<< "(" << site.mLine << ") : ";
|
||||
}
|
||||
|
||||
#if LL_WINDOWS
|
||||
// DevStudio: __FUNCTION__ already includes the full class name
|
||||
#else
|
||||
if (need_function && site.mClassInfo != typeid(NoClassInfo))
|
||||
{
|
||||
prefix << className(site.mClassInfo) << "::";
|
||||
}
|
||||
#endif
|
||||
prefix << site.mFunction << ": ";
|
||||
}
|
||||
#endif
|
||||
prefix << site.mFunction << ": ";
|
||||
|
||||
if (site.mPrintOnce)
|
||||
{
|
||||
@@ -1218,6 +1248,9 @@ namespace LLError
|
||||
#endif
|
||||
void crashAndLoop(const std::string& message)
|
||||
{
|
||||
#ifdef CWDEBUG
|
||||
DoutFatal(dc::core, message);
|
||||
#else
|
||||
// Now, we go kaboom!
|
||||
int* make_me_crash = NULL;
|
||||
|
||||
@@ -1230,6 +1263,7 @@ namespace LLError
|
||||
|
||||
// this is an attempt to let Coverity and other semantic scanners know that this function won't be returning ever.
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
#if LL_WINDOWS
|
||||
#pragma optimize("", on)
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace LLError
|
||||
{ return s; }
|
||||
// used to indicate the end of a message
|
||||
|
||||
class NoClassInfo { };
|
||||
class LL_COMMON_API NoClassInfo { };
|
||||
// used to indicate no class info known for logging
|
||||
|
||||
//LLCallStacks keeps track of call stacks and output the call stacks to log file
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#ifndef LL_LLERRORLEGACY_H
|
||||
#define LL_LLERRORLEGACY_H
|
||||
|
||||
|
||||
#include "llpreprocessor.h"
|
||||
|
||||
/*
|
||||
LEGACY -- DO NOT USE THIS STUFF ANYMORE
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "linden_common.h"
|
||||
#include "llerrorthread.h"
|
||||
#include "llapp.h"
|
||||
#include "lltimer.h"
|
||||
#include "lltimer.h" // ms_sleep()
|
||||
|
||||
LLErrorThread::LLErrorThread()
|
||||
: LLThread("Error"),
|
||||
|
||||
115
indra/llcommon/lleventtimer.cpp
Normal file
115
indra/llcommon/lleventtimer.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* @file lleventtimer.cpp
|
||||
* @brief Cross-platform objects for doing timing
|
||||
*
|
||||
* $LicenseInfo:firstyear=2000&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2000-2010, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "lleventtimer.h"
|
||||
|
||||
#include "u64.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// LLEventTimer Implementation
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//std::list<LLEventTimer*> LLEventTimer::sActiveList;
|
||||
|
||||
LLEventTimer::LLEventTimer(F32 period)
|
||||
: mEventTimer()
|
||||
{
|
||||
mPeriod = period;
|
||||
//sActiveList.push_back(this);
|
||||
}
|
||||
|
||||
LLEventTimer::LLEventTimer(const LLDate& time)
|
||||
: mEventTimer()
|
||||
{
|
||||
mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch());
|
||||
//sActiveList.push_back(this);
|
||||
}
|
||||
|
||||
|
||||
LLEventTimer::~LLEventTimer()
|
||||
{
|
||||
//sActiveList.remove(this);
|
||||
}
|
||||
|
||||
//static
|
||||
void LLEventTimer::updateClass()
|
||||
{
|
||||
std::list<LLEventTimer*> completed_timers;
|
||||
|
||||
/*{
|
||||
for (std::list<LLEventTimer*>::iterator iter = sActiveList.begin(); iter != sActiveList.end(); )
|
||||
{
|
||||
LLEventTimer* timer = *iter++;
|
||||
F32 et = timer->mEventTimer.getElapsedTimeF32();
|
||||
if (timer->mEventTimer.getStarted() && et > timer->mPeriod) {
|
||||
timer->mEventTimer.reset();
|
||||
if ( timer->tick() )
|
||||
{
|
||||
completed_timers.push_back( timer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
{
|
||||
LLInstanceTrackerScopedGuard guard;
|
||||
for (instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); )
|
||||
{
|
||||
LLEventTimer& timer = *iter++;
|
||||
F32 et = timer.mEventTimer.getElapsedTimeF32();
|
||||
if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
|
||||
timer.mEventTimer.reset();
|
||||
if ( timer.tick() )
|
||||
{
|
||||
completed_timers.push_back( &timer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( completed_timers.size() > 0 )
|
||||
{
|
||||
for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin();
|
||||
completed_iter != completed_timers.end();
|
||||
completed_iter++ )
|
||||
{
|
||||
delete *completed_iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
66
indra/llcommon/lleventtimer.h
Normal file
66
indra/llcommon/lleventtimer.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @file lleventtimer.h
|
||||
* @brief Cross-platform objects for doing timing
|
||||
*
|
||||
* $LicenseInfo:firstyear=2000&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2000-2010, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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_EVENTTIMER_H
|
||||
#define LL_EVENTTIMER_H
|
||||
|
||||
#include "stdtypes.h"
|
||||
#include "lldate.h"
|
||||
#include "llinstancetracker.h"
|
||||
#include "lltimer.h"
|
||||
|
||||
// class for scheduling a function to be called at a given frequency (approximate, inprecise)
|
||||
class LL_COMMON_API LLEventTimer : public LLInstanceTracker<LLEventTimer>
|
||||
{
|
||||
public:
|
||||
LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds
|
||||
LLEventTimer(const LLDate& time);
|
||||
virtual ~LLEventTimer();
|
||||
|
||||
//function to be called at the supplied frequency
|
||||
// Normally return FALSE; TRUE will delete the timer after the function returns.
|
||||
virtual BOOL tick() = 0;
|
||||
|
||||
static void updateClass();
|
||||
|
||||
protected:
|
||||
LLTimer mEventTimer;
|
||||
F32 mPeriod;
|
||||
|
||||
//private:
|
||||
//list of active timers
|
||||
// static std::list<LLEventTimer*> sActiveList; // TODO should this be a vector
|
||||
};
|
||||
|
||||
|
||||
#endif //LL_EVENTTIMER_H
|
||||
@@ -33,13 +33,18 @@
|
||||
|
||||
#include "llfasttimer.h"
|
||||
|
||||
#include "llmemory.h"
|
||||
#include "llprocessor.h"
|
||||
|
||||
|
||||
#if LL_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include "lltimer.h"
|
||||
#elif LL_LINUX || LL_SOLARIS
|
||||
#include <sys/time.h>
|
||||
#include <sched.h>
|
||||
#include "lltimer.h"
|
||||
#elif LL_DARWIN
|
||||
#include <sys/time.h>
|
||||
#include "lltimer.h" // get_clock_count()
|
||||
@@ -65,7 +70,7 @@ S32 LLFastTimer::sLastFrameIndex = -1;
|
||||
int LLFastTimer::sPauseHistory = 0;
|
||||
int LLFastTimer::sResetHistory = 0;
|
||||
|
||||
F64 LLFastTimer::sCPUClockFrequency = 0.0;
|
||||
#define USE_RDTSC 0
|
||||
|
||||
#if LL_LINUX || LL_SOLARIS
|
||||
U64 LLFastTimer::sClockResolution = 1000000000; // 1e9, Nanosecond resolution
|
||||
@@ -73,81 +78,34 @@ U64 LLFastTimer::sClockResolution = 1000000000; // 1e9, Nanosecond resolution
|
||||
U64 LLFastTimer::sClockResolution = 1000000; // 1e6, Microsecond resolution
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// CPU clock/other clock frequency and count functions
|
||||
//
|
||||
|
||||
#if LL_WINDOWS
|
||||
|
||||
U64 get_cpu_clock_count()
|
||||
{ U32 hi,lo;
|
||||
|
||||
__asm
|
||||
{
|
||||
_emit 0x0f
|
||||
_emit 0x31
|
||||
mov lo,eax
|
||||
mov hi,edx
|
||||
}
|
||||
|
||||
U64 ret = hi;
|
||||
ret *= 4294967296L;
|
||||
ret |= lo;
|
||||
return ret;
|
||||
};
|
||||
|
||||
#endif // LL_WINDOWS
|
||||
|
||||
#if LL_LINUX || LL_SOLARIS
|
||||
// Try to use the MONOTONIC clock if available, this is a constant time counter
|
||||
// with nanosecond resolution (but not necessarily accuracy) and attempts are made
|
||||
// to synchronize this value between cores at kernel start. It should not be affected
|
||||
// by CPU frequency. If not available use the REALTIME clock, but this may be affected by
|
||||
// NTP adjustments or other user activity affecting the system time.
|
||||
U64 get_cpu_clock_count()
|
||||
{
|
||||
struct timespec tp;
|
||||
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
clock_gettime(CLOCK_MONOTONIC,&tp);
|
||||
#else
|
||||
clock_gettime(CLOCK_REALTIME,&tp);
|
||||
#endif
|
||||
return (tp.tv_sec*LLFastTimer::sClockResolution)+tp.tv_nsec;
|
||||
}
|
||||
#endif // (LL_LINUX || LL_SOLARIS))
|
||||
|
||||
#if LL_DARWIN
|
||||
//
|
||||
// Mac implementation of CPU clock
|
||||
//
|
||||
// Just use gettimeofday implementation for now
|
||||
|
||||
U64 get_cpu_clock_count()
|
||||
{
|
||||
return get_clock_count();
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//static
|
||||
#if LL_DARWIN || LL_LINUX || LL_SOLARIS
|
||||
U64 LLFastTimer::countsPerSecond()
|
||||
#if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
|
||||
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
|
||||
{
|
||||
return sClockResolution;
|
||||
return sClockResolution >> 8;
|
||||
}
|
||||
#else
|
||||
U64 LLFastTimer::countsPerSecond()
|
||||
#else // windows or x86-mac or x86-linux or x86-solaris
|
||||
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
|
||||
{
|
||||
if (!sCPUClockFrequency)
|
||||
#if USE_RDTSC || !LL_WINDOWS
|
||||
//getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz
|
||||
static U64 sCPUClockFrequency = U64(LLProcessorInfo().getCPUFrequency()*1000000.0);
|
||||
|
||||
// we drop the low-order byte in our timers, so report a lower frequency
|
||||
#else
|
||||
// If we're not using RDTSC, each fasttimer tick is just a performance counter tick.
|
||||
// Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency())
|
||||
// since that would change displayed MHz stats for CPUs
|
||||
static bool firstcall = true;
|
||||
static U64 sCPUClockFrequency;
|
||||
if (firstcall)
|
||||
{
|
||||
CProcessor proc;
|
||||
sCPUClockFrequency = proc.GetCPUFrequency(50);
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency);
|
||||
firstcall = false;
|
||||
}
|
||||
return U64(sCPUClockFrequency);
|
||||
#endif
|
||||
return sCPUClockFrequency >> 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -200,3 +158,143 @@ void LLFastTimer::reset()
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Important note: These implementations must be FAST!
|
||||
//
|
||||
|
||||
|
||||
#if LL_WINDOWS
|
||||
//
|
||||
// Windows implementation of CPU clock
|
||||
//
|
||||
|
||||
//
|
||||
// NOTE: put back in when we aren't using platform sdk anymore
|
||||
//
|
||||
// because MS has different signatures for these functions in winnt.h
|
||||
// need to rename them to avoid conflicts
|
||||
//#define _interlockedbittestandset _renamed_interlockedbittestandset
|
||||
//#define _interlockedbittestandreset _renamed_interlockedbittestandreset
|
||||
//#include <intrin.h>
|
||||
//#undef _interlockedbittestandset
|
||||
//#undef _interlockedbittestandreset
|
||||
|
||||
//inline U32 LLFastTimer::getCPUClockCount32()
|
||||
//{
|
||||
// U64 time_stamp = __rdtsc();
|
||||
// return (U32)(time_stamp >> 8);
|
||||
//}
|
||||
//
|
||||
//// return full timer value, *not* shifted by 8 bits
|
||||
//inline U64 LLFastTimer::getCPUClockCount64()
|
||||
//{
|
||||
// return __rdtsc();
|
||||
//}
|
||||
|
||||
// shift off lower 8 bits for lower resolution but longer term timing
|
||||
// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing
|
||||
#if USE_RDTSC
|
||||
U32 LLFastTimer::getCPUClockCount32()
|
||||
{
|
||||
U32 ret_val;
|
||||
__asm
|
||||
{
|
||||
_emit 0x0f
|
||||
_emit 0x31
|
||||
shr eax,8
|
||||
shl edx,24
|
||||
or eax, edx
|
||||
mov dword ptr [ret_val], eax
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
// return full timer value, *not* shifted by 8 bits
|
||||
U64 LLFastTimer::getCPUClockCount64()
|
||||
{
|
||||
U64 ret_val;
|
||||
__asm
|
||||
{
|
||||
_emit 0x0f
|
||||
_emit 0x31
|
||||
mov eax,eax
|
||||
mov edx,edx
|
||||
mov dword ptr [ret_val+4], edx
|
||||
mov dword ptr [ret_val], eax
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
std::string LLFastTimer::sClockType = "rdtsc";
|
||||
|
||||
#else
|
||||
//LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp
|
||||
// These use QueryPerformanceCounter, which is arguably fine and also works on amd architectures.
|
||||
U32 LLFastTimer::getCPUClockCount32()
|
||||
{
|
||||
return (U32)(get_clock_count()>>8);
|
||||
}
|
||||
|
||||
U64 LLFastTimer::getCPUClockCount64()
|
||||
{
|
||||
return get_clock_count();
|
||||
}
|
||||
|
||||
std::string LLFastTimer::sClockType = "QueryPerformanceCounter";
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
|
||||
//
|
||||
// Linux and Solaris implementation of CPU clock - non-x86.
|
||||
// This is accurate but SLOW! Only use out of desperation.
|
||||
//
|
||||
// Try to use the MONOTONIC clock if available, this is a constant time counter
|
||||
// with nanosecond resolution (but not necessarily accuracy) and attempts are
|
||||
// made to synchronize this value between cores at kernel start. It should not
|
||||
// be affected by CPU frequency. If not available use the REALTIME clock, but
|
||||
// this may be affected by NTP adjustments or other user activity affecting
|
||||
// the system time.
|
||||
U64 LLFastTimer::getCPUClockCount64()
|
||||
{
|
||||
struct timespec tp;
|
||||
|
||||
#ifdef CLOCK_MONOTONIC // MONOTONIC supported at build-time?
|
||||
if (-1 == clock_gettime(CLOCK_MONOTONIC,&tp)) // if MONOTONIC isn't supported at runtime then ouch, try REALTIME
|
||||
#endif
|
||||
clock_gettime(CLOCK_REALTIME,&tp);
|
||||
|
||||
return (tp.tv_sec*LLFastTimer::sClockResolution)+tp.tv_nsec;
|
||||
}
|
||||
|
||||
U32 LLFastTimer::getCPUClockCount32()
|
||||
{
|
||||
return (U32)(LLFastTimer::getCPUClockCount64() >> 8);
|
||||
}
|
||||
|
||||
std::string LLFastTimer::sClockType = "clock_gettime";
|
||||
|
||||
#endif // (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
|
||||
|
||||
|
||||
#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
|
||||
//
|
||||
// Mac+Linux+Solaris FAST x86 implementation of CPU clock
|
||||
U32 LLFastTimer::getCPUClockCount32()
|
||||
{
|
||||
U64 x;
|
||||
__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
|
||||
return (U32)(x >> 8);
|
||||
}
|
||||
|
||||
U64 LLFastTimer::getCPUClockCount64()
|
||||
{
|
||||
U64 x;
|
||||
__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
std::string LLFastTimer::sClockType = "rdtsc";
|
||||
#endif
|
||||
@@ -35,7 +35,6 @@
|
||||
|
||||
#define FAST_TIMER_ON 1
|
||||
|
||||
LL_COMMON_API U64 get_cpu_clock_count();
|
||||
|
||||
class LL_COMMON_API LLFastTimer
|
||||
{
|
||||
@@ -51,6 +50,9 @@ public:
|
||||
FTM_IDLE,
|
||||
FTM_SLEEP,
|
||||
|
||||
// general timers
|
||||
FT_STRING_FORMAT,
|
||||
|
||||
// common messaging components
|
||||
FTM_PUMP,
|
||||
FTM_CURL,
|
||||
@@ -104,7 +106,23 @@ public:
|
||||
FTM_RENDER_BLOOM,
|
||||
FTM_RENDER_BLOOM_FBO,
|
||||
FTM_RENDER_FONTS,
|
||||
|
||||
|
||||
// deferred rendering
|
||||
FTM_RENDER_DEFERRED,
|
||||
FTM_BIND_DEFERRED,
|
||||
FTM_SUN_SHADOW,
|
||||
FTM_SOFTEN_SHADOW,
|
||||
FTM_EDGE_DETECTION,
|
||||
FTM_GI_TRACE,
|
||||
FTM_GI_GATHER,
|
||||
FTM_ATMOSPHERICS,
|
||||
FTM_LOCAL_LIGHTS,
|
||||
FTM_FULLSCREEN_LIGHTS,
|
||||
FTM_PROJECTORS,
|
||||
FTM_POST,
|
||||
|
||||
FTM_VISIBLE_CLOUD,
|
||||
|
||||
// newview specific
|
||||
FTM_MESSAGES,
|
||||
FTM_MOUSEHANDLER,
|
||||
@@ -177,6 +195,7 @@ public:
|
||||
FTM_REFRESH,
|
||||
FTM_SORT,
|
||||
FTM_PICK,
|
||||
FTM_STATEMACHINE,
|
||||
|
||||
// Temp
|
||||
FTM_TEMP1,
|
||||
@@ -207,7 +226,7 @@ public:
|
||||
//gTimerBins[gCurTimerBin]++;
|
||||
//LLTimer::sNumTimerCalls++;
|
||||
|
||||
U64 cpu_clocks = get_cpu_clock_count();
|
||||
U64 cpu_clocks = getCPUClockCount64();
|
||||
|
||||
sStart[sCurDepth] = cpu_clocks;
|
||||
sCurDepth++;
|
||||
@@ -222,7 +241,7 @@ public:
|
||||
// These don't get counted, because they use CPU clockticks
|
||||
//gTimerBins[gCurTimerBin]++;
|
||||
//LLTimer::sNumTimerCalls++;
|
||||
end = get_cpu_clock_count();
|
||||
end = getCPUClockCount64();
|
||||
|
||||
sCurDepth--;
|
||||
delta = end - sStart[sCurDepth];
|
||||
@@ -237,6 +256,7 @@ public:
|
||||
static void reset();
|
||||
static U64 countsPerSecond();
|
||||
|
||||
static std::string sClockType;
|
||||
public:
|
||||
static int sCurDepth;
|
||||
static U64 sStart[FTM_MAX_DEPTH];
|
||||
@@ -246,14 +266,17 @@ public:
|
||||
static U64 sCallAverage[FTM_NUM_TYPES];
|
||||
static U64 sCountHistory[FTM_HISTORY_NUM][FTM_NUM_TYPES];
|
||||
static U64 sCallHistory[FTM_HISTORY_NUM][FTM_NUM_TYPES];
|
||||
static S32 sCurFrameIndex;
|
||||
static S32 sLastFrameIndex;
|
||||
|
||||
static int sPauseHistory;
|
||||
static int sResetHistory;
|
||||
static F64 sCPUClockFrequency;
|
||||
static U64 sClockResolution;
|
||||
|
||||
private:
|
||||
static U32 getCPUClockCount32();
|
||||
static U64 getCPUClockCount64();
|
||||
|
||||
static U64 sClockResolution;
|
||||
static S32 sCurFrameIndex;
|
||||
static S32 sLastFrameIndex;
|
||||
|
||||
EFastTimerType mType;
|
||||
};
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ public:
|
||||
* and should only be used for config files and the like -- not in a
|
||||
* loop.
|
||||
*/
|
||||
std::streamsize llifstream_size(llifstream& fstr);
|
||||
std::streamsize llofstream_size(llofstream& fstr);
|
||||
std::streamsize LL_COMMON_API llifstream_size(llifstream& fstr);
|
||||
std::streamsize LL_COMMON_API llofstream_size(llofstream& fstr);
|
||||
|
||||
#endif // not LL_LLFILE_H
|
||||
|
||||
@@ -37,17 +37,41 @@
|
||||
|
||||
#include <cstdarg>
|
||||
|
||||
std::string llformat(const char *fmt, ...)
|
||||
// common used function with va_list argument
|
||||
// wrapper for vsnprintf to be called from llformatXXX functions.
|
||||
static void va_format(std::string& out, const char *fmt, va_list va)
|
||||
{
|
||||
char tstr[1024]; /* Flawfinder: ignore */
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
#if LL_WINDOWS
|
||||
_vsnprintf(tstr, 1024, fmt, va);
|
||||
#else
|
||||
vsnprintf(tstr, 1024, fmt, va); /* Flawfinder: ignore */
|
||||
#endif
|
||||
va_end(va);
|
||||
tstr[1023] = '\0';
|
||||
return std::string(tstr);
|
||||
out.assign(tstr);
|
||||
}
|
||||
|
||||
std::string llformat(const char *fmt, ...)
|
||||
{
|
||||
std::string res;
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
va_format(res, fmt, va);
|
||||
va_end(va);
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string llformat_to_utf8(const char *fmt, ...)
|
||||
{
|
||||
std::string res;
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
va_format(res, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
#if LL_WINDOWS
|
||||
// made converting to utf8. See EXT-8318.
|
||||
res = ll_convert_string_to_utf8_string(res);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
// *NOTE: buffer limited to 1024, (but vsnprintf prevents overrun)
|
||||
// should perhaps be replaced with boost::format.
|
||||
|
||||
LL_COMMON_API std::string llformat(const char *fmt, ...);
|
||||
std::string LL_COMMON_API llformat(const char *fmt, ...);
|
||||
|
||||
// the same version as above but ensures that returned string is in utf8 on windows
|
||||
// to enable correct converting utf8_to_wstring.
|
||||
std::string LL_COMMON_API llformat_to_utf8(const char *fmt, ...);
|
||||
#endif // LL_LLFORMAT_H
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
#ifndef LL_LLINDRACONFIGFILE_H
|
||||
#define LL_LLINDRACONFIGFILE_H
|
||||
|
||||
#include <string>
|
||||
#include "linden_common.h"
|
||||
#include <string>
|
||||
|
||||
#include "lllivefile.h"
|
||||
#include "llsd.h"
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
/**
|
||||
* @file dummy_volume_catcher.cpp
|
||||
* @brief A null implementation of the "VolumeCatcher" class for platforms where it's not implemented yet.
|
||||
*
|
||||
* @cond
|
||||
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
||||
/**
|
||||
* @file lllinstancetracker.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
@@ -23,36 +21,27 @@
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
#include "volume_catcher.h"
|
||||
// Precompiled header
|
||||
#include "linden_common.h"
|
||||
// associated header
|
||||
#include "llinstancetracker.h"
|
||||
// STL headers
|
||||
// std headers
|
||||
// external library headers
|
||||
// other Linden headers
|
||||
|
||||
|
||||
class VolumeCatcherImpl
|
||||
//static
|
||||
void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)
|
||||
{
|
||||
};
|
||||
static std::map<std::string, void *> instances;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
std::string k = info.name();
|
||||
if(instances.find(k) == instances.end())
|
||||
{
|
||||
instances[k] = NULL;
|
||||
}
|
||||
|
||||
VolumeCatcher::VolumeCatcher()
|
||||
{
|
||||
pimpl = NULL;
|
||||
return instances[k];
|
||||
}
|
||||
|
||||
VolumeCatcher::~VolumeCatcher()
|
||||
{
|
||||
}
|
||||
|
||||
void VolumeCatcher::setVolume(F32 volume)
|
||||
{
|
||||
}
|
||||
|
||||
void VolumeCatcher::setPan(F32 pan)
|
||||
{
|
||||
}
|
||||
|
||||
void VolumeCatcher::pump()
|
||||
{
|
||||
}
|
||||
|
||||
202
indra/llcommon/llinstancetracker.h
Normal file
202
indra/llcommon/llinstancetracker.h
Normal file
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* @file llinstancetracker.h
|
||||
* @brief LLInstanceTracker is a mixin class that automatically tracks object
|
||||
* instances with or without an associated key
|
||||
*
|
||||
* $LicenseInfo:firstyear=2000&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2000-2010, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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_LLINSTANCETRACKER_H
|
||||
#define LL_LLINSTANCETRACKER_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "string_table.h"
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
#include <boost/iterator/indirect_iterator.hpp>
|
||||
|
||||
class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
|
||||
{
|
||||
protected:
|
||||
static void * & getInstances(std::type_info const & info);
|
||||
};
|
||||
/// This mix-in class adds support for tracking all instances of the specified class parameter T
|
||||
/// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
|
||||
/// If KEY is not provided, then instances are stored in a simple set
|
||||
/// @NOTE: see explicit specialization below for default KEY==T* case
|
||||
template<typename T, typename KEY = T*>
|
||||
class LLInstanceTracker : public LLInstanceTrackerBase
|
||||
{
|
||||
typedef typename std::map<KEY, T*> InstanceMap;
|
||||
typedef LLInstanceTracker<T, KEY> MyT;
|
||||
typedef boost::function<const KEY&(typename InstanceMap::value_type&)> KeyGetter;
|
||||
typedef boost::function<T*(typename InstanceMap::value_type&)> InstancePtrGetter;
|
||||
public:
|
||||
/// Dereferencing key_iter gives you a const KEY&
|
||||
typedef boost::transform_iterator<KeyGetter, typename InstanceMap::iterator> key_iter;
|
||||
/// Dereferencing instance_iter gives you a T&
|
||||
typedef boost::indirect_iterator< boost::transform_iterator<InstancePtrGetter, typename InstanceMap::iterator> > instance_iter;
|
||||
|
||||
static T* getInstance(const KEY& k)
|
||||
{
|
||||
typename InstanceMap::const_iterator found = getMap_().find(k);
|
||||
return (found == getMap_().end()) ? NULL : found->second;
|
||||
}
|
||||
|
||||
static key_iter beginKeys()
|
||||
{
|
||||
return boost::make_transform_iterator(getMap_().begin(),
|
||||
boost::bind(&InstanceMap::value_type::first, _1));
|
||||
}
|
||||
static key_iter endKeys()
|
||||
{
|
||||
return boost::make_transform_iterator(getMap_().end(),
|
||||
boost::bind(&InstanceMap::value_type::first, _1));
|
||||
}
|
||||
static instance_iter beginInstances()
|
||||
{
|
||||
return instance_iter(boost::make_transform_iterator(getMap_().begin(),
|
||||
boost::bind(&InstanceMap::value_type::second, _1)));
|
||||
}
|
||||
static instance_iter endInstances()
|
||||
{
|
||||
return instance_iter(boost::make_transform_iterator(getMap_().end(),
|
||||
boost::bind(&InstanceMap::value_type::second, _1)));
|
||||
}
|
||||
static S32 instanceCount() { return getMap_().size(); }
|
||||
protected:
|
||||
LLInstanceTracker(KEY key) { add_(key); }
|
||||
virtual ~LLInstanceTracker() { remove_(); }
|
||||
virtual void setKey(KEY key) { remove_(); add_(key); }
|
||||
virtual const KEY& getKey() const { return mKey; }
|
||||
|
||||
private:
|
||||
void add_(KEY key)
|
||||
{
|
||||
mKey = key;
|
||||
getMap_()[key] = static_cast<T*>(this);
|
||||
}
|
||||
void remove_()
|
||||
{
|
||||
getMap_().erase(mKey);
|
||||
}
|
||||
|
||||
static InstanceMap& getMap_()
|
||||
{
|
||||
void * & instances = getInstances(typeid(MyT));
|
||||
if (! instances)
|
||||
{
|
||||
instances = new InstanceMap;
|
||||
}
|
||||
return * static_cast<InstanceMap*>(instances);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
KEY mKey;
|
||||
};
|
||||
|
||||
/// explicit specialization for default case where KEY is T*
|
||||
/// use a simple std::set<T*>
|
||||
template<typename T>
|
||||
class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
|
||||
{
|
||||
typedef typename std::set<T*> InstanceSet;
|
||||
typedef LLInstanceTracker<T, T*> MyT;
|
||||
public:
|
||||
/// Dereferencing key_iter gives you a T* (since T* is the key)
|
||||
typedef typename InstanceSet::iterator key_iter;
|
||||
/// Dereferencing instance_iter gives you a T&
|
||||
typedef boost::indirect_iterator<key_iter> instance_iter;
|
||||
|
||||
/// for completeness of analogy with the generic implementation
|
||||
static T* getInstance(T* k) { return k; }
|
||||
static S32 instanceCount() { return getSet_().size(); }
|
||||
|
||||
// Instantiate this to get access to iterators for this type. It's a 'guard' in the sense
|
||||
// that it treats deletes of this type as errors as long as there is an instance of
|
||||
// this class alive in scope somewhere (i.e. deleting while iterating is bad).
|
||||
class LLInstanceTrackerScopedGuard
|
||||
{
|
||||
public:
|
||||
LLInstanceTrackerScopedGuard()
|
||||
{
|
||||
++sIterationNestDepth;
|
||||
}
|
||||
|
||||
~LLInstanceTrackerScopedGuard()
|
||||
{
|
||||
--sIterationNestDepth;
|
||||
}
|
||||
|
||||
static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
|
||||
static instance_iter endInstances() { return instance_iter(getSet_().end()); }
|
||||
static key_iter beginKeys() { return getSet_().begin(); }
|
||||
static key_iter endKeys() { return getSet_().end(); }
|
||||
};
|
||||
|
||||
protected:
|
||||
LLInstanceTracker()
|
||||
{
|
||||
// it's safe but unpredictable to create instances of this type while all instances are being iterated over. I hate unpredictable. This assert will probably be turned on early in the next development cycle.
|
||||
//llassert(sIterationNestDepth == 0);
|
||||
getSet_().insert(static_cast<T*>(this));
|
||||
}
|
||||
virtual ~LLInstanceTracker()
|
||||
{
|
||||
// it's unsafe to delete instances of this type while all instances are being iterated over.
|
||||
llassert(sIterationNestDepth == 0);
|
||||
getSet_().erase(static_cast<T*>(this));
|
||||
}
|
||||
|
||||
LLInstanceTracker(const LLInstanceTracker& other)
|
||||
{
|
||||
//llassert(sIterationNestDepth == 0);
|
||||
getSet_().insert(static_cast<T*>(this));
|
||||
}
|
||||
|
||||
static InstanceSet& getSet_()
|
||||
{
|
||||
void * & instances = getInstances(typeid(MyT));
|
||||
if (! instances)
|
||||
{
|
||||
instances = new InstanceSet;
|
||||
}
|
||||
return * static_cast<InstanceSet *>(instances);
|
||||
}
|
||||
|
||||
static S32 sIterationNestDepth;
|
||||
};
|
||||
|
||||
template <typename T> S32 LLInstanceTracker<T, T*>::sIterationNestDepth = 0;
|
||||
|
||||
#endif
|
||||
@@ -38,9 +38,12 @@
|
||||
#include "llsd.h"
|
||||
#include "llsdserialize.h"
|
||||
|
||||
LLLiveAppConfig::LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period)
|
||||
: LLLiveFile(filename, refresh_period),
|
||||
mApp(app)
|
||||
LLLiveAppConfig::LLLiveAppConfig(
|
||||
const std::string& filename,
|
||||
F32 refresh_period,
|
||||
LLApp::OptionPriority priority) :
|
||||
LLLiveFile(filename, refresh_period),
|
||||
mPriority(priority)
|
||||
{ }
|
||||
|
||||
|
||||
@@ -77,7 +80,7 @@ bool LLLiveAppConfig::loadFile()
|
||||
// to set the config to an empty config, and return that it
|
||||
// changed.
|
||||
|
||||
mApp->setOptionData(
|
||||
LLApp::PRIORITY_SPECIFIC_CONFIGURATION, config);
|
||||
LLApp* app = LLApp::instance();
|
||||
if(app) app->setOptionData(mPriority, config);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -33,25 +33,43 @@
|
||||
#ifndef LLLIVEAPPCONFIG_H
|
||||
#define LLLIVEAPPCONFIG_H
|
||||
|
||||
#include "llapp.h"
|
||||
#include "lllivefile.h"
|
||||
|
||||
class LLApp;
|
||||
|
||||
/**
|
||||
* @class LLLiveAppConfig
|
||||
* @see LLLiveFile
|
||||
*
|
||||
* To use this, instantiate a LLLiveAppConfig object inside your main
|
||||
* loop. The traditional name for it is live_config. Be sure to call
|
||||
* <code>live_config.checkAndReload()</code> periodically.
|
||||
*/
|
||||
class LL_COMMON_API LLLiveAppConfig : public LLLiveFile
|
||||
{
|
||||
public:
|
||||
// To use this, instantiate a LLLiveAppConfig object inside your main loop.
|
||||
// The traditional name for it is live_config.
|
||||
// Be sure to call live_config.checkAndReload() periodically.
|
||||
|
||||
LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period);
|
||||
~LLLiveAppConfig();
|
||||
/**
|
||||
* @brief Constructor
|
||||
*
|
||||
* @param filename. The name of the file for periodically checking
|
||||
* configuration.
|
||||
* @param refresh_period How often the internal timer should
|
||||
* bother checking the filesystem.
|
||||
* @param The application priority level of that configuration file.
|
||||
*/
|
||||
LLLiveAppConfig(
|
||||
const std::string& filename,
|
||||
F32 refresh_period,
|
||||
LLApp::OptionPriority priority);
|
||||
|
||||
~LLLiveAppConfig(); ///< Destructor
|
||||
|
||||
protected:
|
||||
/*virtual*/ bool loadFile();
|
||||
|
||||
private:
|
||||
LLApp* mApp;
|
||||
LLApp::OptionPriority mPriority;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
#include "lllivefile.h"
|
||||
#include "llframetimer.h"
|
||||
#include "lltimer.h"
|
||||
#include "lleventtimer.h"
|
||||
|
||||
const F32 DEFAULT_CONFIG_FILE_REFRESH = 5.0f;
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ documentation and/or software.
|
||||
#include "llmd5.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <iostream> // cerr
|
||||
|
||||
// how many bytes to grab at a time when checking files
|
||||
const int LLMD5::BLOCK_LEN = 4096;
|
||||
|
||||
@@ -108,9 +108,8 @@ public:
|
||||
// methods to acquire finalized result
|
||||
void raw_digest(unsigned char *array) const; // provide 16-byte array for binary data
|
||||
void hex_digest(char *string) const; // provide 33-byte array for ascii-hex string
|
||||
friend std::ostream& operator<< (std::ostream&, LLMD5 context);
|
||||
|
||||
|
||||
friend LL_COMMON_API std::ostream& operator<< (std::ostream&, LLMD5 context);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ void LLMetricsImpl::recordEventDetails(const std::string& location,
|
||||
metrics["location"] = location;
|
||||
metrics["stats"] = stats;
|
||||
|
||||
llinfos << "LLMETRICS: " << LLSDNotationStreamer(metrics) << llendl;
|
||||
llinfos << "LLMETRICS: " << (LLSDNotationStreamer(metrics)) << llendl;
|
||||
}
|
||||
|
||||
// Store this:
|
||||
|
||||
@@ -32,7 +32,11 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <apr_file_io.h>
|
||||
#include <apr_thread_proc.h>
|
||||
#include "llprocesslauncher.h"
|
||||
#include "aiaprpool.h"
|
||||
|
||||
#include <iostream>
|
||||
#if LL_DARWIN || LL_LINUX
|
||||
@@ -64,6 +68,11 @@ void LLProcessLauncher::setWorkingDirectory(const std::string &dir)
|
||||
mWorkingDir = dir;
|
||||
}
|
||||
|
||||
const std::string& LLProcessLauncher::getExecutable() const
|
||||
{
|
||||
return mExecutable;
|
||||
}
|
||||
|
||||
void LLProcessLauncher::clearArguments()
|
||||
{
|
||||
mLaunchArguments.clear();
|
||||
@@ -142,6 +151,7 @@ bool LLProcessLauncher::isRunning(void)
|
||||
|
||||
return (mProcessHandle != 0);
|
||||
}
|
||||
|
||||
bool LLProcessLauncher::kill(void)
|
||||
{
|
||||
bool result = true;
|
||||
@@ -201,6 +211,79 @@ static bool reap_pid(pid_t pid)
|
||||
return result;
|
||||
}
|
||||
|
||||
#if LL_DEBUG
|
||||
// Define this to create a temporary pipe(2) between parent and child process, so
|
||||
// that the child process can report error messages that it encounters when
|
||||
// trying to execve(2). Most notably failing to start due to missing libraries
|
||||
// or undefined symbols.
|
||||
#define DEBUG_PIPE_CHILD_ERROR_REPORTING 1
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING
|
||||
|
||||
// Called by child process.
|
||||
static void write_pipe(apr_file_t* out, char const* message)
|
||||
{
|
||||
apr_size_t const bytes_to_write = strlen(message) + 1; // +1 for the length byte.
|
||||
assert(bytes_to_write < 256);
|
||||
char buf[256];
|
||||
strncpy(buf + 1, message, sizeof(buf) - 1);
|
||||
*reinterpret_cast<unsigned char*>(buf) = bytes_to_write - 1;
|
||||
|
||||
apr_size_t bytes_written;
|
||||
apr_status_t status = apr_file_write_full(out, buf, bytes_to_write, &bytes_written);
|
||||
if (status != APR_SUCCESS)
|
||||
{
|
||||
std::cerr << "apr_file_write_full: " << apr_strerror(status, buf, sizeof(buf)) << std::endl;
|
||||
}
|
||||
else if (bytes_written != bytes_to_write)
|
||||
{
|
||||
std::cerr << "apr_file_write_full: bytes_written (" << bytes_written << ") != bytes_to_write (" << bytes_to_write << ")!" << std::endl;
|
||||
}
|
||||
status = apr_file_flush(out);
|
||||
if (status != APR_SUCCESS)
|
||||
{
|
||||
std::cerr << "apr_file_flush: " << apr_strerror(status, buf, sizeof(buf)) << std::endl;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "apr_file_write_full: Wrote " << bytes_written << " bytes to the pipe." << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Called by parent process.
|
||||
static std::string read_pipe(apr_file_t* in, bool timeout_ok = false)
|
||||
{
|
||||
char buf[256];
|
||||
unsigned char bytes_to_read;
|
||||
apr_size_t bytes_read;
|
||||
apr_status_t status = apr_file_read_full(in, &bytes_to_read, 1, &bytes_read);
|
||||
if (status != APR_SUCCESS)
|
||||
{
|
||||
if (APR_STATUS_IS_TIMEUP(status) && timeout_ok)
|
||||
{
|
||||
return "TIMEOUT";
|
||||
}
|
||||
llwarns << "apr_file_read_full: " << apr_strerror(status, buf, sizeof(buf)) << llendl;
|
||||
assert(APR_STATUS_IS_EOF(status));
|
||||
return "END OF FILE";
|
||||
}
|
||||
assert(bytes_read == 1);
|
||||
status = apr_file_read_full(in, buf, bytes_to_read, &bytes_read);
|
||||
if (status != APR_SUCCESS)
|
||||
{
|
||||
llwarns << "apr_file_read_full: " << apr_strerror(status, buf, sizeof(buf)) << llendl;
|
||||
assert(status == APR_SUCCESS); // Fail
|
||||
}
|
||||
assert(bytes_read == bytes_to_read);
|
||||
|
||||
std::string received(buf, bytes_read);
|
||||
llinfos << "Received: \"" << received << "\" (bytes read: " << bytes_read << ")" << llendl;
|
||||
return received;
|
||||
}
|
||||
|
||||
#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING
|
||||
|
||||
int LLProcessLauncher::launch(void)
|
||||
{
|
||||
// If there was already a process associated with this object, kill it.
|
||||
@@ -237,23 +320,96 @@ int LLProcessLauncher::launch(void)
|
||||
}
|
||||
}
|
||||
|
||||
// flush all buffers before the child inherits them
|
||||
::fflush(NULL);
|
||||
|
||||
pid_t id = vfork();
|
||||
if(id == 0)
|
||||
pid_t id;
|
||||
{
|
||||
// child process
|
||||
|
||||
::execv(mExecutable.c_str(), (char * const *)fake_argv);
|
||||
|
||||
// If we reach this point, the exec failed.
|
||||
// Use _exit() instead of exit() per the vfork man page.
|
||||
_exit(0);
|
||||
#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING
|
||||
// Set up a pipe to the child process for error reporting.
|
||||
apr_file_t* in;
|
||||
apr_file_t* out;
|
||||
AIAPRPool pool;
|
||||
pool.create();
|
||||
apr_status_t status = apr_file_pipe_create_ex(&in, &out, APR_FULL_BLOCK, pool());
|
||||
assert(status == APR_SUCCESS);
|
||||
bool success = (status == APR_SUCCESS);
|
||||
if (success)
|
||||
{
|
||||
apr_interval_time_t const timeout = 10000000; // 10 seconds.
|
||||
status = apr_file_pipe_timeout_set(in, timeout);
|
||||
assert(status == APR_SUCCESS);
|
||||
success = (status == APR_SUCCESS);
|
||||
}
|
||||
#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING
|
||||
|
||||
// flush all buffers before the child inherits them
|
||||
::fflush(NULL);
|
||||
|
||||
id = vfork();
|
||||
if (id == 0)
|
||||
{
|
||||
// child process
|
||||
|
||||
#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING
|
||||
// Tell parent process we're about to call execv.
|
||||
write_pipe(out, "CALLING EXECV");
|
||||
#ifdef _DEBUG
|
||||
char const* display = getenv("DISPLAY");
|
||||
std::cerr << "Calling ::execv(\"" << mExecutable << '"';
|
||||
for(int j = 0; j < i; ++j)
|
||||
std::cerr << ", \"" << fake_argv[j] << '"';
|
||||
std::cerr << ") with DISPLAY=\"" << (display ? display : "NULL") << '"' << std::endl;
|
||||
#endif
|
||||
#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING
|
||||
|
||||
::execv(mExecutable.c_str(), (char * const *)fake_argv);
|
||||
|
||||
#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING
|
||||
status = APR_FROM_OS_ERROR(apr_get_os_error());
|
||||
char message[256];
|
||||
char errbuf[128];
|
||||
apr_strerror(status, errbuf, sizeof(errbuf));
|
||||
snprintf(message, sizeof(message), "Child process: execv: %s: %s", mExecutable.c_str(), errbuf);
|
||||
write_pipe(out, message);
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "::execv() failed." << std::endl;
|
||||
#endif
|
||||
#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING
|
||||
|
||||
// If we reach this point, the exec failed.
|
||||
// Use _exit() instead of exit() per the vfork man page.
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
// parent process
|
||||
|
||||
#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING
|
||||
// Close unused pipe end.
|
||||
apr_file_close(out);
|
||||
|
||||
if (success)
|
||||
{
|
||||
// Attempt to do error reporting.
|
||||
std::string message = read_pipe(in);
|
||||
success = (message == "CALLING EXECV");
|
||||
assert(success);
|
||||
if (success)
|
||||
{
|
||||
status = apr_file_pipe_timeout_set(in, 2000000); // Only wait 2 seconds.
|
||||
message = read_pipe(in, true);
|
||||
if (message != "TIMEOUT" && message != "END OF FILE")
|
||||
{
|
||||
// Most likely execv failed.
|
||||
llwarns << message << llendl;
|
||||
assert(false); // Fail in debug mode.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up.
|
||||
apr_file_close(in);
|
||||
#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING
|
||||
|
||||
}
|
||||
|
||||
// parent process
|
||||
|
||||
if(current_wd >= 0)
|
||||
{
|
||||
// restore the previous working directory
|
||||
|
||||
@@ -53,6 +53,8 @@ public:
|
||||
void setExecutable(const std::string &executable);
|
||||
void setWorkingDirectory(const std::string &dir);
|
||||
|
||||
const std::string& getExecutable() const;
|
||||
|
||||
void clearArguments();
|
||||
void addArgument(const std::string &arg);
|
||||
void addArgument(const char *arg);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -30,166 +30,26 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// Author: Benjamin Jurke
|
||||
// File history: 27.02.2002 File created.
|
||||
///////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef LLPROCESSOR_H
|
||||
#define LLPROCESSOR_H
|
||||
class LLProcessorInfoImpl;
|
||||
|
||||
// Options:
|
||||
///////////
|
||||
#if LL_WINDOWS
|
||||
#define PROCESSOR_FREQUENCY_MEASURE_AVAILABLE
|
||||
#endif
|
||||
|
||||
#if LL_MSVC && _M_X64
|
||||
# define LL_X86_64 1
|
||||
# define LL_X86 1
|
||||
#elif LL_MSVC && _M_IX86
|
||||
# define LL_X86 1
|
||||
#elif LL_GNUC && ( defined(__amd64__) || defined(__x86_64__) )
|
||||
# define LL_X86_64 1
|
||||
# define LL_X86 1
|
||||
#elif LL_GNUC && ( defined(__i386__) )
|
||||
# define LL_X86 1
|
||||
#elif LL_GNUC && ( defined(__powerpc__) || defined(__ppc__) )
|
||||
# define LL_PPC 1
|
||||
#endif
|
||||
|
||||
|
||||
struct ProcessorExtensions
|
||||
class LL_COMMON_API LLProcessorInfo
|
||||
{
|
||||
bool FPU_FloatingPointUnit;
|
||||
bool VME_Virtual8086ModeEnhancements;
|
||||
bool DE_DebuggingExtensions;
|
||||
bool PSE_PageSizeExtensions;
|
||||
bool TSC_TimeStampCounter;
|
||||
bool MSR_ModelSpecificRegisters;
|
||||
bool PAE_PhysicalAddressExtension;
|
||||
bool MCE_MachineCheckException;
|
||||
bool CX8_COMPXCHG8B_Instruction;
|
||||
bool APIC_AdvancedProgrammableInterruptController;
|
||||
unsigned int APIC_ID;
|
||||
bool SEP_FastSystemCall;
|
||||
bool MTRR_MemoryTypeRangeRegisters;
|
||||
bool PGE_PTE_GlobalFlag;
|
||||
bool MCA_MachineCheckArchitecture;
|
||||
bool CMOV_ConditionalMoveAndCompareInstructions;
|
||||
bool FGPAT_PageAttributeTable;
|
||||
bool PSE36_36bitPageSizeExtension;
|
||||
bool PN_ProcessorSerialNumber;
|
||||
bool CLFSH_CFLUSH_Instruction;
|
||||
unsigned int CLFLUSH_InstructionCacheLineSize;
|
||||
bool DS_DebugStore;
|
||||
bool ACPI_ThermalMonitorAndClockControl;
|
||||
bool EMMX_MultimediaExtensions;
|
||||
bool MMX_MultimediaExtensions;
|
||||
bool FXSR_FastStreamingSIMD_ExtensionsSaveRestore;
|
||||
bool SSE_StreamingSIMD_Extensions;
|
||||
bool SSE2_StreamingSIMD2_Extensions;
|
||||
bool Altivec_Extensions;
|
||||
bool SS_SelfSnoop;
|
||||
bool HT_HyperThreading;
|
||||
unsigned int HT_HyterThreadingSiblings;
|
||||
bool TM_ThermalMonitor;
|
||||
bool IA64_Intel64BitArchitecture;
|
||||
bool _3DNOW_InstructionExtensions;
|
||||
bool _E3DNOW_InstructionExtensions;
|
||||
bool AA64_AMD64BitArchitecture;
|
||||
};
|
||||
|
||||
struct ProcessorCache
|
||||
{
|
||||
bool bPresent;
|
||||
char strSize[32]; /* Flawfinder: ignore */
|
||||
unsigned int uiAssociativeWays;
|
||||
unsigned int uiLineSize;
|
||||
bool bSectored;
|
||||
char strCache[128]; /* Flawfinder: ignore */
|
||||
};
|
||||
|
||||
struct ProcessorL1Cache
|
||||
{
|
||||
ProcessorCache Instruction;
|
||||
ProcessorCache Data;
|
||||
};
|
||||
|
||||
struct ProcessorTLB
|
||||
{
|
||||
bool bPresent;
|
||||
char strPageSize[32]; /* Flawfinder: ignore */
|
||||
unsigned int uiAssociativeWays;
|
||||
unsigned int uiEntries;
|
||||
char strTLB[128]; /* Flawfinder: ignore */
|
||||
};
|
||||
|
||||
struct ProcessorInfo
|
||||
{
|
||||
char strVendor[16]; /* Flawfinder: ignore */
|
||||
unsigned int uiFamily;
|
||||
unsigned int uiExtendedFamily;
|
||||
char strFamily[64]; /* Flawfinder: ignore */
|
||||
unsigned int uiModel;
|
||||
unsigned int uiExtendedModel;
|
||||
char strModel[128]; /* Flawfinder: ignore */
|
||||
unsigned int uiStepping;
|
||||
unsigned int uiType;
|
||||
char strType[64]; /* Flawfinder: ignore */
|
||||
unsigned int uiBrandID;
|
||||
char strBrandID[64]; /* Flawfinder: ignore */
|
||||
char strProcessorSerial[64]; /* Flawfinder: ignore */
|
||||
unsigned long MaxSupportedLevel;
|
||||
unsigned long MaxSupportedExtendedLevel;
|
||||
ProcessorExtensions _Ext;
|
||||
ProcessorL1Cache _L1;
|
||||
ProcessorCache _L2;
|
||||
ProcessorCache _L3;
|
||||
ProcessorCache _Trace;
|
||||
ProcessorTLB _Instruction;
|
||||
ProcessorTLB _Data;
|
||||
};
|
||||
|
||||
|
||||
// CProcessor
|
||||
// ==========
|
||||
// Class for detecting the processor name, type and available
|
||||
// extensions as long as it's speed.
|
||||
/////////////////////////////////////////////////////////////
|
||||
class CProcessor
|
||||
{
|
||||
// Constructor / Destructor:
|
||||
////////////////////////////
|
||||
public:
|
||||
CProcessor();
|
||||
LLProcessorInfo();
|
||||
~LLProcessorInfo();
|
||||
|
||||
// Private vars:
|
||||
////////////////
|
||||
public:
|
||||
F64 uqwFrequency;
|
||||
char strCPUName[128]; /* Flawfinder: ignore */
|
||||
ProcessorInfo CPUInfo;
|
||||
|
||||
// Private functions:
|
||||
/////////////////////
|
||||
F64 getCPUFrequency() const;
|
||||
bool hasSSE() const;
|
||||
bool hasSSE2() const;
|
||||
bool hasAltivec() const;
|
||||
std::string getCPUFamilyName() const;
|
||||
std::string getCPUBrandName() const;
|
||||
std::string getCPUFeatureDescription() const;
|
||||
private:
|
||||
bool AnalyzeIntelProcessor();
|
||||
bool AnalyzeAMDProcessor();
|
||||
bool AnalyzeUnknownProcessor();
|
||||
bool CheckCPUIDPresence();
|
||||
void DecodeProcessorConfiguration(unsigned int cfg);
|
||||
void TranslateProcessorConfiguration();
|
||||
void GetStandardProcessorConfiguration();
|
||||
void GetStandardProcessorExtensions();
|
||||
|
||||
// Public functions:
|
||||
////////////////////
|
||||
public:
|
||||
F64 GetCPUFrequency(unsigned int uiMeasureMSecs);
|
||||
const ProcessorInfo *GetCPUInfo();
|
||||
bool CPUInfoToText(char *strBuffer, unsigned int uiMaxLen);
|
||||
bool WriteInfoTextFile(const std::string& strFilename);
|
||||
LLProcessorInfoImpl* mImpl;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -65,32 +65,32 @@
|
||||
/**
|
||||
*@brief Generate a float from [0, RAND_MAX).
|
||||
*/
|
||||
LL_COMMON_API S32 ll_rand();
|
||||
S32 LL_COMMON_API ll_rand();
|
||||
|
||||
/**
|
||||
*@brief Generate a float from [0, val) or (val, 0].
|
||||
*/
|
||||
LL_COMMON_API S32 ll_rand(S32 val);
|
||||
S32 LL_COMMON_API ll_rand(S32 val);
|
||||
|
||||
/**
|
||||
*@brief Generate a float from [0, 1.0).
|
||||
*/
|
||||
LL_COMMON_API F32 ll_frand();
|
||||
F32 LL_COMMON_API ll_frand();
|
||||
|
||||
/**
|
||||
*@brief Generate a float from [0, val) or (val, 0].
|
||||
*/
|
||||
LL_COMMON_API F32 ll_frand(F32 val);
|
||||
F32 LL_COMMON_API ll_frand(F32 val);
|
||||
|
||||
/**
|
||||
*@brief Generate a double from [0, 1.0).
|
||||
*/
|
||||
LL_COMMON_API F64 ll_drand();
|
||||
F64 LL_COMMON_API ll_drand();
|
||||
|
||||
/**
|
||||
*@brief Generate a double from [0, val) or (val, 0].
|
||||
*/
|
||||
LL_COMMON_API F64 ll_drand(F64 val);
|
||||
F64 LL_COMMON_API ll_drand(F64 val);
|
||||
|
||||
/**
|
||||
* @brief typedefs for good boost lagged fibonacci.
|
||||
|
||||
@@ -38,8 +38,6 @@
|
||||
#include <vector>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "llpreprocessor.h"
|
||||
|
||||
class LLRunnable;
|
||||
|
||||
/**
|
||||
|
||||
143
indra/llcommon/llstacktrace.cpp
Normal file
143
indra/llcommon/llstacktrace.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* @file llstacktrace.cpp
|
||||
* @brief stack tracing functionality
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2001-2010, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llstacktrace.h"
|
||||
|
||||
#ifdef LL_WINDOWS
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "windows.h"
|
||||
#include "Dbghelp.h"
|
||||
|
||||
typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
|
||||
IN ULONG frames_to_skip,
|
||||
IN ULONG frames_to_capture,
|
||||
OUT PVOID *backtrace,
|
||||
OUT PULONG backtrace_hash);
|
||||
|
||||
static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
|
||||
(RtlCaptureStackBackTrace_Function*)
|
||||
GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");
|
||||
|
||||
bool ll_get_stack_trace(std::vector<std::string>& lines)
|
||||
{
|
||||
const S32 MAX_STACK_DEPTH = 32;
|
||||
const S32 STRING_NAME_LENGTH = 200;
|
||||
const S32 FRAME_SKIP = 2;
|
||||
static BOOL symbolsLoaded = false;
|
||||
static BOOL firstCall = true;
|
||||
|
||||
HANDLE hProc = GetCurrentProcess();
|
||||
|
||||
// load the symbols if they're not loaded
|
||||
if(!symbolsLoaded && firstCall)
|
||||
{
|
||||
symbolsLoaded = SymInitialize(hProc, NULL, true);
|
||||
firstCall = false;
|
||||
}
|
||||
|
||||
// if loaded, get the call stack
|
||||
if(symbolsLoaded)
|
||||
{
|
||||
// create the frames to hold the addresses
|
||||
void* frames[MAX_STACK_DEPTH];
|
||||
memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH);
|
||||
S32 depth = 0;
|
||||
|
||||
// get the addresses
|
||||
depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL);
|
||||
|
||||
IMAGEHLP_LINE64 line;
|
||||
memset(&line, 0, sizeof(IMAGEHLP_LINE64));
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
|
||||
// create something to hold address info
|
||||
PIMAGEHLP_SYMBOL64 pSym;
|
||||
pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
|
||||
memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
|
||||
pSym->MaxNameLength = STRING_NAME_LENGTH;
|
||||
pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
|
||||
// get address info for each address frame
|
||||
// and store
|
||||
for(S32 i=0; i < depth; i++)
|
||||
{
|
||||
std::stringstream stack_line;
|
||||
BOOL ret;
|
||||
|
||||
DWORD64 addr = (DWORD64)frames[i];
|
||||
ret = SymGetSymFromAddr64(hProc, addr, 0, pSym);
|
||||
if(ret)
|
||||
{
|
||||
stack_line << pSym->Name << " ";
|
||||
}
|
||||
|
||||
DWORD dummy;
|
||||
ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line);
|
||||
if(ret)
|
||||
{
|
||||
std::string file_name = line.FileName;
|
||||
std::string::size_type index = file_name.rfind("\\");
|
||||
stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber;
|
||||
}
|
||||
|
||||
lines.push_back(stack_line.str());
|
||||
}
|
||||
|
||||
free(pSym);
|
||||
|
||||
// TODO: figure out a way to cleanup symbol loading
|
||||
// Not hugely necessary, however.
|
||||
//SymCleanup(hProc);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lines.push_back("Stack Trace Failed. PDB symbol info not loaded");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool ll_get_stack_trace(std::vector<std::string>& lines)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/**
|
||||
* @file processor.h
|
||||
* @brief Legacy wrapper header.
|
||||
* @file llstacktrace.h
|
||||
* @brief stack trace functions
|
||||
*
|
||||
* $LicenseInfo:firstyear=2000&license=viewergpl$
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2000-2009, Linden Research, Inc.
|
||||
* Copyright (c) 2001-2010, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
@@ -12,13 +12,13 @@
|
||||
* ("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
|
||||
* online at http://secondlife.com/developers/opensource/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
|
||||
* http://secondlife.com/developers/opensource/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
@@ -28,6 +28,18 @@
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "llprocessor.h"
|
||||
|
||||
#ifndef LL_LLSTACKTRACE_H
|
||||
#define LL_LLSTACKTRACE_H
|
||||
|
||||
#include "stdtypes.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
LL_COMMON_API bool ll_get_stack_trace(std::vector<std::string>& lines);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <deque>
|
||||
#include "stdtypes.h" // llcommon/stdtypes.h, needed for S32 and U32.
|
||||
|
||||
// Use to compare the first element only of a pair
|
||||
// e.g. typedef std::set<std::pair<int, Data*>, compare_pair<int, Data*> > some_pair_set_t;
|
||||
|
||||
@@ -436,7 +436,7 @@ void get_keyword_and_value(std::string& keyword,
|
||||
while (line_index < line_size)
|
||||
{
|
||||
c = line[line_index];
|
||||
if (!isspace(c))
|
||||
if (!LLStringOps::isSpace(c))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -448,7 +448,7 @@ void get_keyword_and_value(std::string& keyword,
|
||||
while (line_index < line_size)
|
||||
{
|
||||
c = line[line_index];
|
||||
if (isspace(c) || '\r' == c || '\n' == c)
|
||||
if (LLStringOps::isSpace(c) || '\r' == c || '\n' == c)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include "llstring.h"
|
||||
#include "llerror.h"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
#if LL_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
@@ -71,6 +72,24 @@ U8 hex_as_nybble(char hex)
|
||||
return 0; // uh - oh, not hex any more...
|
||||
}
|
||||
|
||||
bool iswindividual(llwchar elem)
|
||||
{
|
||||
U32 cur_char = (U32)elem;
|
||||
bool result = false;
|
||||
if (0x2E80<= cur_char && cur_char <= 0x9FFF)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
else if (0xAC00<= cur_char && cur_char <= 0xD7A0 )
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
else if (0xF900<= cur_char && cur_char <= 0xFA60 )
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool _read_file_into_string(std::string& str, const std::string& filename)
|
||||
{
|
||||
@@ -630,14 +649,14 @@ namespace snprintf_hack
|
||||
}
|
||||
}
|
||||
|
||||
std::string ll_convert_wide_to_string(const wchar_t* in)
|
||||
std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page)
|
||||
{
|
||||
std::string out;
|
||||
if(in)
|
||||
{
|
||||
int len_in = wcslen(in);
|
||||
int len_out = WideCharToMultiByte(
|
||||
CP_ACP,
|
||||
code_page,
|
||||
0,
|
||||
in,
|
||||
len_in,
|
||||
@@ -652,7 +671,7 @@ std::string ll_convert_wide_to_string(const wchar_t* in)
|
||||
if(pout)
|
||||
{
|
||||
WideCharToMultiByte(
|
||||
CP_ACP,
|
||||
code_page,
|
||||
0,
|
||||
in,
|
||||
len_in,
|
||||
@@ -666,8 +685,55 @@ std::string ll_convert_wide_to_string(const wchar_t* in)
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page)
|
||||
{
|
||||
// From review:
|
||||
// We can preallocate a wide char buffer that is the same length (in wchar_t elements) as the utf8 input,
|
||||
// plus one for a null terminator, and be guaranteed to not overflow.
|
||||
|
||||
// Normally, I'd call that sort of thing premature optimization,
|
||||
// but we *are* seeing string operations taking a bunch of time, especially when constructing widgets.
|
||||
// int output_str_len = MultiByteToWideChar(code_page, 0, in.c_str(), in.length(), NULL, 0);
|
||||
|
||||
// reserve place to NULL terminator
|
||||
int output_str_len = in.length();
|
||||
wchar_t* w_out = new wchar_t[output_str_len + 1];
|
||||
|
||||
memset(w_out, 0, output_str_len + 1);
|
||||
int real_output_str_len = MultiByteToWideChar (code_page, 0, in.c_str(), in.length(), w_out, output_str_len);
|
||||
|
||||
//looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858.
|
||||
w_out[real_output_str_len] = 0;
|
||||
|
||||
return w_out;
|
||||
}
|
||||
|
||||
std::string ll_convert_string_to_utf8_string(const std::string& in)
|
||||
{
|
||||
wchar_t* w_mesg = ll_convert_string_to_wide(in, CP_ACP);
|
||||
std::string out_utf8(ll_convert_wide_to_string(w_mesg, CP_UTF8));
|
||||
delete[] w_mesg;
|
||||
|
||||
return out_utf8;
|
||||
}
|
||||
#endif // LL_WINDOWS
|
||||
|
||||
long LLStringOps::sPacificTimeOffset = 0;
|
||||
long LLStringOps::sLocalTimeOffset = 0;
|
||||
bool LLStringOps::sPacificDaylightTime = 0;
|
||||
std::map<std::string, std::string> LLStringOps::datetimeToCodes;
|
||||
|
||||
std::vector<std::string> LLStringOps::sWeekDayList;
|
||||
std::vector<std::string> LLStringOps::sWeekDayShortList;
|
||||
std::vector<std::string> LLStringOps::sMonthList;
|
||||
std::vector<std::string> LLStringOps::sMonthShortList;
|
||||
|
||||
|
||||
std::string LLStringOps::sDayFormat;
|
||||
std::string LLStringOps::sAM;
|
||||
std::string LLStringOps::sPM;
|
||||
|
||||
S32 LLStringOps::collate(const llwchar* a, const llwchar* b)
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
@@ -679,6 +745,107 @@ S32 LLStringOps::collate(const llwchar* a, const llwchar* b)
|
||||
#endif
|
||||
}
|
||||
|
||||
void LLStringOps::setupDatetimeInfo (bool daylight)
|
||||
{
|
||||
time_t nowT, localT, gmtT;
|
||||
struct tm * tmpT;
|
||||
|
||||
nowT = time (NULL);
|
||||
|
||||
tmpT = gmtime (&nowT);
|
||||
gmtT = mktime (tmpT);
|
||||
|
||||
tmpT = localtime (&nowT);
|
||||
localT = mktime (tmpT);
|
||||
|
||||
sLocalTimeOffset = (long) (gmtT - localT);
|
||||
if (tmpT->tm_isdst)
|
||||
{
|
||||
sLocalTimeOffset -= 60 * 60; // 1 hour
|
||||
}
|
||||
|
||||
sPacificDaylightTime = daylight;
|
||||
sPacificTimeOffset = (sPacificDaylightTime? 7 : 8 ) * 60 * 60;
|
||||
|
||||
datetimeToCodes["wkday"] = "%a"; // Thu
|
||||
datetimeToCodes["weekday"] = "%A"; // Thursday
|
||||
datetimeToCodes["year4"] = "%Y"; // 2009
|
||||
datetimeToCodes["year"] = "%Y"; // 2009
|
||||
datetimeToCodes["year2"] = "%y"; // 09
|
||||
datetimeToCodes["mth"] = "%b"; // Aug
|
||||
datetimeToCodes["month"] = "%B"; // August
|
||||
datetimeToCodes["mthnum"] = "%m"; // 08
|
||||
datetimeToCodes["day"] = "%d"; // 31
|
||||
datetimeToCodes["sday"] = "%-d"; // 9
|
||||
datetimeToCodes["hour24"] = "%H"; // 14
|
||||
datetimeToCodes["hour"] = "%H"; // 14
|
||||
datetimeToCodes["hour12"] = "%I"; // 02
|
||||
datetimeToCodes["min"] = "%M"; // 59
|
||||
datetimeToCodes["ampm"] = "%p"; // AM
|
||||
datetimeToCodes["second"] = "%S"; // 59
|
||||
datetimeToCodes["timezone"] = "%Z"; // PST
|
||||
}
|
||||
|
||||
void tokenizeStringToArray(const std::string& data, std::vector<std::string>& output)
|
||||
{
|
||||
output.clear();
|
||||
size_t length = data.size();
|
||||
|
||||
// tokenize it and put it in the array
|
||||
std::string cur_word;
|
||||
for(size_t i = 0; i < length; ++i)
|
||||
{
|
||||
if(data[i] == ':')
|
||||
{
|
||||
output.push_back(cur_word);
|
||||
cur_word.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_word.append(1, data[i]);
|
||||
}
|
||||
}
|
||||
output.push_back(cur_word);
|
||||
}
|
||||
|
||||
void LLStringOps::setupWeekDaysNames(const std::string& data)
|
||||
{
|
||||
tokenizeStringToArray(data,sWeekDayList);
|
||||
}
|
||||
void LLStringOps::setupWeekDaysShortNames(const std::string& data)
|
||||
{
|
||||
tokenizeStringToArray(data,sWeekDayShortList);
|
||||
}
|
||||
void LLStringOps::setupMonthNames(const std::string& data)
|
||||
{
|
||||
tokenizeStringToArray(data,sMonthList);
|
||||
}
|
||||
void LLStringOps::setupMonthShortNames(const std::string& data)
|
||||
{
|
||||
tokenizeStringToArray(data,sMonthShortList);
|
||||
}
|
||||
void LLStringOps::setupDayFormat(const std::string& data)
|
||||
{
|
||||
sDayFormat = data;
|
||||
}
|
||||
|
||||
|
||||
std::string LLStringOps::getDatetimeCode (std::string key)
|
||||
{
|
||||
std::map<std::string, std::string>::iterator iter;
|
||||
|
||||
iter = datetimeToCodes.find (key);
|
||||
if (iter != datetimeToCodes.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string("");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace LLStringFn
|
||||
{
|
||||
// NOTE - this restricts output to ascii
|
||||
@@ -715,12 +882,12 @@ namespace LLStringFn
|
||||
// https://wiki.lindenlab.com/wiki/Unicode_Guidelines has details on
|
||||
// allowable code points for XML. Specifically, they are:
|
||||
// 0x09, 0x0a, 0x0d, and 0x20 on up. JC
|
||||
std::string strip_invalid_xml(const std::string& input)
|
||||
std::string strip_invalid_xml(const std::string& instr)
|
||||
{
|
||||
std::string output;
|
||||
output.reserve( input.size() );
|
||||
std::string::const_iterator it = input.begin();
|
||||
while (it != input.end())
|
||||
output.reserve( instr.size() );
|
||||
std::string::const_iterator it = instr.begin();
|
||||
while (it != instr.end())
|
||||
{
|
||||
// Must compare as unsigned for >=
|
||||
// Test most likely match first
|
||||
@@ -756,6 +923,412 @@ namespace LLStringFn
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// Forward specialization of LLStringUtil::format before use in LLStringUtil::formatDatetime.
|
||||
template<>
|
||||
S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions);
|
||||
|
||||
//static
|
||||
template<>
|
||||
void LLStringUtil::getTokens(const std::string& instr, std::vector<std::string >& tokens, const std::string& delims)
|
||||
{
|
||||
std::string currToken;
|
||||
std::string::size_type begIdx, endIdx;
|
||||
|
||||
begIdx = instr.find_first_not_of (delims);
|
||||
while (begIdx != std::string::npos)
|
||||
{
|
||||
endIdx = instr.find_first_of (delims, begIdx);
|
||||
if (endIdx == std::string::npos)
|
||||
{
|
||||
endIdx = instr.length();
|
||||
}
|
||||
|
||||
currToken = instr.substr(begIdx, endIdx - begIdx);
|
||||
LLStringUtil::trim (currToken);
|
||||
tokens.push_back(currToken);
|
||||
begIdx = instr.find_first_not_of (delims, endIdx);
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
LLStringUtil::size_type LLStringUtil::getSubstitution(const std::string& instr, size_type& start, std::vector<std::string>& tokens)
|
||||
{
|
||||
const std::string delims (",");
|
||||
|
||||
// Find the first ]
|
||||
size_type pos2 = instr.find(']', start);
|
||||
if (pos2 == std::string::npos)
|
||||
return std::string::npos;
|
||||
|
||||
// Find the last [ before ]
|
||||
size_type pos1 = instr.find_last_of('[', pos2-1);
|
||||
if (pos1 == std::string::npos || pos1 < start)
|
||||
return std::string::npos;
|
||||
|
||||
getTokens(std::string(instr,pos1+1,pos2-pos1-1), tokens, delims);
|
||||
start = pos2+1;
|
||||
|
||||
return pos1;
|
||||
}
|
||||
|
||||
// static
|
||||
template<>
|
||||
bool LLStringUtil::simpleReplacement(std::string &replacement, std::string token, const format_map_t& substitutions)
|
||||
{
|
||||
// see if we have a replacement for the bracketed string (without the brackets)
|
||||
// test first using has() because if we just look up with operator[] we get back an
|
||||
// empty string even if the value is missing. We want to distinguish between
|
||||
// missing replacements and deliberately empty replacement strings.
|
||||
format_map_t::const_iterator iter = substitutions.find(token);
|
||||
if (iter != substitutions.end())
|
||||
{
|
||||
replacement = iter->second;
|
||||
return true;
|
||||
}
|
||||
// if not, see if there's one WITH brackets
|
||||
iter = substitutions.find(std::string("[" + token + "]"));
|
||||
if (iter != substitutions.end())
|
||||
{
|
||||
replacement = iter->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
template<>
|
||||
bool LLStringUtil::simpleReplacement(std::string &replacement, std::string token, const LLSD& substitutions)
|
||||
{
|
||||
// see if we have a replacement for the bracketed string (without the brackets)
|
||||
// test first using has() because if we just look up with operator[] we get back an
|
||||
// empty string even if the value is missing. We want to distinguish between
|
||||
// missing replacements and deliberately empty replacement strings.
|
||||
if (substitutions.has(token))
|
||||
{
|
||||
replacement = substitutions[token].asString();
|
||||
return true;
|
||||
}
|
||||
// if not, see if there's one WITH brackets
|
||||
else if (substitutions.has(std::string("[" + token + "]")))
|
||||
{
|
||||
replacement = substitutions[std::string("[" + token + "]")].asString();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//static
|
||||
template<>
|
||||
void LLStringUtil::setLocale(std::string inLocale)
|
||||
{
|
||||
sLocale = inLocale;
|
||||
};
|
||||
|
||||
//static
|
||||
template<>
|
||||
std::string LLStringUtil::getLocale(void)
|
||||
{
|
||||
return sLocale;
|
||||
};
|
||||
|
||||
// static
|
||||
template<>
|
||||
void LLStringUtil::formatNumber(std::string& numStr, std::string decimals)
|
||||
{
|
||||
std::stringstream strStream;
|
||||
S32 intDecimals = 0;
|
||||
|
||||
convertToS32 (decimals, intDecimals);
|
||||
if (!sLocale.empty())
|
||||
{
|
||||
// std::locale() throws if the locale is unknown! (EXT-7926)
|
||||
try
|
||||
{
|
||||
strStream.imbue(std::locale(sLocale.c_str()));
|
||||
} catch (const std::exception &)
|
||||
{
|
||||
LL_WARNS_ONCE("Locale") << "Cannot set locale to " << sLocale << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!intDecimals)
|
||||
{
|
||||
S32 intStr;
|
||||
|
||||
if (convertToS32(numStr, intStr))
|
||||
{
|
||||
strStream << intStr;
|
||||
numStr = strStream.str();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
F32 floatStr;
|
||||
|
||||
if (convertToF32(numStr, floatStr))
|
||||
{
|
||||
strStream << std::fixed << std::showpoint << std::setprecision(intDecimals) << floatStr;
|
||||
numStr = strStream.str();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
template<>
|
||||
bool LLStringUtil::formatDatetime(std::string& replacement, std::string token,
|
||||
std::string param, S32 secFromEpoch)
|
||||
{
|
||||
if (param == "local") // local
|
||||
{
|
||||
secFromEpoch -= LLStringOps::getLocalTimeOffset();
|
||||
}
|
||||
else if (param != "utc") // slt
|
||||
{
|
||||
secFromEpoch -= LLStringOps::getPacificTimeOffset();
|
||||
}
|
||||
|
||||
// if never fell into those two ifs above, param must be utc
|
||||
if (secFromEpoch < 0) secFromEpoch = 0;
|
||||
|
||||
LLDate datetime((F64)secFromEpoch);
|
||||
std::string code = LLStringOps::getDatetimeCode (token);
|
||||
|
||||
// special case to handle timezone
|
||||
if (code == "%Z") {
|
||||
if (param == "utc")
|
||||
{
|
||||
replacement = "GMT";
|
||||
}
|
||||
else if (param == "local")
|
||||
{
|
||||
replacement = ""; // user knows their own timezone
|
||||
}
|
||||
else
|
||||
{
|
||||
// "slt" = Second Life Time, which is deprecated.
|
||||
// If not utc or user local time, fallback to Pacific time
|
||||
replacement = LLStringOps::getPacificDaylightTime() ? "PDT" : "PST";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//EXT-7013
|
||||
//few codes are not suppotred by strtime function (example - weekdays for Japanise)
|
||||
//so use predefined ones
|
||||
|
||||
//if sWeekDayList is not empty than current locale doesn't support
|
||||
//weekday name.
|
||||
time_t loc_seconds = (time_t) secFromEpoch;
|
||||
if(LLStringOps::sWeekDayList.size() == 7 && code == "%A")
|
||||
{
|
||||
struct tm * gmt = gmtime (&loc_seconds);
|
||||
replacement = LLStringOps::sWeekDayList[gmt->tm_wday];
|
||||
}
|
||||
else if(LLStringOps::sWeekDayShortList.size() == 7 && code == "%a")
|
||||
{
|
||||
struct tm * gmt = gmtime (&loc_seconds);
|
||||
replacement = LLStringOps::sWeekDayShortList[gmt->tm_wday];
|
||||
}
|
||||
else if(LLStringOps::sMonthList.size() == 12 && code == "%B")
|
||||
{
|
||||
struct tm * gmt = gmtime (&loc_seconds);
|
||||
replacement = LLStringOps::sMonthList[gmt->tm_mon];
|
||||
}
|
||||
else if( !LLStringOps::sDayFormat.empty() && code == "%d" )
|
||||
{
|
||||
struct tm * gmt = gmtime (&loc_seconds);
|
||||
LLStringUtil::format_map_t args;
|
||||
args["[MDAY]"] = llformat ("%d", gmt->tm_mday);
|
||||
replacement = LLStringOps::sDayFormat;
|
||||
LLStringUtil::format(replacement, args);
|
||||
}
|
||||
else if (code == "%-d")
|
||||
{
|
||||
struct tm * gmt = gmtime (&loc_seconds);
|
||||
replacement = llformat ("%d", gmt->tm_mday); // day of the month without leading zero
|
||||
}
|
||||
else if( !LLStringOps::sAM.empty() && !LLStringOps::sPM.empty() && code == "%p" )
|
||||
{
|
||||
struct tm * gmt = gmtime (&loc_seconds);
|
||||
if(gmt->tm_hour<12)
|
||||
{
|
||||
replacement = LLStringOps::sAM;
|
||||
}
|
||||
else
|
||||
{
|
||||
replacement = LLStringOps::sPM;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
replacement = datetime.toHTTPDateString(code);
|
||||
}
|
||||
|
||||
// *HACK: delete leading zero from hour string in case 'hour12' (code = %I) time format
|
||||
// to show time without leading zero, e.g. 08:16 -> 8:16 (EXT-2738).
|
||||
// We could have used '%l' format instead, but it's not supported by Windows.
|
||||
if(code == "%I" && token == "hour12" && replacement.at(0) == '0')
|
||||
{
|
||||
replacement = replacement.at(1);
|
||||
}
|
||||
|
||||
return !code.empty();
|
||||
}
|
||||
|
||||
// LLStringUtil::format recogizes the following patterns.
|
||||
// All substitutions *must* be encased in []'s in the input string.
|
||||
// The []'s are optional in the substitution map.
|
||||
// [FOO_123]
|
||||
// [FOO,number,precision]
|
||||
// [FOO,datetime,format]
|
||||
|
||||
|
||||
// static
|
||||
template<>
|
||||
S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
|
||||
{
|
||||
LLFastTimer ft(LLFastTimer::FT_STRING_FORMAT);
|
||||
S32 res = 0;
|
||||
|
||||
std::string output;
|
||||
std::vector<std::string> tokens;
|
||||
|
||||
std::string::size_type start = 0;
|
||||
std::string::size_type prev_start = 0;
|
||||
std::string::size_type key_start = 0;
|
||||
while ((key_start = getSubstitution(s, start, tokens)) != std::string::npos)
|
||||
{
|
||||
output += std::string(s, prev_start, key_start-prev_start);
|
||||
prev_start = start;
|
||||
|
||||
bool found_replacement = false;
|
||||
std::string replacement;
|
||||
|
||||
if (tokens.size() == 0)
|
||||
{
|
||||
found_replacement = false;
|
||||
}
|
||||
else if (tokens.size() == 1)
|
||||
{
|
||||
found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
|
||||
}
|
||||
else if (tokens[1] == "number")
|
||||
{
|
||||
std::string param = "0";
|
||||
|
||||
if (tokens.size() > 2) param = tokens[2];
|
||||
found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
|
||||
if (found_replacement) formatNumber (replacement, param);
|
||||
}
|
||||
else if (tokens[1] == "datetime")
|
||||
{
|
||||
std::string param;
|
||||
if (tokens.size() > 2) param = tokens[2];
|
||||
|
||||
format_map_t::const_iterator iter = substitutions.find("datetime");
|
||||
if (iter != substitutions.end())
|
||||
{
|
||||
S32 secFromEpoch = 0;
|
||||
BOOL r = LLStringUtil::convertToS32(iter->second, secFromEpoch);
|
||||
if (r)
|
||||
{
|
||||
found_replacement = formatDatetime(replacement, tokens[0], param, secFromEpoch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found_replacement)
|
||||
{
|
||||
output += replacement;
|
||||
res++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we had no replacement, use the string as is
|
||||
// e.g. "hello [MISSING_REPLACEMENT]" or "-=[Stylized Name]=-"
|
||||
output += std::string(s, key_start, start-key_start);
|
||||
}
|
||||
tokens.clear();
|
||||
}
|
||||
// send the remainder of the string (with no further matches for bracketed names)
|
||||
output += std::string(s, start);
|
||||
s = output;
|
||||
return res;
|
||||
}
|
||||
|
||||
//static
|
||||
template<>
|
||||
S32 LLStringUtil::format(std::string& s, const LLSD& substitutions)
|
||||
{
|
||||
LLFastTimer ft(LLFastTimer::FT_STRING_FORMAT);
|
||||
S32 res = 0;
|
||||
|
||||
if (!substitutions.isMap())
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string output;
|
||||
std::vector<std::string> tokens;
|
||||
|
||||
std::string::size_type start = 0;
|
||||
std::string::size_type prev_start = 0;
|
||||
std::string::size_type key_start = 0;
|
||||
while ((key_start = getSubstitution(s, start, tokens)) != std::string::npos)
|
||||
{
|
||||
output += std::string(s, prev_start, key_start-prev_start);
|
||||
prev_start = start;
|
||||
|
||||
bool found_replacement = false;
|
||||
std::string replacement;
|
||||
|
||||
if (tokens.size() == 0)
|
||||
{
|
||||
found_replacement = false;
|
||||
}
|
||||
else if (tokens.size() == 1)
|
||||
{
|
||||
found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
|
||||
}
|
||||
else if (tokens[1] == "number")
|
||||
{
|
||||
std::string param = "0";
|
||||
|
||||
if (tokens.size() > 2) param = tokens[2];
|
||||
found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
|
||||
if (found_replacement) formatNumber (replacement, param);
|
||||
}
|
||||
else if (tokens[1] == "datetime")
|
||||
{
|
||||
std::string param;
|
||||
if (tokens.size() > 2) param = tokens[2];
|
||||
|
||||
S32 secFromEpoch = (S32) substitutions["datetime"].asInteger();
|
||||
found_replacement = formatDatetime (replacement, tokens[0], param, secFromEpoch);
|
||||
}
|
||||
|
||||
if (found_replacement)
|
||||
{
|
||||
output += replacement;
|
||||
res++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we had no replacement, use the string as is
|
||||
// e.g. "hello [MISSING_REPLACEMENT]" or "-=[Stylized Name]=-"
|
||||
output += std::string(s, key_start, start-key_start);
|
||||
}
|
||||
tokens.clear();
|
||||
}
|
||||
// send the remainder of the string (with no further matches for bracketed names)
|
||||
output += std::string(s, start);
|
||||
s = output;
|
||||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Testing
|
||||
|
||||
@@ -37,6 +37,9 @@
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <locale>
|
||||
#include <iomanip>
|
||||
#include "llsd.h"
|
||||
|
||||
#if LL_LINUX || LL_SOLARIS
|
||||
#include <wctype.h>
|
||||
@@ -148,7 +151,23 @@ struct char_traits<U16>
|
||||
|
||||
class LL_COMMON_API LLStringOps
|
||||
{
|
||||
private:
|
||||
static long sPacificTimeOffset;
|
||||
static long sLocalTimeOffset;
|
||||
static bool sPacificDaylightTime;
|
||||
|
||||
static std::map<std::string, std::string> datetimeToCodes;
|
||||
|
||||
public:
|
||||
static std::vector<std::string> sWeekDayList;
|
||||
static std::vector<std::string> sWeekDayShortList;
|
||||
static std::vector<std::string> sMonthList;
|
||||
static std::vector<std::string> sMonthShortList;
|
||||
static std::string sDayFormat;
|
||||
|
||||
static std::string sAM;
|
||||
static std::string sPM;
|
||||
|
||||
static char toUpper(char elem) { return toupper((unsigned char)elem); }
|
||||
static llwchar toUpper(llwchar elem) { return towupper(elem); }
|
||||
|
||||
@@ -177,14 +196,31 @@ public:
|
||||
static S32 collate(const llwchar* a, const llwchar* b);
|
||||
|
||||
static bool isHexString(const std::string& str);
|
||||
|
||||
static void setupDatetimeInfo(bool pacific_daylight_time);
|
||||
|
||||
static void setupWeekDaysNames(const std::string& data);
|
||||
static void setupWeekDaysShortNames(const std::string& data);
|
||||
static void setupMonthNames(const std::string& data);
|
||||
static void setupMonthShortNames(const std::string& data);
|
||||
static void setupDayFormat(const std::string& data);
|
||||
|
||||
|
||||
static long getPacificTimeOffset(void) { return sPacificTimeOffset;}
|
||||
static long getLocalTimeOffset(void) { return sLocalTimeOffset;}
|
||||
// Is the Pacific time zone (aka server time zone)
|
||||
// currently in daylight savings time?
|
||||
static bool getPacificDaylightTime(void) { return sPacificDaylightTime;}
|
||||
|
||||
static std::string getDatetimeCode (std::string key);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Return a string constructed from in without crashing if the
|
||||
* pointer is NULL.
|
||||
*/
|
||||
std::string LL_COMMON_API ll_safe_string(const char* in);
|
||||
std::string LL_COMMON_API ll_safe_string(const char* in, S32 maxlen);
|
||||
LL_COMMON_API std::string ll_safe_string(const char* in);
|
||||
LL_COMMON_API std::string ll_safe_string(const char* in, S32 maxlen);
|
||||
|
||||
|
||||
// Allowing assignments from non-strings into format_map_t is apparently
|
||||
@@ -206,6 +242,9 @@ private:
|
||||
template <class T>
|
||||
class LLStringUtilBase
|
||||
{
|
||||
private:
|
||||
static std::string sLocale;
|
||||
|
||||
public:
|
||||
typedef typename std::basic_string<T>::size_type size_type;
|
||||
|
||||
@@ -213,10 +252,18 @@ public:
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Static Utility functions that operate on std::strings
|
||||
|
||||
static std::basic_string<T> const null;
|
||||
static const std::basic_string<T> null;
|
||||
|
||||
typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t;
|
||||
static S32 format(std::basic_string<T>& s, const format_map_t& fmt_map);
|
||||
LL_COMMON_API static void getTokens(const std::basic_string<T>& instr, std::vector<std::basic_string<T> >& tokens, const std::basic_string<T>& delims);
|
||||
LL_COMMON_API static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals);
|
||||
LL_COMMON_API static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, S32 secFromEpoch);
|
||||
LL_COMMON_API static S32 format(std::basic_string<T>& s, const format_map_t& substitutions);
|
||||
LL_COMMON_API static S32 format(std::basic_string<T>& s, const LLSD& substitutions);
|
||||
LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const format_map_t& substitutions);
|
||||
LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const LLSD& substitutions);
|
||||
LL_COMMON_API static void setLocale (std::string inLocale);
|
||||
LL_COMMON_API static std::string getLocale (void);
|
||||
|
||||
static bool isValidIndex(const std::basic_string<T>& string, size_type i)
|
||||
{
|
||||
@@ -233,7 +280,25 @@ public:
|
||||
|
||||
// True if this is the head of s.
|
||||
static BOOL isHead( const std::basic_string<T>& string, const T* s );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns true if string starts with substr
|
||||
*
|
||||
* If etither string or substr are empty, this method returns false.
|
||||
*/
|
||||
static bool startsWith(
|
||||
const std::basic_string<T>& string,
|
||||
const std::basic_string<T>& substr);
|
||||
|
||||
/**
|
||||
* @brief Returns true if string ends in substr
|
||||
*
|
||||
* If etither string or substr are empty, this method returns false.
|
||||
*/
|
||||
static bool endsWith(
|
||||
const std::basic_string<T>& string,
|
||||
const std::basic_string<T>& substr);
|
||||
|
||||
static void addCRLF(std::basic_string<T>& string);
|
||||
static void removeCRLF(std::basic_string<T>& string);
|
||||
|
||||
@@ -298,13 +363,19 @@ public:
|
||||
// Copies src into dst at a given offset.
|
||||
static void copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset);
|
||||
|
||||
static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); }
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
static void testHarness();
|
||||
LL_COMMON_API static void testHarness();
|
||||
#endif
|
||||
|
||||
private:
|
||||
LL_COMMON_API static size_type getSubstitution(const std::basic_string<T>& instr, size_type& start, std::vector<std::basic_string<T> >& tokens);
|
||||
};
|
||||
|
||||
template<class T> std::basic_string<T> const LLStringUtilBase<T>::null;
|
||||
template<class T> const std::basic_string<T> LLStringUtilBase<T>::null;
|
||||
template<class T> std::string LLStringUtilBase<T>::sLocale;
|
||||
|
||||
typedef LLStringUtilBase<char> LLStringUtil;
|
||||
typedef LLStringUtilBase<llwchar> LLWStringUtil;
|
||||
@@ -366,6 +437,7 @@ LL_COMMON_API U8 hex_as_nybble(char hex);
|
||||
* @return Returns true on success. If false, str is unmodified.
|
||||
*/
|
||||
LL_COMMON_API bool _read_file_into_string(std::string& str, const std::string& filename);
|
||||
LL_COMMON_API bool iswindividual(llwchar elem);
|
||||
|
||||
/**
|
||||
* Unicode support
|
||||
@@ -495,7 +567,20 @@ using snprintf_hack::snprintf;
|
||||
*
|
||||
* This replaces the unsafe W2A macro from ATL.
|
||||
*/
|
||||
LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in);
|
||||
LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page);
|
||||
|
||||
/**
|
||||
* Converts a string to wide string.
|
||||
*
|
||||
* It will allocate memory for result string with "new []". Don't forget to release it with "delete []".
|
||||
*/
|
||||
LL_COMMON_API wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page);
|
||||
|
||||
/**
|
||||
* Converts incoming string into urf8 string
|
||||
*
|
||||
*/
|
||||
LL_COMMON_API std::string ll_convert_string_to_utf8_string(const std::string& in);
|
||||
|
||||
//@}
|
||||
#endif // LL_WINDOWS
|
||||
@@ -558,63 +643,12 @@ namespace LLStringFn
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// NOTE: LLStringUtil::format, getTokens, and support functions moved to llstring.cpp.
|
||||
// There is no LLWStringUtil::format implementation currently.
|
||||
// Calling thse for anything other than LLStringUtil will produce link errors.
|
||||
|
||||
// LLStringBase::format()
|
||||
//
|
||||
// This function takes a string 's' and a map 'fmt_map' of strings-to-strings.
|
||||
// All occurances of strings in 's' from the left-hand side of 'fmt_map' are
|
||||
// then replaced with the corresponding right-hand side of 'fmt_map', non-
|
||||
// recursively. The function returns the number of substitutions made.
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// static
|
||||
template<class T>
|
||||
S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const format_map_t& fmt_map)
|
||||
{
|
||||
typedef typename std::basic_string<T>::size_type string_size_type_t;
|
||||
string_size_type_t scanstart = 0;
|
||||
S32 res = 0;
|
||||
|
||||
// Look for the first match of any keyword, replace that keyword,
|
||||
// repeat from the end of the replacement string. This avoids
|
||||
// accidentally performing substitution on a substituted string.
|
||||
while (1)
|
||||
{
|
||||
string_size_type_t first_match_pos = scanstart;
|
||||
string_size_type_t first_match_str_length = 0;
|
||||
std::basic_string<T> first_match_str_replacement;
|
||||
|
||||
for (format_map_t::const_iterator iter = fmt_map.begin();
|
||||
iter != fmt_map.end();
|
||||
++iter)
|
||||
{
|
||||
string_size_type_t n = s.find(iter->first, scanstart);
|
||||
if (n != std::basic_string<T>::npos &&
|
||||
(n < first_match_pos ||
|
||||
0 == first_match_str_length))
|
||||
{
|
||||
first_match_pos = n;
|
||||
first_match_str_length = iter->first.length();
|
||||
first_match_str_replacement = iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == first_match_str_length)
|
||||
{
|
||||
// no more keys found to substitute from this point
|
||||
// in the string forward.
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
s.erase(first_match_pos, first_match_str_length);
|
||||
s.insert(first_match_pos, first_match_str_replacement);
|
||||
scanstart = first_match_pos +
|
||||
first_match_str_replacement.length();
|
||||
++res;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// static
|
||||
template<class T>
|
||||
@@ -1003,14 +1037,15 @@ void LLStringUtilBase<T>::stripNonprintable(std::basic_string<T>& string)
|
||||
{
|
||||
return;
|
||||
}
|
||||
char* c_string = new char[string.size() + 1];
|
||||
size_t src_size = string.size();
|
||||
char* c_string = new char[src_size + 1];
|
||||
if(c_string == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
strcpy(c_string, string.c_str()); /*Flawfinder: ignore*/
|
||||
copy(c_string, string.c_str(), src_size+1);
|
||||
char* write_head = &c_string[0];
|
||||
for (size_type i = 0; i < string.size(); i++)
|
||||
for (size_type i = 0; i < src_size; i++)
|
||||
{
|
||||
char* read_head = &string[i];
|
||||
write_head = &c_string[j];
|
||||
@@ -1090,6 +1125,30 @@ BOOL LLStringUtilBase<T>::isHead( const std::basic_string<T>& string, const T* s
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
template<class T>
|
||||
bool LLStringUtilBase<T>::startsWith(
|
||||
const std::basic_string<T>& string,
|
||||
const std::basic_string<T>& substr)
|
||||
{
|
||||
if(string.empty() || (substr.empty())) return false;
|
||||
if(0 == string.find(substr)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
template<class T>
|
||||
bool LLStringUtilBase<T>::endsWith(
|
||||
const std::basic_string<T>& string,
|
||||
const std::basic_string<T>& substr)
|
||||
{
|
||||
if(string.empty() || (substr.empty())) return false;
|
||||
std::string::size_type idx = string.rfind(substr);
|
||||
if(std::string::npos == idx) return false;
|
||||
return (idx == (string.size() - substr.size()));
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
BOOL LLStringUtilBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value)
|
||||
{
|
||||
|
||||
@@ -38,6 +38,23 @@
|
||||
|
||||
LLStringTable gStringTable(32768);
|
||||
|
||||
LLStringTableEntry::LLStringTableEntry(const char *str)
|
||||
: mString(NULL), mCount(1)
|
||||
{
|
||||
// Copy string
|
||||
U32 length = (U32)strlen(str) + 1; /*Flawfinder: ignore*/
|
||||
length = llmin(length, MAX_STRINGS_LENGTH);
|
||||
mString = new char[length];
|
||||
strncpy(mString, str, length); /*Flawfinder: ignore*/
|
||||
mString[length - 1] = 0;
|
||||
}
|
||||
|
||||
LLStringTableEntry::~LLStringTableEntry()
|
||||
{
|
||||
delete [] mString;
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
LLStringTable::LLStringTable(int tablesize)
|
||||
: mUniqueEntries(0)
|
||||
{
|
||||
|
||||
@@ -49,11 +49,11 @@
|
||||
#endif
|
||||
|
||||
#if STRING_TABLE_HASH_MAP
|
||||
#if LL_WINDOWS
|
||||
#include <hash_map>
|
||||
#else
|
||||
#include <ext/hash_map>
|
||||
#endif
|
||||
# if LL_WINDOWS
|
||||
# include <hash_map>
|
||||
# else
|
||||
# include <ext/hash_map>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
const U32 MAX_STRINGS_LENGTH = 256;
|
||||
@@ -61,21 +61,9 @@ const U32 MAX_STRINGS_LENGTH = 256;
|
||||
class LL_COMMON_API LLStringTableEntry
|
||||
{
|
||||
public:
|
||||
LLStringTableEntry(const char *str)
|
||||
: mString(NULL), mCount(1)
|
||||
{
|
||||
// Copy string
|
||||
U32 length = (U32)strlen(str) + 1; /*Flawfinder: ignore*/
|
||||
length = llmin(length, MAX_STRINGS_LENGTH);
|
||||
mString = new char[length];
|
||||
strncpy(mString, str, length); /*Flawfinder: ignore*/
|
||||
mString[length - 1] = 0;
|
||||
}
|
||||
~LLStringTableEntry()
|
||||
{
|
||||
delete [] mString;
|
||||
mCount = 0;
|
||||
}
|
||||
LLStringTableEntry(const char *str);
|
||||
~LLStringTableEntry();
|
||||
|
||||
void incCount() { mCount++; }
|
||||
BOOL decCount() { return --mCount; }
|
||||
|
||||
|
||||
@@ -52,13 +52,13 @@
|
||||
# include <sys/sysctl.h>
|
||||
# include <sys/utsname.h>
|
||||
# include <stdint.h>
|
||||
//# include <Carbon/Carbon.h> May be needed?
|
||||
#elif LL_LINUX
|
||||
# include <errno.h>
|
||||
# include <sys/utsname.h>
|
||||
# include <unistd.h>
|
||||
# include <sys/sysinfo.h>
|
||||
const char MEMINFO_FILE[] = "/proc/meminfo";
|
||||
const char CPUINFO_FILE[] = "/proc/cpuinfo";
|
||||
#elif LL_SOLARIS
|
||||
# include <stdio.h>
|
||||
# include <unistd.h>
|
||||
@@ -74,7 +74,7 @@ extern int errno;
|
||||
|
||||
|
||||
static const S32 CPUINFO_BUFFER_SIZE = 16383;
|
||||
LL_COMMON_API LLCPUInfo gSysCPU;
|
||||
LLCPUInfo gSysCPU;
|
||||
|
||||
#if LL_WINDOWS
|
||||
#ifndef DLLVERSIONINFO
|
||||
@@ -325,7 +325,58 @@ LLOSInfo::LLOSInfo() :
|
||||
}
|
||||
mOSString += compatibility_mode;
|
||||
|
||||
#elif LL_DARWIN
|
||||
|
||||
// Initialize mOSStringSimple to something like:
|
||||
// "Mac OS X 10.6.7"
|
||||
{
|
||||
const char * DARWIN_PRODUCT_NAME = "Mac OS X";
|
||||
|
||||
SInt32 major_version, minor_version, bugfix_version;
|
||||
OSErr r1 = Gestalt(gestaltSystemVersionMajor, &major_version);
|
||||
OSErr r2 = Gestalt(gestaltSystemVersionMinor, &minor_version);
|
||||
OSErr r3 = Gestalt(gestaltSystemVersionBugFix, &bugfix_version);
|
||||
|
||||
if((r1 == noErr) && (r2 == noErr) && (r3 == noErr))
|
||||
{
|
||||
mMajorVer = major_version;
|
||||
mMinorVer = minor_version;
|
||||
mBuild = bugfix_version;
|
||||
|
||||
std::stringstream os_version_string;
|
||||
os_version_string << DARWIN_PRODUCT_NAME << " " << mMajorVer << "." << mMinorVer << "." << mBuild;
|
||||
|
||||
// Put it in the OS string we are compiling
|
||||
mOSStringSimple.append(os_version_string.str());
|
||||
}
|
||||
else
|
||||
{
|
||||
mOSStringSimple.append("Unable to collect OS info");
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize mOSString to something like:
|
||||
// "Mac OS X 10.6.7 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386"
|
||||
struct utsname un;
|
||||
if(uname(&un) != -1)
|
||||
{
|
||||
mOSString = mOSStringSimple;
|
||||
mOSString.append(" ");
|
||||
mOSString.append(un.sysname);
|
||||
mOSString.append(" ");
|
||||
mOSString.append(un.release);
|
||||
mOSString.append(" ");
|
||||
mOSString.append(un.version);
|
||||
mOSString.append(" ");
|
||||
mOSString.append(un.machine);
|
||||
}
|
||||
else
|
||||
{
|
||||
mOSString = mOSStringSimple;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct utsname un;
|
||||
if(uname(&un) != -1)
|
||||
{
|
||||
@@ -341,15 +392,7 @@ LLOSInfo::LLOSInfo() :
|
||||
|
||||
// Simplify 'Simple'
|
||||
std::string ostype = mOSStringSimple.substr(0, mOSStringSimple.find_first_of(" ", 0));
|
||||
if (ostype == "Darwin")
|
||||
{
|
||||
// Only care about major Darwin versions, truncate at first '.'
|
||||
S32 idx1 = mOSStringSimple.find_first_of(".", 0);
|
||||
std::string simple = mOSStringSimple.substr(0, idx1);
|
||||
if (simple.length() > 0)
|
||||
mOSStringSimple = simple;
|
||||
}
|
||||
else if (ostype == "Linux")
|
||||
if (ostype == "Linux")
|
||||
{
|
||||
// Only care about major and minor Linux versions, truncate at second '.'
|
||||
std::string::size_type idx1 = mOSStringSimple.find_first_of(".", 0);
|
||||
@@ -513,71 +556,21 @@ U32 LLOSInfo::getProcessResidentSizeKB()
|
||||
LLCPUInfo::LLCPUInfo()
|
||||
{
|
||||
std::ostringstream out;
|
||||
CProcessor proc;
|
||||
const ProcessorInfo* info = proc.GetCPUInfo();
|
||||
LLProcessorInfo proc;
|
||||
// proc.WriteInfoTextFile("procInfo.txt");
|
||||
mHasSSE = info->_Ext.SSE_StreamingSIMD_Extensions;
|
||||
mHasSSE2 = info->_Ext.SSE2_StreamingSIMD2_Extensions;
|
||||
mHasAltivec = info->_Ext.Altivec_Extensions;
|
||||
mCPUMHz = (F64)(proc.GetCPUFrequency(50)/1000000.0);
|
||||
mFamily.assign( info->strFamily );
|
||||
mHasSSE = proc.hasSSE();
|
||||
mHasSSE2 = proc.hasSSE2();
|
||||
mHasAltivec = proc.hasAltivec();
|
||||
mCPUMHz = (F64)proc.getCPUFrequency();
|
||||
mFamily = proc.getCPUFamilyName();
|
||||
mCPUString = "Unknown";
|
||||
|
||||
#if LL_WINDOWS || LL_DARWIN || LL_SOLARIS
|
||||
out << proc.strCPUName;
|
||||
out << proc.getCPUBrandName();
|
||||
if (200 < mCPUMHz && mCPUMHz < 10000) // *NOTE: cpu speed is often way wrong, do a sanity check
|
||||
{
|
||||
out << " (" << mCPUMHz << " MHz)";
|
||||
}
|
||||
mCPUString = out.str();
|
||||
|
||||
#elif LL_LINUX
|
||||
std::map< std::string, std::string > cpuinfo;
|
||||
LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb");
|
||||
if(cpuinfo_fp)
|
||||
{
|
||||
char line[MAX_STRING];
|
||||
memset(line, 0, MAX_STRING);
|
||||
while(fgets(line, MAX_STRING, cpuinfo_fp))
|
||||
{
|
||||
// /proc/cpuinfo on Linux looks like:
|
||||
// name\t*: value\n
|
||||
char* tabspot = strchr( line, '\t' );
|
||||
if (tabspot == NULL)
|
||||
continue;
|
||||
char* colspot = strchr( tabspot, ':' );
|
||||
if (colspot == NULL)
|
||||
continue;
|
||||
char* spacespot = strchr( colspot, ' ' );
|
||||
if (spacespot == NULL)
|
||||
continue;
|
||||
char* nlspot = strchr( line, '\n' );
|
||||
if (nlspot == NULL)
|
||||
nlspot = line + strlen( line ); // Fallback to terminating NUL
|
||||
std::string linename( line, tabspot );
|
||||
std::string llinename(linename);
|
||||
LLStringUtil::toLower(llinename);
|
||||
std::string lineval( spacespot + 1, nlspot );
|
||||
cpuinfo[ llinename ] = lineval;
|
||||
}
|
||||
fclose(cpuinfo_fp);
|
||||
}
|
||||
# if LL_X86
|
||||
std::string flags = " " + cpuinfo["flags"] + " ";
|
||||
LLStringUtil::toLower(flags);
|
||||
mHasSSE = ( flags.find( " sse " ) != std::string::npos );
|
||||
mHasSSE2 = ( flags.find( " sse2 " ) != std::string::npos );
|
||||
|
||||
F64 mhz;
|
||||
if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz)
|
||||
&& 200.0 < mhz && mhz < 10000.0)
|
||||
{
|
||||
mCPUMHz = (F64)llrint(mhz);
|
||||
}
|
||||
if (!cpuinfo["model name"].empty())
|
||||
mCPUString = cpuinfo["model name"];
|
||||
# endif // LL_X86
|
||||
#endif // LL_LINUX
|
||||
}
|
||||
|
||||
bool LLCPUInfo::hasAltivec() const
|
||||
@@ -607,38 +600,9 @@ std::string LLCPUInfo::getCPUString() const
|
||||
|
||||
void LLCPUInfo::stream(std::ostream& s) const
|
||||
{
|
||||
#if LL_WINDOWS || LL_DARWIN || LL_SOLARIS
|
||||
// gather machine information.
|
||||
char proc_buf[CPUINFO_BUFFER_SIZE]; /* Flawfinder: ignore */
|
||||
CProcessor proc;
|
||||
if(proc.CPUInfoToText(proc_buf, CPUINFO_BUFFER_SIZE))
|
||||
{
|
||||
s << proc_buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
s << "Unable to collect processor information" << std::endl;
|
||||
}
|
||||
#else
|
||||
// *NOTE: This works on linux. What will it do on other systems?
|
||||
LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb");
|
||||
if(cpuinfo)
|
||||
{
|
||||
char line[MAX_STRING];
|
||||
memset(line, 0, MAX_STRING);
|
||||
while(fgets(line, MAX_STRING, cpuinfo))
|
||||
{
|
||||
line[strlen(line)-1] = ' ';
|
||||
s << line;
|
||||
}
|
||||
fclose(cpuinfo);
|
||||
s << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
s << "Unable to collect processor information" << std::endl;
|
||||
}
|
||||
#endif
|
||||
s << LLProcessorInfo().getCPUFeatureDescription();
|
||||
|
||||
// These are interesting as they reflect our internal view of the
|
||||
// CPU's attributes regardless of platform
|
||||
s << "->mHasSSE: " << (U32)mHasSSE << std::endl;
|
||||
|
||||
@@ -131,10 +131,10 @@ LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLCPUInfo& info);
|
||||
LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLMemoryInfo& info);
|
||||
|
||||
// gunzip srcfile into dstfile. Returns FALSE on error.
|
||||
LL_COMMON_API BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile);
|
||||
BOOL LL_COMMON_API gunzip_file(const std::string& srcfile, const std::string& dstfile);
|
||||
// gzip srcfile into dstfile. Returns FALSE on error.
|
||||
LL_COMMON_API BOOL gzip_file(const std::string& srcfile, const std::string& dstfile);
|
||||
BOOL LL_COMMON_API gzip_file(const std::string& srcfile, const std::string& dstfile);
|
||||
|
||||
LL_COMMON_API extern LLCPUInfo gSysCPU;
|
||||
extern LL_COMMON_API LLCPUInfo gSysCPU;
|
||||
|
||||
#endif // LL_LLSYS_H
|
||||
|
||||
@@ -67,6 +67,10 @@
|
||||
//
|
||||
void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap)
|
||||
{
|
||||
#ifdef CWDEBUG
|
||||
debug::init_thread();
|
||||
#endif
|
||||
|
||||
LLThread *threadp = (LLThread *)datap;
|
||||
|
||||
// Set thread state to running
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "lltimer.h"
|
||||
#include "timing.h" // totalTime prototype.
|
||||
|
||||
#include "u64.h"
|
||||
|
||||
@@ -52,6 +51,9 @@
|
||||
//
|
||||
// Locally used constants
|
||||
//
|
||||
const U32 SEC_PER_DAY = 86400;
|
||||
const F64 SEC_TO_MICROSEC = 1000000.f;
|
||||
const U64 SEC_TO_MICROSEC_U64 = 1000000;
|
||||
const F64 USEC_TO_SEC_F64 = 0.000001;
|
||||
|
||||
|
||||
@@ -571,59 +573,6 @@ void timeStructToFormattedString(struct tm * time, std::string format, std::stri
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// LLEventTimer Implementation
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::list<LLEventTimer*> LLEventTimer::sActiveList;
|
||||
|
||||
LLEventTimer::LLEventTimer(F32 period)
|
||||
: mEventTimer()
|
||||
{
|
||||
mPeriod = period;
|
||||
sActiveList.push_back(this);
|
||||
}
|
||||
|
||||
LLEventTimer::LLEventTimer(const LLDate& time)
|
||||
: mEventTimer()
|
||||
{
|
||||
mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch());
|
||||
sActiveList.push_back(this);
|
||||
}
|
||||
|
||||
|
||||
LLEventTimer::~LLEventTimer()
|
||||
{
|
||||
sActiveList.remove(this);
|
||||
}
|
||||
|
||||
void LLEventTimer::updateClass()
|
||||
{
|
||||
std::list<LLEventTimer*> completed_timers;
|
||||
for (std::list<LLEventTimer*>::iterator iter = sActiveList.begin(); iter != sActiveList.end(); )
|
||||
{
|
||||
LLEventTimer* timer = *iter++;
|
||||
F32 et = timer->mEventTimer.getElapsedTimeF32();
|
||||
if (timer->mEventTimer.getStarted() && et > timer->mPeriod) {
|
||||
timer->mEventTimer.reset();
|
||||
if ( timer->tick() )
|
||||
{
|
||||
completed_timers.push_back( timer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( completed_timers.size() > 0 )
|
||||
{
|
||||
for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin();
|
||||
completed_iter != completed_timers.end();
|
||||
completed_iter++ )
|
||||
{
|
||||
delete *completed_iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -55,6 +55,8 @@ const U32 USEC_PER_HOUR = USEC_PER_MIN * MIN_PER_HOUR;
|
||||
const U32 SEC_PER_HOUR = SEC_PER_MIN * MIN_PER_HOUR;
|
||||
const F64 SEC_PER_USEC = 1.0 / (F64) USEC_PER_SEC;
|
||||
|
||||
LL_COMMON_API U64 totalTime(); // Returns current system time in microseconds
|
||||
|
||||
class LL_COMMON_API LLTimer
|
||||
{
|
||||
public:
|
||||
@@ -155,7 +157,7 @@ static inline time_t time_max()
|
||||
}
|
||||
|
||||
// Correction factor used by time_corrected() above.
|
||||
LL_COMMON_API extern S32 gUTCOffset;
|
||||
extern LL_COMMON_API S32 gUTCOffset;
|
||||
|
||||
// Is the current computer (in its current time zone)
|
||||
// observing daylight savings time?
|
||||
@@ -173,27 +175,4 @@ LL_COMMON_API void secondsToTimecodeString(F32 current_time, std::string& tcstri
|
||||
LL_COMMON_API void timeToFormattedString(time_t time, std::string format, std::string ×tr);
|
||||
LL_COMMON_API void timeStructToFormattedString(struct tm * time, std::string format, std::string ×tr);
|
||||
|
||||
// class for scheduling a function to be called at a given frequency (approximate, inprecise)
|
||||
class LL_COMMON_API LLEventTimer
|
||||
{
|
||||
public:
|
||||
LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds
|
||||
LLEventTimer(const LLDate& time);
|
||||
virtual ~LLEventTimer();
|
||||
|
||||
//function to be called at the supplied frequency
|
||||
// Normally return FALSE; TRUE will delete the timer after the function returns.
|
||||
virtual BOOL tick() = 0;
|
||||
|
||||
static void updateClass();
|
||||
|
||||
protected:
|
||||
LLTimer mEventTimer;
|
||||
F32 mPeriod;
|
||||
|
||||
private:
|
||||
//list of active timers
|
||||
static std::list<LLEventTimer*> sActiveList; // TODO should this be a vector
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -43,7 +43,6 @@ const F32 SEC_TO_MICROSEC = 1000000.f;
|
||||
const U64 SEC_TO_MICROSEC_U64 = 1000000;
|
||||
const U32 SEC_PER_DAY = 86400;
|
||||
|
||||
// This is just a stub, implementation in lltimer.cpp. This file will be deprecated in the future.
|
||||
LL_COMMON_API U64 totalTime(); // Returns current system time in microseconds
|
||||
// functionality has been moved lltimer.{cpp,h}. This file will be deprecated in the future.
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,13 +29,15 @@
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#include "llcrashlogger.h"
|
||||
#include "linden_common.h"
|
||||
#include "llstring.h"
|
||||
#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME
|
||||
#include "llerror.h"
|
||||
|
||||
@@ -32,10 +32,10 @@
|
||||
#ifndef LLCRASHLOGGER_H
|
||||
#define LLCRASHLOGGER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "llapp.h"
|
||||
#include "llsd.h"
|
||||
#include "llcontrol.h"
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
*/
|
||||
|
||||
// Precompiled header: almost always required for newview cpp files
|
||||
#include "../llcommon/linden_common.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "linden_common.h"
|
||||
#include <iostream>
|
||||
|
||||
#include "llsaleinfo.h"
|
||||
|
||||
|
||||
@@ -45,7 +45,8 @@ LLCamera::LLCamera() :
|
||||
mNearPlane(DEFAULT_NEAR_PLANE),
|
||||
mFarPlane(DEFAULT_FAR_PLANE),
|
||||
mFixedDistance(-1.f),
|
||||
mPlaneCount(6)
|
||||
mPlaneCount(6),
|
||||
mFrustumCornerDist(0.f)
|
||||
{
|
||||
calculateFrustumPlanes();
|
||||
}
|
||||
@@ -55,7 +56,8 @@ LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_p
|
||||
LLCoordFrame(),
|
||||
mViewHeightInPixels(view_height_in_pixels),
|
||||
mFixedDistance(-1.f),
|
||||
mPlaneCount(6)
|
||||
mPlaneCount(6),
|
||||
mFrustumCornerDist(0.f)
|
||||
{
|
||||
mAspect = llclamp(aspect_ratio, MIN_ASPECT_RATIO, MAX_ASPECT_RATIO);
|
||||
mNearPlane = llclamp(near_plane, MIN_NEAR_PLANE, MAX_NEAR_PLANE);
|
||||
@@ -65,6 +67,10 @@ LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_p
|
||||
setView(vertical_fov_rads);
|
||||
}
|
||||
|
||||
LLCamera::~LLCamera()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// ---------------- LLCamera::getFoo() member functions ----------------
|
||||
|
||||
@@ -86,11 +92,11 @@ F32 LLCamera::getMaxView() const
|
||||
|
||||
// ---------------- LLCamera::setFoo() member functions ----------------
|
||||
|
||||
void LLCamera::setUserClipPlane(LLPlane plane)
|
||||
void LLCamera::setUserClipPlane(LLPlane const& plane)
|
||||
{
|
||||
mPlaneCount = 7;
|
||||
mAgentPlanes[6].p = plane;
|
||||
mAgentPlanes[6].mask = calcPlaneMask(plane);
|
||||
mAgentPlanes[6] = plane;
|
||||
mPlaneMask[6] = plane.calcPlaneMask();
|
||||
}
|
||||
|
||||
void LLCamera::disableUserClipPlane()
|
||||
@@ -178,7 +184,7 @@ S32 LLCamera::AABBInFrustum(const LLVector3 ¢er, const LLVector3& radius)
|
||||
U8 mask = 0;
|
||||
S32 result = 2;
|
||||
|
||||
if (radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist)
|
||||
/*if (radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist)
|
||||
{ //box is larger than frustum, check frustum quads against box planes
|
||||
|
||||
static const LLVector3 dir[] =
|
||||
@@ -241,12 +247,16 @@ S32 LLCamera::AABBInFrustum(const LLVector3 ¢er, const LLVector3& radius)
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
else*/
|
||||
{
|
||||
for (U32 i = 0; i < mPlaneCount; i++)
|
||||
{
|
||||
mask = mAgentPlanes[i].mask;
|
||||
LLPlane p = mAgentPlanes[i].p;
|
||||
mask = mPlaneMask[i];
|
||||
if (mask == 0xff)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
LLPlane p = mAgentPlanes[i];
|
||||
LLVector3 n = LLVector3(p);
|
||||
float d = p.mV[3];
|
||||
LLVector3 rscale = radius.scaledVec(scaler[mask]);
|
||||
@@ -293,8 +303,12 @@ S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 ¢er, const LLVector3& r
|
||||
continue;
|
||||
}
|
||||
|
||||
mask = mAgentPlanes[i].mask;
|
||||
LLPlane p = mAgentPlanes[i].p;
|
||||
mask = mPlaneMask[i];
|
||||
if (mask == 0xff)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
LLPlane p = mAgentPlanes[i];
|
||||
LLVector3 n = LLVector3(p);
|
||||
float d = p.mV[3];
|
||||
LLVector3 rscale = radius.scaledVec(scaler[mask]);
|
||||
@@ -434,23 +448,22 @@ int LLCamera::sphereInFrustumOld(const LLVector3 &sphere_center, const F32 radiu
|
||||
int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius) const
|
||||
{
|
||||
// Returns 1 if sphere is in frustum, 0 if not.
|
||||
int res = 2;
|
||||
bool res = false;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
float d = mAgentPlanes[i].p.dist(sphere_center);
|
||||
|
||||
if (d > radius)
|
||||
if (mPlaneMask[i] != 0xff)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
float d = mAgentPlanes[i].dist(sphere_center);
|
||||
|
||||
if (d > -radius)
|
||||
{
|
||||
res = 1;
|
||||
if (d > radius)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
res = res || (d > -radius);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
return res?1:2;
|
||||
}
|
||||
|
||||
|
||||
@@ -602,29 +615,20 @@ LLPlane planeFromPoints(LLVector3 p1, LLVector3 p2, LLVector3 p3)
|
||||
return LLPlane(p1, n);
|
||||
}
|
||||
|
||||
U8 LLCamera::calcPlaneMask(const LLPlane& plane)
|
||||
|
||||
void LLCamera::ignoreAgentFrustumPlane(S32 idx)
|
||||
{
|
||||
U8 mask = 0;
|
||||
|
||||
if (plane.mV[0] >= 0)
|
||||
if (idx < 0 || idx > (S32) mPlaneCount)
|
||||
{
|
||||
mask |= 1;
|
||||
}
|
||||
if (plane.mV[1] >= 0)
|
||||
{
|
||||
mask |= 2;
|
||||
}
|
||||
if (plane.mV[2] >= 0)
|
||||
{
|
||||
mask |= 4;
|
||||
return;
|
||||
}
|
||||
|
||||
return mask;
|
||||
mPlaneMask[idx] = 0xff;
|
||||
mAgentPlanes[idx].clear();
|
||||
}
|
||||
|
||||
void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)
|
||||
{
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
mAgentFrustum[i] = frust[i];
|
||||
@@ -637,27 +641,27 @@ void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)
|
||||
//order of planes is important, keep most likely to fail in the front of the list
|
||||
|
||||
//near - frust[0], frust[1], frust[2]
|
||||
mAgentPlanes[2].p = planeFromPoints(frust[0], frust[1], frust[2]);
|
||||
mAgentPlanes[2] = planeFromPoints(frust[0], frust[1], frust[2]);
|
||||
|
||||
//far
|
||||
mAgentPlanes[5].p = planeFromPoints(frust[5], frust[4], frust[6]);
|
||||
mAgentPlanes[5] = planeFromPoints(frust[5], frust[4], frust[6]);
|
||||
|
||||
//left
|
||||
mAgentPlanes[0].p = planeFromPoints(frust[4], frust[0], frust[7]);
|
||||
mAgentPlanes[0] = planeFromPoints(frust[4], frust[0], frust[7]);
|
||||
|
||||
//right
|
||||
mAgentPlanes[1].p = planeFromPoints(frust[1], frust[5], frust[6]);
|
||||
mAgentPlanes[1] = planeFromPoints(frust[1], frust[5], frust[6]);
|
||||
|
||||
//top
|
||||
mAgentPlanes[4].p = planeFromPoints(frust[3], frust[2], frust[6]);
|
||||
mAgentPlanes[4] = planeFromPoints(frust[3], frust[2], frust[6]);
|
||||
|
||||
//bottom
|
||||
mAgentPlanes[3].p = planeFromPoints(frust[1], frust[0], frust[4]);
|
||||
mAgentPlanes[3] = planeFromPoints(frust[1], frust[0], frust[4]);
|
||||
|
||||
//cache plane octant facing mask for use in AABBInFrustum
|
||||
for (U32 i = 0; i < mPlaneCount; i++)
|
||||
{
|
||||
mAgentPlanes[i].mask = calcPlaneMask(mAgentPlanes[i].p);
|
||||
mPlaneMask[i] = mAgentPlanes[i].calcPlaneMask();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,12 @@ class LLCamera
|
||||
: public LLCoordFrame
|
||||
{
|
||||
public:
|
||||
|
||||
LLCamera(const LLCamera& rhs)
|
||||
{
|
||||
*this = rhs;
|
||||
}
|
||||
|
||||
enum {
|
||||
PLANE_LEFT = 0,
|
||||
PLANE_RIGHT = 1,
|
||||
@@ -84,6 +90,17 @@ public:
|
||||
PLANE_TOP_MASK = (1<<PLANE_TOP),
|
||||
PLANE_ALL_MASK = 0xf
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
AGENT_PLANE_LEFT = 0,
|
||||
AGENT_PLANE_RIGHT,
|
||||
AGENT_PLANE_NEAR,
|
||||
AGENT_PLANE_BOTTOM,
|
||||
AGENT_PLANE_TOP,
|
||||
AGENT_PLANE_FAR,
|
||||
};
|
||||
|
||||
enum {
|
||||
HORIZ_PLANE_LEFT = 0,
|
||||
HORIZ_PLANE_RIGHT = 1,
|
||||
@@ -96,6 +113,9 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
LLPlane mAgentPlanes[7]; //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
|
||||
U8 mPlaneMask[8]; // 8 for alignment
|
||||
|
||||
F32 mView; // angle between top and bottom frustum planes in radians.
|
||||
F32 mAspect; // width/height
|
||||
S32 mViewHeightInPixels; // for ViewHeightInPixels() only
|
||||
@@ -109,29 +129,22 @@ private:
|
||||
LLPlane mWorldPlanes[PLANE_NUM];
|
||||
LLPlane mHorizPlanes[HORIZ_PLANE_NUM];
|
||||
|
||||
struct frustum_plane
|
||||
{
|
||||
frustum_plane() : mask(0) {}
|
||||
LLPlane p;
|
||||
U8 mask;
|
||||
};
|
||||
frustum_plane mAgentPlanes[7]; //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
|
||||
|
||||
U32 mPlaneCount; //defaults to 6, if setUserClipPlane is called, uses user supplied clip plane in
|
||||
|
||||
LLVector3 mWorldPlanePos; // Position of World Planes (may be offset from camera)
|
||||
public:
|
||||
LLVector3 mAgentFrustum[8]; //8 corners of 6-plane frustum
|
||||
F32 mFrustumCornerDist; //distance to corner of frustum against far clip plane
|
||||
|
||||
LLPlane& getAgentPlane(U32 idx) { return mAgentPlanes[idx]; }
|
||||
|
||||
public:
|
||||
LLCamera();
|
||||
LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane);
|
||||
virtual ~LLCamera(){} // no-op virtual destructor
|
||||
virtual ~LLCamera();
|
||||
|
||||
|
||||
void setUserClipPlane(LLPlane plane);
|
||||
void setUserClipPlane(LLPlane const& plane);
|
||||
void disableUserClipPlane();
|
||||
U8 calcPlaneMask(const LLPlane& plane);
|
||||
virtual void setView(F32 vertical_fov_rads);
|
||||
void setViewHeightInPixels(S32 height);
|
||||
void setAspect(F32 new_aspect);
|
||||
@@ -170,6 +183,8 @@ public:
|
||||
// Return number of bytes copied.
|
||||
size_t readFrustumFromBuffer(const char *buffer);
|
||||
void calcAgentFrustumPlanes(LLVector3* frust);
|
||||
void ignoreAgentFrustumPlane(S32 idx);
|
||||
|
||||
// Returns 1 if partly in, 2 if fully in.
|
||||
// NOTE: 'center' is in absolute frame.
|
||||
S32 sphereInFrustumOld(const LLVector3 ¢er, const F32 radius) const;
|
||||
|
||||
@@ -384,11 +384,14 @@ inline F32 snap_to_sig_figs(F32 foo, S32 sig_figs)
|
||||
bar *= 10.f;
|
||||
}
|
||||
|
||||
foo = (F32)llround(foo * bar);
|
||||
//F32 new_foo = (F32)llround(foo * bar);
|
||||
// the llround() implementation sucks. Don't us it.
|
||||
|
||||
// shift back
|
||||
foo /= bar;
|
||||
return foo;
|
||||
F32 sign = (foo > 0.f) ? 1.f : -1.f;
|
||||
F32 new_foo = F32( S64(foo * bar + sign * 0.5f));
|
||||
new_foo /= bar;
|
||||
|
||||
return new_foo;
|
||||
}
|
||||
|
||||
inline F32 lerp(F32 a, F32 b, F32 u)
|
||||
@@ -522,4 +525,41 @@ inline F32 llgaussian(F32 x, F32 o)
|
||||
return 1.f/(F_SQRT_TWO_PI*o)*powf(F_E, -(x*x)/(2*o*o));
|
||||
}
|
||||
|
||||
//helper function for removing outliers
|
||||
template <class VEC_TYPE>
|
||||
inline void ll_remove_outliers(std::vector<VEC_TYPE>& data, F32 k)
|
||||
{
|
||||
if (data.size() < 100)
|
||||
{ //not enough samples
|
||||
return;
|
||||
}
|
||||
|
||||
VEC_TYPE Q1 = data[data.size()/4];
|
||||
VEC_TYPE Q3 = data[data.size()-data.size()/4-1];
|
||||
|
||||
VEC_TYPE min = (VEC_TYPE) ((F32) Q1-k * (F32) (Q3-Q1));
|
||||
VEC_TYPE max = (VEC_TYPE) ((F32) Q3+k * (F32) (Q3-Q1));
|
||||
|
||||
U32 i = 0;
|
||||
while (i < data.size() && data[i] < min)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
S32 j = data.size()-1;
|
||||
while (j > 0 && data[j] > max)
|
||||
{
|
||||
j--;
|
||||
}
|
||||
|
||||
if (j < data.size()-1)
|
||||
{
|
||||
data.erase(data.begin()+j, data.end());
|
||||
}
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
data.erase(data.begin(), data.begin()+i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -73,6 +73,13 @@ public:
|
||||
virtual void visit(const LLOctreeNode<T>* branch) = 0;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class LLOctreeTravelerDepthFirst : public LLOctreeTraveler<T>
|
||||
{
|
||||
public:
|
||||
virtual void traverse(const LLOctreeNode<T>* node);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class LLOctreeNode : public LLTreeNode<T>
|
||||
{
|
||||
@@ -124,11 +131,10 @@ public:
|
||||
inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; }
|
||||
inline const LLVector3d& getCenter() const { return mCenter; }
|
||||
inline const LLVector3d& getSize() const { return mSize; }
|
||||
inline void setCenter(LLVector3d center) { mCenter = center; }
|
||||
inline void setSize(LLVector3d size) { mSize = size; }
|
||||
inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
|
||||
inline U8 getOctant() const { return mOctant; }
|
||||
inline void setOctant(U8 octant) { mOctant = octant; }
|
||||
inline void setCenter(const LLVector3d center) { mCenter = center; }
|
||||
inline void setSize(const LLVector3d size) { mSize = size; }
|
||||
inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
|
||||
inline U8 getOctant() const { return mOctant; }
|
||||
inline const oct_node* getOctParent() const { return (const oct_node*) getParent(); }
|
||||
inline oct_node* getOctParent() { return (oct_node*) getParent(); }
|
||||
|
||||
@@ -197,17 +203,17 @@ public:
|
||||
return contains(xform->getBinRadius());
|
||||
}
|
||||
|
||||
bool contains(F64 radius)
|
||||
bool contains(F32 radius)
|
||||
{
|
||||
if (mParent == NULL)
|
||||
{ //root node contains nothing
|
||||
return false;
|
||||
}
|
||||
|
||||
F64 size = mSize.mdV[0];
|
||||
F64 p_size = size * 2.0;
|
||||
F32 size = mSize[0];
|
||||
F32 p_size = size * 2.f;
|
||||
|
||||
return (radius <= 0.001 && size <= 0.001) ||
|
||||
return (radius <= 0.001f && size <= 0.001f) ||
|
||||
(radius <= p_size && radius > size);
|
||||
}
|
||||
|
||||
@@ -243,7 +249,30 @@ public:
|
||||
void accept(tree_traveler* visitor) const { visitor->visit(this); }
|
||||
void accept(oct_traveler* visitor) const { visitor->visit(this); }
|
||||
|
||||
oct_node* getNodeAt(const LLVector3d& pos, const F64& rad)
|
||||
void validateChildMap()
|
||||
{
|
||||
for (U32 i = 0; i < 8; i++)
|
||||
{
|
||||
U8 idx = mChildMap[i];
|
||||
if (idx != 255)
|
||||
{
|
||||
LLOctreeNode<T>* child = mChild[idx];
|
||||
|
||||
if (child->getOctant() != i)
|
||||
{
|
||||
llerrs << "Invalid child map, bad octant data." << llendl;
|
||||
}
|
||||
|
||||
if (getOctant(child->getCenter()) != child->getOctant())
|
||||
{
|
||||
llerrs << "Invalid child octant compared to position data." << llendl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
oct_node* getNodeAt(const LLVector3d& pos, const F32& rad)
|
||||
{
|
||||
LLOctreeNode<T>* node = this;
|
||||
|
||||
@@ -251,24 +280,18 @@ public:
|
||||
{
|
||||
//do a quick search by octant
|
||||
U8 octant = node->getOctant(pos.mdV);
|
||||
BOOL keep_going = TRUE;
|
||||
|
||||
|
||||
//traverse the tree until we find a node that has no node
|
||||
//at the appropriate octant or is smaller than the object.
|
||||
//by definition, that node is the smallest node that contains
|
||||
// the data
|
||||
while (keep_going && node->getSize().mdV[0] >= rad)
|
||||
U8 next_node = node->mChildMap[octant];
|
||||
|
||||
while (next_node != 255 && node->getSize()[0] >= rad)
|
||||
{
|
||||
keep_going = FALSE;
|
||||
for (U32 i = 0; i < node->getChildCount() && !keep_going; i++)
|
||||
{
|
||||
if (node->getChild(i)->getOctant() == octant)
|
||||
{
|
||||
node = node->getChild(i);
|
||||
octant = node->getOctant(pos.mdV);
|
||||
keep_going = TRUE;
|
||||
}
|
||||
}
|
||||
node = node->getChild(next_node);
|
||||
octant = node->getOctant(pos.mdV);
|
||||
next_node = node->mChildMap[octant];
|
||||
}
|
||||
}
|
||||
else if (!node->contains(rad) && node->getParent())
|
||||
@@ -444,6 +467,9 @@ public:
|
||||
void clearChildren()
|
||||
{
|
||||
mChild.clear();
|
||||
|
||||
U32* foo = (U32*) mChildMap;
|
||||
foo[0] = foo[1] = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
void validate()
|
||||
@@ -477,6 +503,12 @@ public:
|
||||
void addChild(oct_node* child, BOOL silent = FALSE)
|
||||
{
|
||||
#if LL_OCTREE_PARANOIA_CHECK
|
||||
|
||||
if (child->getSize() == getSize())
|
||||
{
|
||||
OCT_ERRS << "Child size is same as parent size!" << llendl;
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < getChildCount(); i++)
|
||||
{
|
||||
if(mChild[i]->getSize() != child->getSize())
|
||||
@@ -495,6 +527,8 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
mChildMap[child->getOctant()] = (U8) mChild.size();
|
||||
|
||||
mChild.push_back(child);
|
||||
child->setParent(this);
|
||||
|
||||
@@ -508,7 +542,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void removeChild(U8 index, BOOL destroy = FALSE)
|
||||
void removeChild(S32 index, BOOL destroy = FALSE)
|
||||
{
|
||||
for (U32 i = 0; i < this->getListenerCount(); i++)
|
||||
{
|
||||
@@ -516,6 +550,8 @@ public:
|
||||
listener->handleChildRemoval(this, getChild(index));
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (destroy)
|
||||
{
|
||||
mChild[index]->destroy();
|
||||
@@ -523,6 +559,15 @@ public:
|
||||
}
|
||||
mChild.erase(mChild.begin() + index);
|
||||
|
||||
//rebuild child map
|
||||
U32* foo = (U32*) mChildMap;
|
||||
foo[0] = foo[1] = 0xFFFFFFFF;
|
||||
|
||||
for (U32 i = 0; i < mChild.size(); ++i)
|
||||
{
|
||||
mChildMap[mChild[i]->getOctant()] = i;
|
||||
}
|
||||
|
||||
checkAlive();
|
||||
}
|
||||
|
||||
@@ -553,14 +598,27 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
child_list mChild;
|
||||
element_list mData;
|
||||
oct_node* mParent;
|
||||
typedef enum
|
||||
{
|
||||
CENTER = 0,
|
||||
SIZE = 1,
|
||||
MAX = 2,
|
||||
MIN = 3
|
||||
} eDName;
|
||||
|
||||
LLVector3d mCenter;
|
||||
LLVector3d mSize;
|
||||
LLVector3d mMax;
|
||||
LLVector3d mMin;
|
||||
|
||||
oct_node* mParent;
|
||||
U8 mOctant;
|
||||
|
||||
child_list mChild;
|
||||
U8 mChildMap[8];
|
||||
|
||||
element_list mData;
|
||||
|
||||
};
|
||||
|
||||
//just like a regular node, except it might expand on insert and compress on balance
|
||||
@@ -571,8 +629,8 @@ public:
|
||||
typedef LLOctreeNode<T> BaseType;
|
||||
typedef LLOctreeNode<T> oct_node;
|
||||
|
||||
LLOctreeRoot( LLVector3d center,
|
||||
LLVector3d size,
|
||||
LLOctreeRoot( const LLVector3d ¢er,
|
||||
const LLVector3d &size,
|
||||
BaseType* parent)
|
||||
: BaseType(center, size, parent)
|
||||
{
|
||||
@@ -604,6 +662,8 @@ public:
|
||||
//destroy child
|
||||
child->clearChildren();
|
||||
delete child;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -700,7 +760,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//========================
|
||||
// LLOctreeTraveler
|
||||
//========================
|
||||
@@ -714,4 +773,14 @@ void LLOctreeTraveler<T>::traverse(const LLOctreeNode<T>* node)
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void LLOctreeTravelerDepthFirst<T>::traverse(const LLOctreeNode<T>* node)
|
||||
{
|
||||
for (U32 i = 0; i < node->getChildCount(); i++)
|
||||
{
|
||||
traverse(node->getChild(i));
|
||||
}
|
||||
node->accept(this);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -48,13 +48,13 @@ public:
|
||||
LLPlane() {}; // no default constructor
|
||||
LLPlane(const LLVector3 &p0, F32 d) { setVec(p0, d); }
|
||||
LLPlane(const LLVector3 &p0, const LLVector3 &n) { setVec(p0, n); }
|
||||
void setVec(const LLVector3 &p0, F32 d) { LLVector4::setVec(p0[0], p0[1], p0[2], d); }
|
||||
void setVec(const LLVector3 &p0, const LLVector3 &n)
|
||||
inline void setVec(const LLVector3 &p0, F32 d) { LLVector4::setVec(p0[0], p0[1], p0[2], d); }
|
||||
inline void setVec(const LLVector3 &p0, const LLVector3 &n)
|
||||
{
|
||||
F32 d = -(p0 * n);
|
||||
setVec(n, d);
|
||||
}
|
||||
void setVec(const LLVector3 &p0, const LLVector3 &p1, const LLVector3 &p2)
|
||||
inline void setVec(const LLVector3 &p0, const LLVector3 &p1, const LLVector3 &p2)
|
||||
{
|
||||
LLVector3 u, v, w;
|
||||
u = p1 - p0;
|
||||
@@ -64,8 +64,39 @@ public:
|
||||
F32 d = -(w * p0);
|
||||
setVec(w, d);
|
||||
}
|
||||
LLPlane& operator=(const LLVector4& v2) { LLVector4::setVec(v2[0],v2[1],v2[2],v2[3]); return *this;}
|
||||
|
||||
inline LLPlane& operator=(const LLVector4& v2) { LLVector4::setVec(v2[0],v2[1],v2[2],v2[3]); return *this;}
|
||||
|
||||
inline void set(const LLPlane& p2) { LLVector4::setVec(p2); }
|
||||
|
||||
//
|
||||
F32 dist(const LLVector3 &v2) const { return mV[0]*v2[0] + mV[1]*v2[1] + mV[2]*v2[2] + mV[3]; }
|
||||
|
||||
// reset the vector to 0, 0, 0, 1
|
||||
inline void clear() { LLVector4::setVec(0, 0, 0, 1); }
|
||||
|
||||
inline void getVector3(LLVector3& vec) const { vec.set(mV[0], mV[1], mV[2]); }
|
||||
|
||||
// Retrieve the mask indicating which of the x, y, or z axis are greater or equal to zero.
|
||||
inline U8 calcPlaneMask() const
|
||||
{
|
||||
U8 mask = 0;
|
||||
|
||||
if (mV[0] >= 0)
|
||||
{
|
||||
mask |= 1;
|
||||
}
|
||||
if (mV[1] >= 0)
|
||||
{
|
||||
mask |= 2;
|
||||
}
|
||||
if (mV[2] >= 0)
|
||||
{
|
||||
mask |= 4;
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -32,9 +32,10 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llmath.h" // for F_PI
|
||||
|
||||
#include "llquaternion.h"
|
||||
|
||||
#include "llmath.h" // for F_PI
|
||||
//#include "vmath.h"
|
||||
#include "v3math.h"
|
||||
#include "v3dmath.h"
|
||||
|
||||
@@ -33,7 +33,11 @@
|
||||
#ifndef LLQUATERNION_H
|
||||
#define LLQUATERNION_H
|
||||
|
||||
#include "llmath.h"
|
||||
#include <iostream>
|
||||
|
||||
#ifndef LLMATH_H //enforce specific include order to avoid tangling inline dependencies
|
||||
#error "Please include llmath.h first."
|
||||
#endif
|
||||
|
||||
class LLVector4;
|
||||
class LLVector3;
|
||||
|
||||
@@ -103,27 +103,33 @@ BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLV
|
||||
|
||||
BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size)
|
||||
{
|
||||
float fAWdU[3];
|
||||
LLVector3 dir;
|
||||
LLVector3 diff;
|
||||
return LLLineSegmentBoxIntersect(start.mV, end.mV, center.mV, size.mV);
|
||||
}
|
||||
|
||||
BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size)
|
||||
{
|
||||
F32 fAWdU[3];
|
||||
F32 dir[3];
|
||||
F32 diff[3];
|
||||
|
||||
for (U32 i = 0; i < 3; i++)
|
||||
{
|
||||
dir.mV[i] = 0.5f * (end.mV[i] - start.mV[i]);
|
||||
diff.mV[i] = (0.5f * (end.mV[i] + start.mV[i])) - center.mV[i];
|
||||
fAWdU[i] = fabsf(dir.mV[i]);
|
||||
if(fabsf(diff.mV[i])>size.mV[i] + fAWdU[i]) return false;
|
||||
dir[i] = 0.5f * (end[i] - start[i]);
|
||||
diff[i] = (0.5f * (end[i] + start[i])) - center[i];
|
||||
fAWdU[i] = fabsf(dir[i]);
|
||||
if(fabsf(diff[i])>size[i] + fAWdU[i]) return false;
|
||||
}
|
||||
|
||||
float f;
|
||||
f = dir.mV[1] * diff.mV[2] - dir.mV[2] * diff.mV[1]; if(fabsf(f)>size.mV[1]*fAWdU[2] + size.mV[2]*fAWdU[1]) return false;
|
||||
f = dir.mV[2] * diff.mV[0] - dir.mV[0] * diff.mV[2]; if(fabsf(f)>size.mV[0]*fAWdU[2] + size.mV[2]*fAWdU[0]) return false;
|
||||
f = dir.mV[0] * diff.mV[1] - dir.mV[1] * diff.mV[0]; if(fabsf(f)>size.mV[0]*fAWdU[1] + size.mV[1]*fAWdU[0]) return false;
|
||||
f = dir[1] * diff[2] - dir[2] * diff[1]; if(fabsf(f)>size[1]*fAWdU[2] + size[2]*fAWdU[1]) return false;
|
||||
f = dir[2] * diff[0] - dir[0] * diff[2]; if(fabsf(f)>size[0]*fAWdU[2] + size[2]*fAWdU[0]) return false;
|
||||
f = dir[0] * diff[1] - dir[1] * diff[0]; if(fabsf(f)>size[0]*fAWdU[1] + size[1]*fAWdU[0]) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir.
|
||||
// returns TRUE if intersecting and returns barycentric coordinates in intersection_a, intersection_b,
|
||||
// and returns the intersection point along dir in intersection_t.
|
||||
@@ -1688,7 +1694,8 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge
|
||||
mGenerateSingleFace = generate_single_face;
|
||||
|
||||
generate();
|
||||
if (mParams.getSculptID().isNull() && params.getSculptType() == LL_SCULPT_TYPE_NONE)
|
||||
|
||||
if (mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE)
|
||||
{
|
||||
createVolumeFaces();
|
||||
}
|
||||
|
||||
@@ -984,6 +984,7 @@ LLVector3 calc_binormal_from_triangle(
|
||||
const LLVector3& pos2,
|
||||
const LLVector2& tex2);
|
||||
|
||||
BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size);
|
||||
BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size);
|
||||
BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
|
||||
F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided);
|
||||
|
||||
@@ -221,8 +221,33 @@ const LLMatrix4& LLMatrix4::transpose()
|
||||
|
||||
F32 LLMatrix4::determinant() const
|
||||
{
|
||||
llerrs << "Not implemented!" << llendl;
|
||||
return 0.f;
|
||||
F32 value =
|
||||
mMatrix[0][3] * mMatrix[1][2] * mMatrix[2][1] * mMatrix[3][0] -
|
||||
mMatrix[0][2] * mMatrix[1][3] * mMatrix[2][1] * mMatrix[3][0] -
|
||||
mMatrix[0][3] * mMatrix[1][1] * mMatrix[2][2] * mMatrix[3][0] +
|
||||
mMatrix[0][1] * mMatrix[1][3] * mMatrix[2][2] * mMatrix[3][0] +
|
||||
mMatrix[0][2] * mMatrix[1][1] * mMatrix[2][3] * mMatrix[3][0] -
|
||||
mMatrix[0][1] * mMatrix[1][2] * mMatrix[2][3] * mMatrix[3][0] -
|
||||
mMatrix[0][3] * mMatrix[1][2] * mMatrix[2][0] * mMatrix[3][1] +
|
||||
mMatrix[0][2] * mMatrix[1][3] * mMatrix[2][0] * mMatrix[3][1] +
|
||||
mMatrix[0][3] * mMatrix[1][0] * mMatrix[2][2] * mMatrix[3][1] -
|
||||
mMatrix[0][0] * mMatrix[1][3] * mMatrix[2][2] * mMatrix[3][1] -
|
||||
mMatrix[0][2] * mMatrix[1][0] * mMatrix[2][3] * mMatrix[3][1] +
|
||||
mMatrix[0][0] * mMatrix[1][2] * mMatrix[2][3] * mMatrix[3][1] +
|
||||
mMatrix[0][3] * mMatrix[1][1] * mMatrix[2][0] * mMatrix[3][2] -
|
||||
mMatrix[0][1] * mMatrix[1][3] * mMatrix[2][0] * mMatrix[3][2] -
|
||||
mMatrix[0][3] * mMatrix[1][0] * mMatrix[2][1] * mMatrix[3][2] +
|
||||
mMatrix[0][0] * mMatrix[1][3] * mMatrix[2][1] * mMatrix[3][2] +
|
||||
mMatrix[0][1] * mMatrix[1][0] * mMatrix[2][3] * mMatrix[3][2] -
|
||||
mMatrix[0][0] * mMatrix[1][1] * mMatrix[2][3] * mMatrix[3][2] -
|
||||
mMatrix[0][2] * mMatrix[1][1] * mMatrix[2][0] * mMatrix[3][3] +
|
||||
mMatrix[0][1] * mMatrix[1][2] * mMatrix[2][0] * mMatrix[3][3] +
|
||||
mMatrix[0][2] * mMatrix[1][0] * mMatrix[2][1] * mMatrix[3][3] -
|
||||
mMatrix[0][0] * mMatrix[1][2] * mMatrix[2][1] * mMatrix[3][3] -
|
||||
mMatrix[0][1] * mMatrix[1][0] * mMatrix[2][2] * mMatrix[3][3] +
|
||||
mMatrix[0][0] * mMatrix[1][1] * mMatrix[2][2] * mMatrix[3][3];
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Only works for pure orthonormal, homogeneous transform matrices.
|
||||
@@ -428,6 +453,17 @@ const LLMatrix4& LLMatrix4::initRotTrans(const LLQuaternion &q, const LLVector
|
||||
return (*this);
|
||||
}
|
||||
|
||||
const LLMatrix4& LLMatrix4::initScale(const LLVector3 &scale)
|
||||
{
|
||||
setIdentity();
|
||||
|
||||
mMatrix[VX][VX] = scale.mV[VX];
|
||||
mMatrix[VY][VY] = scale.mV[VY];
|
||||
mMatrix[VZ][VZ] = scale.mV[VZ];
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
const LLMatrix4& LLMatrix4::initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos)
|
||||
{
|
||||
F32 sx, sy, sz;
|
||||
@@ -774,6 +810,23 @@ bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool operator<(const LLMatrix4& a, const LLMatrix4 &b)
|
||||
{
|
||||
U32 i, j;
|
||||
for (i = 0; i < NUM_VALUES_IN_MAT4; i++)
|
||||
{
|
||||
for (j = 0; j < NUM_VALUES_IN_MAT4; j++)
|
||||
{
|
||||
if (a.mMatrix[i][j] != b.mMatrix[i][j])
|
||||
{
|
||||
return a.mMatrix[i][j] < b.mMatrix[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const LLMatrix4& operator*=(LLMatrix4 &a, F32 k)
|
||||
{
|
||||
U32 i, j;
|
||||
@@ -813,4 +866,54 @@ std::ostream& operator<<(std::ostream& s, const LLMatrix4 &a)
|
||||
return s;
|
||||
}
|
||||
|
||||
LLSD LLMatrix4::getValue() const
|
||||
{
|
||||
LLSD ret;
|
||||
|
||||
ret[0] = mMatrix[0][0];
|
||||
ret[1] = mMatrix[0][1];
|
||||
ret[2] = mMatrix[0][2];
|
||||
ret[3] = mMatrix[0][3];
|
||||
|
||||
ret[4] = mMatrix[1][0];
|
||||
ret[5] = mMatrix[1][1];
|
||||
ret[6] = mMatrix[1][2];
|
||||
ret[7] = mMatrix[1][3];
|
||||
|
||||
ret[8] = mMatrix[2][0];
|
||||
ret[9] = mMatrix[2][1];
|
||||
ret[10] = mMatrix[2][2];
|
||||
ret[11] = mMatrix[2][3];
|
||||
|
||||
ret[12] = mMatrix[3][0];
|
||||
ret[13] = mMatrix[3][1];
|
||||
ret[14] = mMatrix[3][2];
|
||||
ret[15] = mMatrix[3][3];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LLMatrix4::setValue(const LLSD& data)
|
||||
{
|
||||
mMatrix[0][0] = data[0].asReal();
|
||||
mMatrix[0][1] = data[1].asReal();
|
||||
mMatrix[0][2] = data[2].asReal();
|
||||
mMatrix[0][3] = data[3].asReal();
|
||||
|
||||
mMatrix[1][0] = data[4].asReal();
|
||||
mMatrix[1][1] = data[5].asReal();
|
||||
mMatrix[1][2] = data[6].asReal();
|
||||
mMatrix[1][3] = data[7].asReal();
|
||||
|
||||
mMatrix[2][0] = data[8].asReal();
|
||||
mMatrix[2][1] = data[9].asReal();
|
||||
mMatrix[2][2] = data[10].asReal();
|
||||
mMatrix[2][3] = data[11].asReal();
|
||||
|
||||
mMatrix[3][0] = data[12].asReal();
|
||||
mMatrix[3][1] = data[13].asReal();
|
||||
mMatrix[3][2] = data[14].asReal();
|
||||
mMatrix[3][3] = data[15].asReal();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -125,6 +125,8 @@ public:
|
||||
|
||||
~LLMatrix4(void); // Destructor
|
||||
|
||||
LLSD getValue() const;
|
||||
void setValue(const LLSD&);
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
@@ -138,6 +140,7 @@ public:
|
||||
|
||||
// various useful matrix functions
|
||||
const LLMatrix4& setIdentity(); // Load identity matrix
|
||||
bool isIdentity() const;
|
||||
const LLMatrix4& setZero(); // Clears matrix to all zeros.
|
||||
|
||||
const LLMatrix4& initRotation(const F32 angle, const F32 x, const F32 y, const F32 z); // Calculate rotation matrix by rotating angle radians about (x, y, z)
|
||||
@@ -159,6 +162,7 @@ public:
|
||||
const LLMatrix4& initRotTrans(const F32 roll, const F32 pitch, const F32 yaw, const LLVector4 &pos); // Rotation from Euler + translation
|
||||
const LLMatrix4& initRotTrans(const LLQuaternion &q, const LLVector4 &pos); // Set with Quaternion and position
|
||||
|
||||
const LLMatrix4& initScale(const LLVector3 &scale);
|
||||
|
||||
// Set all
|
||||
const LLMatrix4& initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos);
|
||||
@@ -236,6 +240,7 @@ public:
|
||||
|
||||
friend bool operator==(const LLMatrix4 &a, const LLMatrix4 &b); // Return a == b
|
||||
friend bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b); // Return a != b
|
||||
friend bool operator<(const LLMatrix4 &a, const LLMatrix4& b); // Return a < b
|
||||
|
||||
friend const LLMatrix4& operator+=(LLMatrix4 &a, const LLMatrix4 &b); // Return a + b
|
||||
friend const LLMatrix4& operator-=(LLMatrix4 &a, const LLMatrix4 &b); // Return a - b
|
||||
@@ -269,6 +274,30 @@ inline const LLMatrix4& LLMatrix4::setIdentity()
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline bool LLMatrix4::isIdentity() const
|
||||
{
|
||||
return
|
||||
mMatrix[0][0] == 1.f &&
|
||||
mMatrix[0][1] == 0.f &&
|
||||
mMatrix[0][2] == 0.f &&
|
||||
mMatrix[0][3] == 0.f &&
|
||||
|
||||
mMatrix[1][0] == 0.f &&
|
||||
mMatrix[1][1] == 1.f &&
|
||||
mMatrix[1][2] == 0.f &&
|
||||
mMatrix[1][3] == 0.f &&
|
||||
|
||||
mMatrix[2][0] == 0.f &&
|
||||
mMatrix[2][1] == 0.f &&
|
||||
mMatrix[2][2] == 1.f &&
|
||||
mMatrix[2][3] == 0.f &&
|
||||
|
||||
mMatrix[3][0] == 0.f &&
|
||||
mMatrix[3][1] == 0.f &&
|
||||
mMatrix[3][2] == 0.f &&
|
||||
mMatrix[3][3] == 1.f;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b)
|
||||
|
||||
@@ -115,3 +115,18 @@ LLVector2 lerp(const LLVector2 &a, const LLVector2 &b, F32 u)
|
||||
a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u,
|
||||
a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u );
|
||||
}
|
||||
|
||||
LLSD LLVector2::getValue() const
|
||||
{
|
||||
LLSD ret;
|
||||
ret[0] = mV[0];
|
||||
ret[1] = mV[1];
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LLVector2::setValue(LLSD& sd)
|
||||
{
|
||||
mV[0] = (F32) sd[0].asReal();
|
||||
mV[1] = (F32) sd[1].asReal();
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,9 @@ class LLVector2
|
||||
void set(const LLVector2 &vec); // Sets LLVector2 to vec
|
||||
void set(const F32 *vec); // Sets LLVector2 to vec
|
||||
|
||||
LLSD getValue() const;
|
||||
void setValue(LLSD& sd);
|
||||
|
||||
void setVec(F32 x, F32 y); // deprecated
|
||||
void setVec(const LLVector2 &vec); // deprecated
|
||||
void setVec(const F32 *vec); // deprecated
|
||||
|
||||
@@ -140,6 +140,21 @@ BOOL LLVector3::clampLength( F32 length_limit )
|
||||
return changed;
|
||||
}
|
||||
|
||||
BOOL LLVector3::clamp(const LLVector3 &min_vec, const LLVector3 &max_vec)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
|
||||
if (mV[0] < min_vec[0]) { mV[0] = min_vec[0]; ret = TRUE; }
|
||||
if (mV[1] < min_vec[1]) { mV[1] = min_vec[1]; ret = TRUE; }
|
||||
if (mV[2] < min_vec[2]) { mV[2] = min_vec[2]; ret = TRUE; }
|
||||
|
||||
if (mV[0] > max_vec[0]) { mV[0] = max_vec[0]; ret = TRUE; }
|
||||
if (mV[1] > max_vec[1]) { mV[1] = max_vec[1]; ret = TRUE; }
|
||||
if (mV[2] > max_vec[2]) { mV[2] = max_vec[2]; ret = TRUE; }
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// Sets all values to absolute value of their original values
|
||||
// Returns TRUE if data changed
|
||||
@@ -197,6 +212,28 @@ const LLVector3& LLVector3::rotVec(const LLQuaternion &q)
|
||||
return *this;
|
||||
}
|
||||
|
||||
const LLVector3& LLVector3::transVec(const LLMatrix4& mat)
|
||||
{
|
||||
setVec(
|
||||
mV[VX] * mat.mMatrix[VX][VX] +
|
||||
mV[VY] * mat.mMatrix[VX][VY] +
|
||||
mV[VZ] * mat.mMatrix[VX][VZ] +
|
||||
mat.mMatrix[VX][VW],
|
||||
|
||||
mV[VX] * mat.mMatrix[VY][VX] +
|
||||
mV[VY] * mat.mMatrix[VY][VY] +
|
||||
mV[VZ] * mat.mMatrix[VY][VZ] +
|
||||
mat.mMatrix[VY][VW],
|
||||
|
||||
mV[VX] * mat.mMatrix[VZ][VX] +
|
||||
mV[VY] * mat.mMatrix[VZ][VY] +
|
||||
mV[VZ] * mat.mMatrix[VZ][VZ] +
|
||||
mat.mMatrix[VZ][VW]);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
const LLVector3& LLVector3::rotVec(F32 angle, const LLVector3 &vec)
|
||||
{
|
||||
if ( !vec.isExactlyZero() && angle )
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
class LLVector2;
|
||||
class LLVector4;
|
||||
class LLMatrix3;
|
||||
class LLMatrix4;
|
||||
class LLVector3d;
|
||||
class LLQuaternion;
|
||||
|
||||
@@ -75,6 +76,7 @@ class LLVector3
|
||||
|
||||
inline BOOL isFinite() const; // checks to see if all values of LLVector3 are finite
|
||||
BOOL clamp(F32 min, F32 max); // Clamps all values to (min,max), returns TRUE if data changed
|
||||
BOOL clamp(const LLVector3 &min_vec, const LLVector3 &max_vec); // Scales vector by another vector
|
||||
BOOL clampLength( F32 length_limit ); // Scales vector to limit length to a value
|
||||
|
||||
void quantize16(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz); // changes the vector to reflect quatization
|
||||
@@ -115,6 +117,7 @@ class LLVector3
|
||||
const LLVector3& rotVec(F32 angle, F32 x, F32 y, F32 z); // Rotates about x,y,z by angle radians
|
||||
const LLVector3& rotVec(const LLMatrix3 &mat); // Rotates by LLMatrix4 mat
|
||||
const LLVector3& rotVec(const LLQuaternion &q); // Rotates by LLQuaternion q
|
||||
const LLVector3& transVec(const LLMatrix4& mat); // Transforms by LLMatrix4 mat (mat * v)
|
||||
|
||||
const LLVector3& scaleVec(const LLVector3& vec); // scales per component by vec
|
||||
LLVector3 scaledVec(const LLVector3& vec) const; // get a copy of this vector scaled by vec
|
||||
@@ -162,6 +165,8 @@ F32 dist_vec(const LLVector3 &a, const LLVector3 &b); // Returns distance betwe
|
||||
F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b);// Returns distance squared between a and b
|
||||
F32 dist_vec_squared2D(const LLVector3 &a, const LLVector3 &b);// Returns distance squared between a and b ignoring Z component
|
||||
LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b); // Returns vector a projected on vector b
|
||||
LLVector3 parallel_component(const LLVector3 &a, const LLVector3 &b); // Returns vector a projected on vector b (same as projected_vec)
|
||||
LLVector3 orthogonal_component(const LLVector3 &a, const LLVector3 &b); // Returns component of vector a not parallel to vector b (same as projected_vec)
|
||||
LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u); // Returns a vector that is a linear interpolation between a and b
|
||||
|
||||
inline LLVector3::LLVector3(void)
|
||||
@@ -496,6 +501,17 @@ inline LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b)
|
||||
return project_axis * (a * project_axis);
|
||||
}
|
||||
|
||||
inline LLVector3 parallel_component(const LLVector3 &a, const LLVector3 &b)
|
||||
{
|
||||
return projected_vec(a, b);
|
||||
}
|
||||
|
||||
inline LLVector3 orthogonal_component(const LLVector3 &a, const LLVector3 &b)
|
||||
{
|
||||
return a - projected_vec(a, b);
|
||||
}
|
||||
|
||||
|
||||
inline LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u)
|
||||
{
|
||||
return LLVector3(
|
||||
@@ -529,6 +545,21 @@ inline void update_min_max(LLVector3& min, LLVector3& max, const LLVector3& pos)
|
||||
}
|
||||
}
|
||||
|
||||
inline void update_min_max(LLVector3& min, LLVector3& max, const F32* pos)
|
||||
{
|
||||
for (U32 i = 0; i < 3; i++)
|
||||
{
|
||||
if (min.mV[i] > pos[i])
|
||||
{
|
||||
min.mV[i] = pos[i];
|
||||
}
|
||||
if (max.mV[i] < pos[i])
|
||||
{
|
||||
max.mV[i] = pos[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline F32 angle_between(const LLVector3& a, const LLVector3& b)
|
||||
{
|
||||
LLVector3 an = a;
|
||||
|
||||
@@ -114,6 +114,7 @@ class LLColor4
|
||||
|
||||
const LLColor4& operator=(const LLColor3 &a); // Assigns vec3 to vec4 and returns vec4
|
||||
|
||||
bool operator<(const LLColor4& rhs) const;
|
||||
friend std::ostream& operator<<(std::ostream& s, const LLColor4 &a); // Print a
|
||||
friend LLColor4 operator+(const LLColor4 &a, const LLColor4 &b); // Return vector a + b
|
||||
friend LLColor4 operator-(const LLColor4 &a, const LLColor4 &b); // Return vector a minus b
|
||||
@@ -595,6 +596,23 @@ inline LLColor4 lerp(const LLColor4 &a, const LLColor4 &b, F32 u)
|
||||
a.mV[VW] + (b.mV[VW] - a.mV[VW]) * u);
|
||||
}
|
||||
|
||||
inline bool LLColor4::operator<(const LLColor4& rhs) const
|
||||
{
|
||||
if (mV[0] != rhs.mV[0])
|
||||
{
|
||||
return mV[0] < rhs.mV[0];
|
||||
}
|
||||
if (mV[1] != rhs.mV[1])
|
||||
{
|
||||
return mV[1] < rhs.mV[1];
|
||||
}
|
||||
if (mV[2] != rhs.mV[2])
|
||||
{
|
||||
return mV[2] < rhs.mV[2];
|
||||
}
|
||||
|
||||
return mV[3] < rhs.mV[3];
|
||||
}
|
||||
|
||||
void LLColor4::clamp()
|
||||
{
|
||||
|
||||
@@ -55,8 +55,8 @@
|
||||
#include "llstl.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llthread.h"
|
||||
|
||||
#include "llsocks5.h"
|
||||
#include "lltimer.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
@@ -92,6 +92,26 @@ std::vector<LLMutex*> LLCurl::sSSLMutex;
|
||||
std::string LLCurl::sCAPath;
|
||||
std::string LLCurl::sCAFile;
|
||||
|
||||
void check_curl_code(CURLcode code)
|
||||
{
|
||||
if (code != CURLE_OK)
|
||||
{
|
||||
// linux appears to throw a curl error once per session for a bad initialization
|
||||
// at a pretty random time (when enabling cookies).
|
||||
llinfos << "curl error detected: " << curl_easy_strerror(code) << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
void check_curl_multi_code(CURLMcode code)
|
||||
{
|
||||
if (code != CURLM_OK)
|
||||
{
|
||||
// linux appears to throw a curl error once per session for a bad initialization
|
||||
// at a pretty random time (when enabling cookies).
|
||||
llinfos << "curl multi error detected: " << curl_multi_strerror(code) << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLCurl::setCAPath(const std::string& path)
|
||||
{
|
||||
@@ -241,7 +261,12 @@ public:
|
||||
|
||||
void resetState();
|
||||
|
||||
static CURL* allocEasyHandle();
|
||||
static void releaseEasyHandle(CURL* handle);
|
||||
|
||||
private:
|
||||
friend class LLCurl;
|
||||
|
||||
CURL* mCurlEasyHandle;
|
||||
struct curl_slist* mHeaders;
|
||||
|
||||
@@ -256,8 +281,62 @@ private:
|
||||
std::vector<char*> mStrings;
|
||||
|
||||
ResponderPtr mResponder;
|
||||
|
||||
static std::set<CURL*> sFreeHandles;
|
||||
static std::set<CURL*> sActiveHandles;
|
||||
static LLMutex* sHandleMutex;
|
||||
};
|
||||
|
||||
std::set<CURL*> LLCurl::Easy::sFreeHandles;
|
||||
std::set<CURL*> LLCurl::Easy::sActiveHandles;
|
||||
LLMutex* LLCurl::Easy::sHandleMutex = NULL;
|
||||
|
||||
|
||||
//static
|
||||
CURL* LLCurl::Easy::allocEasyHandle()
|
||||
{
|
||||
CURL* ret = NULL;
|
||||
LLMutexLock lock(sHandleMutex);
|
||||
if (sFreeHandles.empty())
|
||||
{
|
||||
ret = curl_easy_init();
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = *(sFreeHandles.begin());
|
||||
sFreeHandles.erase(ret);
|
||||
curl_easy_reset(ret);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
{
|
||||
sActiveHandles.insert(ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLCurl::Easy::releaseEasyHandle(CURL* handle)
|
||||
{
|
||||
if (!handle)
|
||||
{
|
||||
llerrs << "handle cannot be NULL!" << llendl;
|
||||
}
|
||||
|
||||
LLMutexLock lock(sHandleMutex);
|
||||
|
||||
if (sActiveHandles.find(handle) != sActiveHandles.end())
|
||||
{
|
||||
sActiveHandles.erase(handle);
|
||||
sFreeHandles.insert(handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
llerrs << "Invalid handle." << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
LLCurl::Easy::Easy()
|
||||
: mHeaders(NULL),
|
||||
mCurlEasyHandle(NULL)
|
||||
@@ -268,18 +347,20 @@ LLCurl::Easy::Easy()
|
||||
LLCurl::Easy* LLCurl::Easy::getEasy()
|
||||
{
|
||||
Easy* easy = new Easy();
|
||||
easy->mCurlEasyHandle = curl_easy_init();
|
||||
easy->mCurlEasyHandle = allocEasyHandle();
|
||||
|
||||
if (!easy->mCurlEasyHandle)
|
||||
{
|
||||
// this can happen if we have too many open files (fails in c-ares/ares_init.c)
|
||||
llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
|
||||
llwarns << "allocEasyHandle() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
|
||||
delete easy;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// set no DMS caching as default for all easy handles. This prevents them adopting a
|
||||
// set no DNS caching as default for all easy handles. This prevents them adopting a
|
||||
// multi handles cache if they are added to one.
|
||||
curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
|
||||
CURLcode result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
|
||||
check_curl_code(result);
|
||||
|
||||
if (LLSocks::getInstance()->isHttpProxyEnabled())
|
||||
{
|
||||
@@ -305,7 +386,7 @@ LLCurl::Easy* LLCurl::Easy::getEasy()
|
||||
|
||||
LLCurl::Easy::~Easy()
|
||||
{
|
||||
curl_easy_cleanup(mCurlEasyHandle);
|
||||
releaseEasyHandle(mCurlEasyHandle);
|
||||
--gCurlEasyCount;
|
||||
curl_slist_free_all(mHeaders);
|
||||
for_each(mStrings.begin(), mStrings.end(), DeletePointerArray());
|
||||
@@ -364,9 +445,9 @@ void LLCurl::Easy::setHeaders()
|
||||
|
||||
void LLCurl::Easy::getTransferInfo(LLCurl::TransferInfo* info)
|
||||
{
|
||||
curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SIZE_DOWNLOAD, &info->mSizeDownload);
|
||||
curl_easy_getinfo(mCurlEasyHandle, CURLINFO_TOTAL_TIME, &info->mTotalTime);
|
||||
curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload);
|
||||
check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SIZE_DOWNLOAD, &info->mSizeDownload));
|
||||
check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_TOTAL_TIME, &info->mTotalTime));
|
||||
check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload));
|
||||
}
|
||||
|
||||
U32 LLCurl::Easy::report(CURLcode code)
|
||||
@@ -376,13 +457,14 @@ U32 LLCurl::Easy::report(CURLcode code)
|
||||
|
||||
if (code == CURLE_OK)
|
||||
{
|
||||
curl_easy_getinfo(mCurlEasyHandle, CURLINFO_RESPONSE_CODE, &responseCode);
|
||||
check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_RESPONSE_CODE, &responseCode));
|
||||
//*TODO: get reason from first line of mHeaderOutput
|
||||
}
|
||||
else
|
||||
{
|
||||
responseCode = 499;
|
||||
responseReason = strerror(code) + " : " + mErrorBuffer;
|
||||
setopt(CURLOPT_FRESH_CONNECT, TRUE);
|
||||
}
|
||||
|
||||
if (mResponder)
|
||||
@@ -398,17 +480,20 @@ U32 LLCurl::Easy::report(CURLcode code)
|
||||
// Note: these all assume the caller tracks the value (i.e. keeps it persistant)
|
||||
void LLCurl::Easy::setopt(CURLoption option, S32 value)
|
||||
{
|
||||
curl_easy_setopt(mCurlEasyHandle, option, value);
|
||||
CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
|
||||
check_curl_code(result);
|
||||
}
|
||||
|
||||
void LLCurl::Easy::setopt(CURLoption option, void* value)
|
||||
{
|
||||
curl_easy_setopt(mCurlEasyHandle, option, value);
|
||||
CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
|
||||
check_curl_code(result);
|
||||
}
|
||||
|
||||
void LLCurl::Easy::setopt(CURLoption option, char* value)
|
||||
{
|
||||
curl_easy_setopt(mCurlEasyHandle, option, value);
|
||||
CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
|
||||
check_curl_code(result);
|
||||
}
|
||||
|
||||
// Note: this copies the string so that the caller does not have to keep it around
|
||||
@@ -417,7 +502,8 @@ void LLCurl::Easy::setoptString(CURLoption option, const std::string& value)
|
||||
char* tstring = new char[value.length()+1];
|
||||
strcpy(tstring, value.c_str());
|
||||
mStrings.push_back(tstring);
|
||||
curl_easy_setopt(mCurlEasyHandle, option, tstring);
|
||||
CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, tstring);
|
||||
check_curl_code(result);
|
||||
}
|
||||
|
||||
void LLCurl::Easy::slist_append(const char* str)
|
||||
@@ -510,6 +596,9 @@ void LLCurl::Easy::prepRequest(const std::string& url,
|
||||
setCA();
|
||||
|
||||
setopt(CURLOPT_SSL_VERIFYPEER, true);
|
||||
|
||||
//don't verify host name so urls with scrubbed host names will work (improves DNS performance)
|
||||
setopt(CURLOPT_SSL_VERIFYHOST, 0);
|
||||
setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT);
|
||||
|
||||
setoptString(CURLOPT_URL, url);
|
||||
@@ -586,7 +675,7 @@ LLCurl::Multi::~Multi()
|
||||
iter != mEasyActiveList.end(); ++iter)
|
||||
{
|
||||
Easy* easy = *iter;
|
||||
curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle());
|
||||
check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
|
||||
delete easy;
|
||||
}
|
||||
mEasyActiveList.clear();
|
||||
@@ -596,7 +685,7 @@ LLCurl::Multi::~Multi()
|
||||
for_each(mEasyFreeList.begin(), mEasyFreeList.end(), DeletePointer());
|
||||
mEasyFreeList.clear();
|
||||
|
||||
curl_multi_cleanup(mCurlMultiHandle);
|
||||
check_curl_multi_code(curl_multi_cleanup(mCurlMultiHandle));
|
||||
--gCurlMultiCount;
|
||||
}
|
||||
|
||||
@@ -617,8 +706,10 @@ S32 LLCurl::Multi::perform()
|
||||
CURLMcode code = curl_multi_perform(mCurlMultiHandle, &q);
|
||||
if (CURLM_CALL_MULTI_PERFORM != code || q == 0)
|
||||
{
|
||||
check_curl_multi_code(code);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
mQueued = q;
|
||||
return q;
|
||||
@@ -685,11 +776,12 @@ LLCurl::Easy* LLCurl::Multi::allocEasy()
|
||||
bool LLCurl::Multi::addEasy(Easy* easy)
|
||||
{
|
||||
CURLMcode mcode = curl_multi_add_handle(mCurlMultiHandle, easy->getCurlHandle());
|
||||
if (mcode != CURLM_OK)
|
||||
{
|
||||
llwarns << "Curl Error: " << curl_multi_strerror(mcode) << llendl;
|
||||
return false;
|
||||
}
|
||||
check_curl_multi_code(mcode);
|
||||
//if (mcode != CURLM_OK)
|
||||
//{
|
||||
// llwarns << "Curl Error: " << curl_multi_strerror(mcode) << llendl;
|
||||
// return false;
|
||||
//}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -710,22 +802,14 @@ void LLCurl::Multi::easyFree(Easy* easy)
|
||||
|
||||
void LLCurl::Multi::removeEasy(Easy* easy)
|
||||
{
|
||||
curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle());
|
||||
check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
|
||||
easyFree(easy);
|
||||
}
|
||||
|
||||
//static
|
||||
std::string LLCurl::strerror(CURLcode errorcode)
|
||||
{
|
||||
#if LL_DARWIN
|
||||
// curl_easy_strerror was added in libcurl 7.12.0. Unfortunately, the version in the Mac OS X 10.3.9 SDK is 7.10.2...
|
||||
// There's a problem with the custom curl headers in our build that keeps me from #ifdefing this on the libcurl version number
|
||||
// (the correct check would be #if LIBCURL_VERSION_NUM >= 0x070c00). We'll fix the header problem soon, but for now
|
||||
// just punt and print the numeric error code on the Mac.
|
||||
return llformat("%d", errorcode);
|
||||
#else // LL_DARWIN
|
||||
return std::string(curl_easy_strerror(errorcode));
|
||||
#endif // LL_DARWIN
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
@@ -737,6 +821,7 @@ LLCurlRequest::LLCurlRequest() :
|
||||
mActiveRequestCount(0)
|
||||
{
|
||||
mThreadID = LLThread::currentID();
|
||||
mProcessing = FALSE;
|
||||
}
|
||||
|
||||
LLCurlRequest::~LLCurlRequest()
|
||||
@@ -771,6 +856,11 @@ LLCurl::Easy* LLCurlRequest::allocEasy()
|
||||
bool LLCurlRequest::addEasy(LLCurl::Easy* easy)
|
||||
{
|
||||
llassert_always(mActiveMulti);
|
||||
|
||||
if (mProcessing)
|
||||
{
|
||||
llerrs << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << llendl;
|
||||
}
|
||||
bool res = mActiveMulti->addEasy(easy);
|
||||
return res;
|
||||
}
|
||||
@@ -828,12 +918,41 @@ bool LLCurlRequest::post(const std::string& url,
|
||||
bool res = addEasy(easy);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool LLCurlRequest::post(const std::string& url,
|
||||
const headers_t& headers,
|
||||
const std::string& data,
|
||||
LLCurl::ResponderPtr responder)
|
||||
{
|
||||
LLCurl::Easy* easy = allocEasy();
|
||||
if (!easy)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
easy->prepRequest(url, headers, responder);
|
||||
|
||||
easy->getInput().write(data.data(), data.size());
|
||||
S32 bytes = easy->getInput().str().length();
|
||||
|
||||
easy->setopt(CURLOPT_POST, 1);
|
||||
easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
|
||||
easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
|
||||
|
||||
easy->slist_append("Content-Type: application/octet-stream");
|
||||
easy->setHeaders();
|
||||
|
||||
lldebugs << "POSTING: " << bytes << " bytes." << llendl;
|
||||
bool res = addEasy(easy);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Note: call once per frame
|
||||
S32 LLCurlRequest::process()
|
||||
{
|
||||
llassert_always(mThreadID == LLThread::currentID());
|
||||
S32 res = 0;
|
||||
|
||||
mProcessing = TRUE;
|
||||
for (curlmulti_set_t::iterator iter = mMultiSet.begin();
|
||||
iter != mMultiSet.end(); )
|
||||
{
|
||||
@@ -847,6 +966,7 @@ S32 LLCurlRequest::process()
|
||||
delete multi;
|
||||
}
|
||||
}
|
||||
mProcessing = FALSE;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1076,8 +1196,12 @@ void LLCurl::initClass()
|
||||
// Do not change this "unless you are familiar with and mean to control
|
||||
// internal operations of libcurl"
|
||||
// - http://curl.haxx.se/libcurl/c/curl_global_init.html
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
|
||||
|
||||
check_curl_code(code);
|
||||
|
||||
Easy::sHandleMutex = new LLMutex;
|
||||
|
||||
#if SAFE_SSL
|
||||
S32 mutex_count = CRYPTO_num_locks();
|
||||
for (S32 i=0; i<mutex_count; i++)
|
||||
@@ -1095,7 +1219,19 @@ void LLCurl::cleanupClass()
|
||||
CRYPTO_set_locking_callback(NULL);
|
||||
for_each(sSSLMutex.begin(), sSSLMutex.end(), DeletePointer());
|
||||
#endif
|
||||
curl_global_cleanup();
|
||||
|
||||
delete Easy::sHandleMutex;
|
||||
Easy::sHandleMutex = NULL;
|
||||
|
||||
for (std::set<CURL*>::iterator iter = Easy::sFreeHandles.begin(); iter != Easy::sFreeHandles.end(); ++iter)
|
||||
{
|
||||
CURL* curl = *iter;
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
Easy::sFreeHandles.clear();
|
||||
|
||||
llassert(Easy::sActiveHandles.empty());
|
||||
}
|
||||
|
||||
const unsigned int LLCurl::MAX_REDIRECTS = 5;
|
||||
|
||||
@@ -207,6 +207,8 @@ public:
|
||||
void get(const std::string& url, LLCurl::ResponderPtr responder);
|
||||
bool getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, LLCurl::ResponderPtr responder);
|
||||
bool post(const std::string& url, const headers_t& headers, const LLSD& data, LLCurl::ResponderPtr responder);
|
||||
bool post(const std::string& url, const headers_t& headers, const std::string& data, LLCurl::ResponderPtr responder);
|
||||
|
||||
S32 process();
|
||||
S32 getQueued();
|
||||
|
||||
@@ -220,6 +222,7 @@ private:
|
||||
curlmulti_set_t mMultiSet;
|
||||
LLCurl::Multi* mActiveMulti;
|
||||
S32 mActiveRequestCount;
|
||||
BOOL mProcessing;
|
||||
U32 mThreadID; // debug
|
||||
};
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user