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:
Siana Gearz
2011-06-05 19:56:46 +02:00
587 changed files with 27725 additions and 13002 deletions

View File

@@ -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

View File

@@ -673,9 +673,6 @@
<key>FetchInventoryDescendents</key>
<boolean>false</boolean>
<key>WebFetchInventoryDescendents</key>
<boolean>true</boolean>
<key>FetchInventory</key>
<boolean>true</boolean>

View File

@@ -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)

View File

@@ -0,0 +1,4 @@
# -*- cmake -*-
set(AISTATEMACHINE_INCLUDE_DIRS statemachine)
set(AISTATEMACHINE_LIBRARIES statemachine)

View 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)

View File

@@ -0,0 +1 @@
set(CWDEBUG_LIBRARIES cwdebug)

View File

@@ -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
)

View File

@@ -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)

View File

@@ -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")

View File

@@ -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}

View File

@@ -42,6 +42,7 @@ if (WINDOWS)
wldap32
gdi32
user32
dbghelp
)
else (WINDOWS)
set(WINDOWS_LIBRARIES "")

View File

@@ -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})

View 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
View 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
View 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
View 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

View File

@@ -0,0 +1 @@
// Empty so far...

9
indra/cwdebug/sys.h Normal file
View 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

View File

@@ -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();
}
}

View File

@@ -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;

View File

@@ -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++;

View File

@@ -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);

View File

@@ -47,7 +47,6 @@
#include "llquaternion.h"
#include "v3dmath.h"
#include "v3math.h"
#include "llapr.h"
#include "llbvhconsts.h"
class LLKeyframeDataCache;

View File

@@ -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)

View File

@@ -36,12 +36,12 @@
//-----------------------------------------------------------------------------
// Header Files
//-----------------------------------------------------------------------------
#include <string>
#include "llmap.h"
#include "lljointstate.h"
#include "lljoint.h"
#include "llmap.h"
#include <map>
#include <string>
//-----------------------------------------------------------------------------

View File

@@ -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(

View File

@@ -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) { }

View File

@@ -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;

View File

@@ -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

View File

@@ -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)

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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.

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -34,7 +34,7 @@
#ifndef LL_LLERRORLEGACY_H
#define LL_LLERRORLEGACY_H
#include "llpreprocessor.h"
/*
LEGACY -- DO NOT USE THIS STUFF ANYMORE

View File

@@ -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"),

View 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;
}
}
}

View 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

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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"

View File

@@ -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()
{
}

View 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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -33,7 +33,7 @@
#include "lllivefile.h"
#include "llframetimer.h"
#include "lltimer.h"
#include "lleventtimer.h"
const F32 DEFAULT_CONFIG_FILE_REFRESH = 5.0f;

View File

@@ -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;

View File

@@ -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:

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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.

View File

@@ -38,8 +38,6 @@
#include <vector>
#include <boost/shared_ptr.hpp>
#include "llpreprocessor.h"
class LLRunnable;
/**

View 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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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)
{

View File

@@ -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; }

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}
}
}

View File

@@ -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 &timestr);
LL_COMMON_API void timeStructToFormattedString(struct tm * time, std::string format, std::string &timestr);
// 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

View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -32,6 +32,7 @@
*/
// Precompiled header: almost always required for newview cpp files
#include "../llcommon/linden_common.h"
#include <list>
#include <map>
#include <algorithm>

View File

@@ -30,8 +30,8 @@
* $/LicenseInfo$
*/
#include <iostream>
#include "linden_common.h"
#include <iostream>
#include "llsaleinfo.h"

View File

@@ -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 &center, 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 &center, 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 &center, 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();
}
}

View File

@@ -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 &center, const F32 radius) const;

View File

@@ -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

View File

@@ -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 &center,
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

View File

@@ -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;
}
};

View File

@@ -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"

View File

@@ -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;

View File

@@ -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 &params, 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();
}

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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)

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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 )

View File

@@ -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;

View File

@@ -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()
{

View File

@@ -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;

View File

@@ -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