Merged latest login-api with latest viewer-2.0.0-3 up through plugin-api-05 merge (r131929).

Some minor post-merge cleanups still required.
master
brad kittenbrink 2009-08-27 16:25:02 -04:00
commit d020dae7b9
324 changed files with 16299 additions and 8995 deletions

36
.hgignore Normal file
View File

@ -0,0 +1,36 @@
syntax: glob
*.pyc
*~
.*.swp
LICENSES
indra/.distcc
indra/build-darwin-*
indra/build-vc[0-9]*
indra/lib/mono/1.0/*.dll
indra/lib/mono/indra/*.dll
indra/lib/mono/indra/*.exe
indra/lib/mono/indra/*.pdb
indra/lib/python/eventlet/
indra/llwindow/glh/glh_linear.h
indra/newview/app_settings/mozilla
indra/newview/app_settings/mozilla-runtime-*
indra/newview/app_settings/mozilla_debug
indra/newview/app_settings/static_*.db2
indra/newview/character
indra/newview/fmod.dll
indra/newview/mozilla-theme
indra/newview/mozilla-universal-darwin.tgz
indra/newview/res-sdl
indra/newview/skins
indra/newview/vivox-runtime
indra/server-linux-*
indra/test_apps/llmediatest/dependencies/i686-win32
indra/test_apps/terrain_mule/*.dll
indra/viewer-linux-*
indra/web/doc/asset-upload/plugins/lsl_compiler/lslc
indra/web/doc/asset-upload/plugins/verify-notecard
indra/web/doc/asset-upload/plugins/verify-texture
installed.xml
libraries
tarfile_tmp

View File

@ -66,6 +66,7 @@ if (VIEWER)
add_subdirectory(${LIBS_OPEN_PREFIX}llplugin)
add_subdirectory(${LIBS_OPEN_PREFIX}llui)
add_subdirectory(${LIBS_OPEN_PREFIX}llxuixml)
add_subdirectory(${LIBS_OPEN_PREFIX}viewer_components)
# viewer media plugins
add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins)

View File

@ -13,26 +13,38 @@ if (STANDALONE)
else (STANDALONE)
use_prebuilt_binary(apr_suite)
if (WINDOWS)
if (LLCOMMON_LINK_SHARED)
set(APR_selector "lib")
else (LLCOMMON_LINK_SHARED)
set(APR_selector "")
endif (LLCOMMON_LINK_SHARED)
set(APR_LIBRARIES
debug ${ARCH_PREBUILT_DIRS_DEBUG}/apr-1.lib
optimized ${ARCH_PREBUILT_DIRS_RELEASE}/apr-1.lib
debug ${ARCH_PREBUILT_DIRS_DEBUG}/${APR_selector}apr-1.lib
optimized ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}apr-1.lib
)
set(APRICONV_LIBRARIES
debug ${ARCH_PREBUILT_DIRS_DEBUG}/apriconv-1.lib
optimized ${ARCH_PREBUILT_DIRS_RELEASE}/apriconv-1.lib
debug ${ARCH_PREBUILT_DIRS_DEBUG}/${APR_selector}apriconv-1.lib
optimized ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}apriconv-1.lib
)
set(APRUTIL_LIBRARIES
debug ${ARCH_PREBUILT_DIRS_DEBUG}/aprutil-1.lib ${APRICONV_LIBRARIES}
optimized ${ARCH_PREBUILT_DIRS_RELEASE}/aprutil-1.lib ${APRICONV_LIBRARIES}
debug ${ARCH_PREBUILT_DIRS_DEBUG}/${APR_selector}aprutil-1.lib ${APRICONV_LIBRARIES}
optimized ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}aprutil-1.lib ${APRICONV_LIBRARIES}
)
elseif (DARWIN)
if (LLCOMMON_LINK_SHARED)
set(APR_selector "0.3.7.dylib")
set(APRUTIL_selector "0.3.8.dylib")
else (LLCOMMON_LINK_SHARED)
set(APR_selector "a")
set(APRUTIL_selector "a")
endif (LLCOMMON_LINK_SHARED)
set(APR_LIBRARIES
debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.a
optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.a
debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.${APR_selector}
optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.${APR_selector}
)
set(APRUTIL_LIBRARIES
debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.a
optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.a
debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.${APRUTIL_selector}
optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.${APRUTIL_selector}
)
set(APRICONV_LIBRARIES iconv)
else (WINDOWS)

View File

@ -0,0 +1,34 @@
# -*- cmake -*-
include(Python)
include(FindSVN)
macro (use_svn_external _binary _path _url _rev)
if (NOT STANDALONE)
if(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed)
if(SVN_FOUND)
if(DEBUG_EXTERNALS)
message("cd ${_path} && ${SVN_EXECUTABLE} checkout -r ${_rev} ${_url} ${_binary}")
endif(DEBUG_EXTERNALS)
execute_process(COMMAND ${SVN_EXECUTABLE}
checkout
-r ${_rev}
${_url}
${_binary}
WORKING_DIRECTORY ${_path}
RESULT_VARIABLE ${_binary}_installed
)
else(SVN_FOUND)
message(FATAL_ERROR "Failed to find SVN_EXECUTABLE")
endif(SVN_FOUND)
file(WRITE ${CMAKE_BINARY_DIR}/temp/${_binary}_installed "${${_binary}_installed}")
else(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed)
set(${_binary}_installed 0)
endif(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed)
if(NOT ${_binary}_installed EQUAL 0)
message(FATAL_ERROR
"Failed to download or unpack prebuilt '${_binary}'."
" Process returned ${${_binary}_installed}.")
endif (NOT ${_binary}_installed EQUAL 0)
endif (NOT STANDALONE)
endmacro (use_svn_external _binary _path _url _rev)

View File

@ -42,7 +42,7 @@ FIND_PROGRAM (GACUTIL_EXECUTABLE gacutil
/usr/local/bin
)
FIND_PROGRAM (ILASM_EXECUTABLE
ilasm
NAMES ilasm.bat ilasm
NO_DEFAULT_PATH
PATHS "$ENV{PROGRAMFILES}/Mono-1.9.1/bin" "$ENV{PROGRAMFILES}/Mono-1.2.6/bin" /bin /usr/bin /usr/local/bin
)

34
indra/cmake/FindSVN.cmake Normal file
View File

@ -0,0 +1,34 @@
# -*- cmake -*-
#
# Find the svn executable for exporting old svn:externals.
#
# Input variables:
# SVN_FIND_REQUIRED - set this if configuration should fail without scp
#
# Output variables:
#
# SVN_FOUND - set if svn was found
# SVN_EXECUTABLE - path to svn executable
# SVN_BATCH_FLAG - how to put svn into batch mode
SET(SVN_EXECUTABLE)
FIND_PROGRAM(SVN_EXECUTABLE NAMES svn svn.exe)
IF (SVN_EXECUTABLE)
SET(SVN_FOUND ON)
ELSE (SVN_EXECUTABLE)
SET(SVN_FOUND OFF)
ENDIF (SVN_EXECUTABLE)
IF (SVN_FOUND)
GET_FILENAME_COMPONENT(_svn_name ${SVN_EXECUTABLE} NAME_WE)
SET(SVN_BATCH_FLAG --non-interactive)
ELSE (SVN_FOUND)
IF (SVN_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find svn executable")
ENDIF (SVN_FIND_REQUIRED)
ENDIF (SVN_FOUND)
MARK_AS_ADVANCED(SVN_EXECUTABLE SVN_FOUND SVN_BATCH_FLAG)

View File

@ -114,22 +114,29 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
GET_TARGET_PROPERTY(TEST_EXE PROJECT_${project}_TEST_${name} LOCATION)
SET(TEST_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/PROJECT_${project}_TEST_${name}_ok.txt)
SET(TEST_CMD ${TEST_EXE} --touch=${TEST_OUTPUT} --sourcedir=${CMAKE_CURRENT_SOURCE_DIR})
# daveh - what configuration does this use? Debug? it's cmake-time, not build time. + poppy 2009-04-19
# daveh - what configuration does this use? Debug? it's cmake-time, not build time. + poppy 2009-04-19
IF(LL_TEST_VERBOSE)
MESSAGE(STATUS "LL_ADD_PROJECT_UNIT_TESTS ${name} test_cmd = ${TEST_CMD}")
ENDIF(LL_TEST_VERBOSE)
SET(TEST_SCRIPT_CMD
${CMAKE_COMMAND}
-DLD_LIBRARY_PATH=${ARCH_PREBUILT_DIRS}:/usr/lib
-DTEST_CMD:STRING="${TEST_CMD}"
-P ${CMAKE_SOURCE_DIR}/cmake/RunBuildTest.cmake
)
IF(WINDOWS)
set(LD_LIBRARY_PATH ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR})
ELSE(WINDOWS)
set(LD_LIBRARY_PATH ${ARCH_PREBUILT_DIRS}:${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}:/usr/lib)
ENDIF(WINDOWS)
IF(LL_TEST_VERBOSE)
MESSAGE(STATUS "LL_ADD_PROJECT_UNIT_TESTS ${name} test_script = ${TEST_SCRIPT_CMD}")
ENDIF(LL_TEST_VERBOSE)
# Add test
ADD_CUSTOM_COMMAND(
OUTPUT ${TEST_OUTPUT}
COMMAND ${CMAKE_COMMAND}
ARGS
-DLD_LIBRARY_PATH=${LD_LIBRARY_PATH}
"-DTEST_CMD:STRING=\"${TEST_CMD}\""
-P ${CMAKE_SOURCE_DIR}/cmake/RunBuildTest.cmake
COMMAND ${TEST_SCRIPT_CMD}
DEPENDS PROJECT_${project}_TEST_${name}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}

View File

@ -17,3 +17,7 @@ set(LLCOMMON_LIBRARIES llcommon)
add_definitions(${TCMALLOC_FLAG})
set(LLCOMMON_LINK_SHARED ON CACHE BOOL "Build the llcommon target as a shared library.")
if(LLCOMMON_LINK_SHARED)
add_definitions(-DLL_COMMON_LINK_SHARED=1)
endif(LLCOMMON_LINK_SHARED)

View File

@ -0,0 +1,7 @@
# -*- cmake -*-
set(LLLOGIN_INCLUDE_DIRS
${LIBS_OPEN_DIR}/viewer_components/login
)
set(LLLOGIN_LIBRARIES lllogin)

View File

@ -5,6 +5,7 @@ if (NOT STANDALONE)
set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib)
set(ARCH_PREBUILT_DIRS_RELEASE ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/release)
set(ARCH_PREBUILT_DIRS_DEBUG ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/debug)
set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs CACHE FILEPATH "Location of staged DLLs")
elseif (LINUX)
if (VIEWER)
set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib_release_client)
@ -13,10 +14,12 @@ if (NOT STANDALONE)
endif (VIEWER)
set(ARCH_PREBUILT_DIRS_RELEASE ${ARCH_PREBUILT_DIRS})
set(ARCH_PREBUILT_DIRS_DEBUG ${ARCH_PREBUILT_DIRS})
set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs CACHE FILEPATH "Location of staged .sos")
elseif (DARWIN)
set(ARCH_PREBUILT_DIRS_RELEASE ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib_release)
set(ARCH_PREBUILT_DIRS ${ARCH_PREBUILT_DIRS_RELEASE})
set(ARCH_PREBUILT_DIRS_DEBUG ${ARCH_PREBUILT_DIRS_RELEASE})
set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs CACHE FILEPATH "Location of staged DLLs")
endif (WINDOWS)
endif (NOT STANDALONE)

21
indra/cmake/Pth.cmake Normal file
View File

@ -0,0 +1,21 @@
# -*- cmake -*-
include(Prebuilt)
set(PTH_FIND_QUIETLY ON)
set(PTH_FIND_REQUIRED ON)
if (STANDALONE)
# ?? How would I construct FindPTH.cmake? This file was cloned from
# CURL.cmake, which uses include(FindCURL), but there's no FindCURL.cmake?
# include(FindPTH)
else (STANDALONE)
# This library is only needed to support Boost.Coroutine, and only on Mac.
if (DARWIN)
use_prebuilt_binary(pth)
set(PTH_LIBRARIES pth)
set(PTH_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
else (DARWIN)
set(PTH_LIBRARIES)
set(PTH_INCLUDE_DIRS)
endif (DARWIN)
endif (STANDALONE)

View File

@ -439,7 +439,6 @@ class DarwinSetup(UnixSetup):
)
if self.universal == 'ON':
args['universal'] = '-DCMAKE_OSX_ARCHITECTURES:STRING=\'i386;ppc\''
pass
#if simple:
# return 'cmake %(opts)s %(dir)r' % args
return ('cmake -G %(generator)r '

View File

@ -26,8 +26,14 @@ THE SOFTWARE.
$/LicenseInfo$
"""
import md5, random, socket, string, time, re
import random, socket, string, time, re
import uuid
try:
# Python 2.6
from hashlib import md5
except ImportError:
# Python 2.5 and earlier
from md5 import new as md5
def _int2binstr(i,l):
s=''
@ -196,7 +202,7 @@ class UUID(object):
from c++ implementation for portability reasons.
Returns self.
"""
m = md5.new()
m = md5()
m.update(uuid.uuid1().bytes)
self._bits = m.digest()
return self

View File

@ -5,12 +5,19 @@ project(llcommon)
include(00-Common)
include(LLAddBuildTest)
include(LLCommon)
include(Linking)
include(Boost)
include (Pth)
if (WINDOWS)
include(CopyWinLibs)
endif (WINDOWS)
include_directories(
${EXPAT_INCLUDE_DIRS}
${LLCOMMON_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS}
${PTH_INCLUDE_DIRS}
)
# add_executable(lltreeiterators lltreeiterators.cpp)
@ -27,6 +34,7 @@ set(llcommon_SOURCE_FILES
llbase32.cpp
llbase64.cpp
llcommon.cpp
llcoros.cpp
llcrc.cpp
llcriticaldamp.cpp
llcursortypes.cpp
@ -35,6 +43,9 @@ set(llcommon_SOURCE_FILES
llerror.cpp
llerrorthread.cpp
llevent.cpp
lleventcoro.cpp
lleventdispatcher.cpp
lleventfilter.cpp
llevents.cpp
llfasttimer.cpp
llfile.cpp
@ -64,6 +75,7 @@ set(llcommon_SOURCE_FILES
llsdserialize_xml.cpp
llsdutil.cpp
llsecondlifeurls.cpp
llsingleton.cpp
llstat.cpp
llstacktrace.cpp
llstreamtools.cpp
@ -106,6 +118,7 @@ set(llcommon_HEADER_FILES
llchat.h
llclickaction.h
llcommon.h
llcoros.h
llcrc.h
llcriticaldamp.h
llcursortypes.h
@ -127,6 +140,9 @@ set(llcommon_HEADER_FILES
llerrorlegacy.h
llerrorthread.h
llevent.h
lleventcoro.h
lleventdispatcher.h
lleventfilter.h
llevents.h
lleventemitter.h
llextendedstatus.h
@ -141,6 +157,7 @@ set(llcommon_HEADER_FILES
llhttpstatuscodes.h
llindexedqueue.h
llinstancetracker.h
llinstancetracker.h
llkeythrottle.h
lllazy.h
lllinkedqueue.h
@ -221,17 +238,57 @@ set_source_files_properties(${llcommon_HEADER_FILES}
list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES})
add_library (llcommon ${llcommon_SOURCE_FILES})
if(LLCOMMON_LINK_SHARED)
add_library (llcommon SHARED ${llcommon_SOURCE_FILES})
add_definitions(-DLL_COMMON_BUILD=1)
if(SHARED_LIB_STAGING_DIR)
# *FIX:Mani ---
# llcommon.dll get written to the DLL staging directory.
# Also this directory is shared with RunBuildTest.cmake, y'know, for the tests.
set_target_properties(llcommon PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${SHARED_LIB_STAGING_DIR})
if(NOT WINDOWS)
get_target_property(LLCOMMON_PATH llcommon LOCATION)
get_filename_component(LLCOMMON_FILE ${LLCOMMON_PATH} NAME)
add_custom_command(
TARGET llcommon POST_BUILD
COMMAND ${CMAKE_COMMAND}
ARGS
-E
copy_if_different
${LLCOMMON_PATH}
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/${LLCOMMON_FILE}
COMMENT "Copying llcommon to the staging folder."
)
endif(NOT WINDOWS)
endif(SHARED_LIB_STAGING_DIR)
if (DARWIN)
set_target_properties(llcommon PROPERTIES
BUILD_WITH_INSTALL_RPATH 1
INSTALL_NAME_DIR "@executable_path/../Resources"
)
endif(DARWIN)
else(LLCOMMON_LINK_SHARED)
add_library (llcommon ${llcommon_SOURCE_FILES})
endif(LLCOMMON_LINK_SHARED)
target_link_libraries(
llcommon
${APRUTIL_LIBRARIES}
${APR_LIBRARIES}
${EXPAT_LIBRARIES}
${ZLIB_LIBRARIES}
${WINDOWS_LIBRARIES}
${BOOST_PROGRAM_OPTIONS_LIBRARY}
${BOOST_REGEX_LIBRARY}
${PTH_LIBRARIES}
)
add_dependencies(llcommon stage_third_party_libs)
include(LLAddBuildTest)
SET(llcommon_TEST_SOURCE_FILES
# WARNING: Please don't write tests against LLCommon or LLMath until this issue is resolved: https://jira.lindenlab.com/jira/browse/DEV-29456

View File

@ -72,13 +72,7 @@
#ifdef LL_WINDOWS
// Reenable warnings we disabled above
#pragma warning (3 : 4702) // unreachable code, we like level 3, not 4
// level 4 warnings that we need to disable:
#pragma warning (disable : 4100) // unreferenced formal parameter
#pragma warning (disable : 4127) // conditional expression is constant (e.g. while(1) )
#pragma warning (disable : 4244) // possible loss of data on conversions
#pragma warning (disable : 4396) // the inline specifier cannot be used when a friend declaration refers to a specialization of a function template
#pragma warning (disable : 4512) // assignment operator could not be generated
#pragma warning (disable : 4706) // assignment within conditional (even if((x = y)) )
// moved msvc warnings to llpreprocessor.h *TODO - delete this comment after merge conflicts are unlikely -brad
#endif // LL_WINDOWS
// Linden only libs in alpha-order other than stdtypes.h

View File

@ -1,63 +1,63 @@
/**
* @file llallocator.h
* @brief Declaration of the LLAllocator class.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
* Copyright (c) 2009-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLALLOCATOR_H
#define LL_LLALLOCATOR_H
#include <string>
#include "llmemtype.h"
#include "llallocator_heap_profile.h"
class LLAllocator {
friend class LLMemoryView;
friend class LLMemType;
private:
static void pushMemType(S32 type);
static S32 popMemType();
public:
void setProfilingEnabled(bool should_enable);
static bool isProfiling();
LLAllocatorHeapProfile const & getProfile();
private:
std::string getRawProfile();
private:
LLAllocatorHeapProfile mProf;
};
#endif // LL_LLALLOCATOR_H
/**
* @file llallocator.h
* @brief Declaration of the LLAllocator class.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
* Copyright (c) 2009-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLALLOCATOR_H
#define LL_LLALLOCATOR_H
#include <string>
#include "llmemtype.h"
#include "llallocator_heap_profile.h"
class LL_COMMON_API LLAllocator {
friend class LLMemoryView;
friend class LLMemType;
private:
static void pushMemType(S32 type);
static S32 popMemType();
public:
void setProfilingEnabled(bool should_enable);
static bool isProfiling();
LLAllocatorHeapProfile const & getProfile();
private:
std::string getRawProfile();
private:
LLAllocatorHeapProfile mProf;
};
#endif // LL_LLALLOCATOR_H

View File

@ -61,7 +61,7 @@ public:
};
#endif
class LLApp
class LL_COMMON_API LLApp
{
friend class LLErrorThread;
public:

View File

@ -1,259 +1,259 @@
/**
* @file llapr.h
* @author Phoenix
* @date 2004-11-28
* @brief Helper functions for using the apache portable runtime library.
*
* $LicenseInfo:firstyear=2004&license=viewergpl$
*
* Copyright (c) 2004-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLAPR_H
#define LL_LLAPR_H
#if LL_LINUX || LL_SOLARIS
#include <sys/param.h> // Need PATH_MAX in APR headers...
#endif
#include <boost/noncopyable.hpp>
#include "apr_thread_proc.h"
#include "apr_thread_mutex.h"
#include "apr_getopt.h"
#include "apr_signal.h"
#include "apr_atomic.h"
#include "llstring.h"
extern apr_thread_mutex_t* gLogMutexp;
extern apr_thread_mutex_t* gCallStacksLogMutexp;
/**
* @brief initialize the common apr constructs -- apr itself, the
* global pool, and a mutex.
*/
void ll_init_apr();
/**
* @brief Cleanup those common apr constructs.
*/
void ll_cleanup_apr();
//
//LL apr_pool
//manage apr_pool_t, destroy allocated apr_pool in the destruction function.
//
class LLAPRPool
{
public:
LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ;
~LLAPRPool() ;
apr_pool_t* getAPRPool() ;
apr_status_t getStatus() {return mStatus ; }
protected:
void releaseAPRPool() ;
void createAPRPool() ;
protected:
apr_pool_t* mPool ; //pointing to an apr_pool
apr_pool_t* mParent ; //parent pool
apr_size_t mMaxSize ; //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work.
apr_status_t mStatus ; //status when creating the pool
BOOL mReleasePoolFlag ; //if set, mPool is destroyed when LLAPRPool is deleted. default value is true.
};
//
//volatile LL apr_pool
//which clears memory automatically.
//so it can not hold static data or data after memory is cleared
//
class LLVolatileAPRPool : public LLAPRPool
{
public:
LLVolatileAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE);
~LLVolatileAPRPool(){}
apr_pool_t* getVolatileAPRPool() ;
void clearVolatileAPRPool() ;
BOOL isFull() ;
BOOL isEmpty() {return !mNumActiveRef ;}
private:
S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool.
S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating.
} ;
/**
* @class LLScopedLock
* @brief Small class to help lock and unlock mutexes.
*
* This class is used to have a stack level lock once you already have
* an apr mutex handy. The constructor handles the lock, and the
* destructor handles the unlock. Instances of this class are
* <b>not</b> thread safe.
*/
class LLScopedLock : private boost::noncopyable
{
public:
/**
* @brief Constructor which accepts a mutex, and locks it.
*
* @param mutex An allocated APR mutex. If you pass in NULL,
* this wrapper will not lock.
*/
LLScopedLock(apr_thread_mutex_t* mutex);
/**
* @brief Destructor which unlocks the mutex if still locked.
*/
~LLScopedLock();
/**
* @brief Check lock.
*/
bool isLocked() const { return mLocked; }
/**
* @brief This method unlocks the mutex.
*/
void unlock();
protected:
bool mLocked;
apr_thread_mutex_t* mMutex;
};
template <typename Type> class LLAtomic32
{
public:
LLAtomic32<Type>() {};
LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); };
~LLAtomic32<Type>() {};
operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); }
void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }
void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }
Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++
Type operator --(int) { return apr_atomic_dec32(&mData); } // Type--
private:
apr_uint32_t mData;
};
typedef LLAtomic32<U32> LLAtomicU32;
typedef LLAtomic32<S32> LLAtomicS32;
// File IO convenience functions.
// Returns NULL if the file fails to openm sets *sizep to file size of not NULL
// abbreviated flags
#define LL_APR_R (APR_READ) // "r"
#define LL_APR_W (APR_CREATE|APR_TRUNCATE|APR_WRITE) // "w"
#define LL_APR_RB (APR_READ|APR_BINARY) // "rb"
#define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb"
#define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b"
#define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b"
//
//apr_file manager
//which: 1)only keeps one file open;
// 2)closes the open file in the destruction function
// 3)informs the apr_pool to clean the memory when the file is closed.
//Note: please close an open file at the earliest convenience.
// especially do not put some time-costly operations between open() and close().
// otherwise it might lock the APRFilePool.
//there are two different apr_pools the APRFile can use:
// 1, a temperary pool passed to an APRFile function, which is used within this function and only once.
// 2, a global pool.
//
class LLAPRFile
{
private:
apr_file_t* mFile ;
LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool.
public:
LLAPRFile() ;
~LLAPRFile() ;
apr_status_t open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep = NULL);
apr_status_t open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool = NULL, S32* sizep = NULL);
apr_status_t close() ;
// Returns actual offset, -1 if seek fails
S32 seek(apr_seek_where_t where, S32 offset);
apr_status_t eof() { return apr_file_eof(mFile);}
// Returns bytes read/written, 0 if read/write fails:
S32 read(void* buf, S32 nbytes);
S32 write(const void* buf, S32 nbytes);
apr_file_t* getFileHandle() {return mFile;}
private:
apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;
//
//*******************************************************************************************************************************
//static components
//
public:
static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist.
private:
static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags);
static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ;
static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset);
public:
// returns false if failure:
static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL);
static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL);
static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ);
static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL);
static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
// Returns bytes read/written, 0 if read/write fails:
static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);
static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);
//*******************************************************************************************************************************
};
/**
* @brief Function which approprately logs error or remains quiet on
* APR_SUCCESS.
* @return Returns <code>true</code> if status is an error condition.
*/
bool ll_apr_warn_status(apr_status_t status);
void ll_apr_assert_status(apr_status_t status);
extern "C" apr_pool_t* gAPRPoolp; // Global APR memory pool
#endif // LL_LLAPR_H
/**
* @file llapr.h
* @author Phoenix
* @date 2004-11-28
* @brief Helper functions for using the apache portable runtime library.
*
* $LicenseInfo:firstyear=2004&license=viewergpl$
*
* Copyright (c) 2004-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLAPR_H
#define LL_LLAPR_H
#if LL_LINUX || LL_SOLARIS
#include <sys/param.h> // Need PATH_MAX in APR headers...
#endif
#include <boost/noncopyable.hpp>
#include "apr_thread_proc.h"
#include "apr_thread_mutex.h"
#include "apr_getopt.h"
#include "apr_signal.h"
#include "apr_atomic.h"
#include "llstring.h"
extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
extern apr_thread_mutex_t* gCallStacksLogMutexp;
/**
* @brief initialize the common apr constructs -- apr itself, the
* global pool, and a mutex.
*/
void LL_COMMON_API ll_init_apr();
/**
* @brief Cleanup those common apr constructs.
*/
void LL_COMMON_API ll_cleanup_apr();
//
//LL apr_pool
//manage apr_pool_t, destroy allocated apr_pool in the destruction function.
//
class LL_COMMON_API LLAPRPool
{
public:
LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ;
~LLAPRPool() ;
apr_pool_t* getAPRPool() ;
apr_status_t getStatus() {return mStatus ; }
protected:
void releaseAPRPool() ;
void createAPRPool() ;
protected:
apr_pool_t* mPool ; //pointing to an apr_pool
apr_pool_t* mParent ; //parent pool
apr_size_t mMaxSize ; //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work.
apr_status_t mStatus ; //status when creating the pool
BOOL mReleasePoolFlag ; //if set, mPool is destroyed when LLAPRPool is deleted. default value is true.
};
//
//volatile LL apr_pool
//which clears memory automatically.
//so it can not hold static data or data after memory is cleared
//
class LL_COMMON_API LLVolatileAPRPool : public LLAPRPool
{
public:
LLVolatileAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE);
~LLVolatileAPRPool(){}
apr_pool_t* getVolatileAPRPool() ;
void clearVolatileAPRPool() ;
BOOL isFull() ;
BOOL isEmpty() {return !mNumActiveRef ;}
private:
S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool.
S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating.
} ;
/**
* @class LLScopedLock
* @brief Small class to help lock and unlock mutexes.
*
* This class is used to have a stack level lock once you already have
* an apr mutex handy. The constructor handles the lock, and the
* destructor handles the unlock. Instances of this class are
* <b>not</b> thread safe.
*/
class LL_COMMON_API LLScopedLock : private boost::noncopyable
{
public:
/**
* @brief Constructor which accepts a mutex, and locks it.
*
* @param mutex An allocated APR mutex. If you pass in NULL,
* this wrapper will not lock.
*/
LLScopedLock(apr_thread_mutex_t* mutex);
/**
* @brief Destructor which unlocks the mutex if still locked.
*/
~LLScopedLock();
/**
* @brief Check lock.
*/
bool isLocked() const { return mLocked; }
/**
* @brief This method unlocks the mutex.
*/
void unlock();
protected:
bool mLocked;
apr_thread_mutex_t* mMutex;
};
template <typename Type> class LLAtomic32
{
public:
LLAtomic32<Type>() {};
LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); };
~LLAtomic32<Type>() {};
operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); }
void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }
void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }
Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++
Type operator --(int) { return apr_atomic_dec32(&mData); } // Type--
private:
apr_uint32_t mData;
};
typedef LLAtomic32<U32> LLAtomicU32;
typedef LLAtomic32<S32> LLAtomicS32;
// File IO convenience functions.
// Returns NULL if the file fails to openm sets *sizep to file size of not NULL
// abbreviated flags
#define LL_APR_R (APR_READ) // "r"
#define LL_APR_W (APR_CREATE|APR_TRUNCATE|APR_WRITE) // "w"
#define LL_APR_RB (APR_READ|APR_BINARY) // "rb"
#define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb"
#define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b"
#define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b"
//
//apr_file manager
//which: 1)only keeps one file open;
// 2)closes the open file in the destruction function
// 3)informs the apr_pool to clean the memory when the file is closed.
//Note: please close an open file at the earliest convenience.
// especially do not put some time-costly operations between open() and close().
// otherwise it might lock the APRFilePool.
//there are two different apr_pools the APRFile can use:
// 1, a temperary pool passed to an APRFile function, which is used within this function and only once.
// 2, a global pool.
//
class LL_COMMON_API LLAPRFile
{
private:
apr_file_t* mFile ;
LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool.
public:
LLAPRFile() ;
~LLAPRFile() ;
apr_status_t open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep = NULL);
apr_status_t open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool = NULL, S32* sizep = NULL);
apr_status_t close() ;
// Returns actual offset, -1 if seek fails
S32 seek(apr_seek_where_t where, S32 offset);
apr_status_t eof() { return apr_file_eof(mFile);}
// Returns bytes read/written, 0 if read/write fails:
S32 read(void* buf, S32 nbytes);
S32 write(const void* buf, S32 nbytes);
apr_file_t* getFileHandle() {return mFile;}
private:
apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;
//
//*******************************************************************************************************************************
//static components
//
public:
static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist.
private:
static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags);
static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ;
static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset);
public:
// returns false if failure:
static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL);
static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL);
static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ);
static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL);
static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
// Returns bytes read/written, 0 if read/write fails:
static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);
static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);
//*******************************************************************************************************************************
};
/**
* @brief Function which approprately logs error or remains quiet on
* APR_SUCCESS.
* @return Returns <code>true</code> if status is an error condition.
*/
bool LL_COMMON_API ll_apr_warn_status(apr_status_t status);
void LL_COMMON_API ll_apr_assert_status(apr_status_t status);
extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool
#endif // LL_LLAPR_H

View File

@ -1,204 +1,204 @@
/**
* @file llassettype.h
* @brief Declaration of LLAssetType.
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLASSETTYPE_H
#define LL_LLASSETTYPE_H
#include <string>
#include "stdenums.h" // for EDragAndDropType
class LLAssetType
{
public:
enum EType
{
AT_TEXTURE = 0,
// Used for painting the faces of geometry.
// Stored in typical j2c stream format.
AT_SOUND = 1,
// Used to fill the aural spectrum.
AT_CALLINGCARD = 2,
// Links instant message access to the user on the card.
// : E.G. A card for yourself, for linden support, for
// : the guy you were talking to in the coliseum.
AT_LANDMARK = 3,
// Links to places in the world with location and a screen shot or image saved.
// : E.G. Home, linden headquarters, the coliseum, destinations where
// : we want to increase traffic.
AT_SCRIPT = 4,
// Valid scripts that can be attached to an object.
// : E.G. Open a door, jump into the air.
AT_CLOTHING = 5,
// A collection of textures and parameters that can be worn by an avatar.
AT_OBJECT = 6,
// Any combination of textures, sounds, and scripts that are
// associated with a fixed piece of geometry.
// : E.G. A hot tub, a house with working door.
AT_NOTECARD = 7,
// Just text.
AT_CATEGORY = 8,
// Holds a collection of inventory items.
// It's treated as an item in the inventory and therefore needs a type.
AT_ROOT_CATEGORY = 9,
// A user's root inventory category.
// We decided to expose it visually, so it seems logical to fold
// it into the asset types.
AT_LSL_TEXT = 10,
AT_LSL_BYTECODE = 11,
// The LSL is the scripting language.
// We've split it into a text and bytecode representation.
AT_TEXTURE_TGA = 12,
// Uncompressed TGA texture.
AT_BODYPART = 13,
// A collection of textures and parameters that can be worn by an avatar.
AT_TRASH = 14,
// Only to be used as a marker for a category preferred type.
// Using this, we can throw things in the trash before completely deleting.
AT_SNAPSHOT_CATEGORY = 15,
// A marker for a folder meant for snapshots.
// No actual assets will be snapshots, though if there were, you
// could interpret them as textures.
AT_LOST_AND_FOUND = 16,
// Used to stuff lost&found items into.
AT_SOUND_WAV = 17,
// Uncompressed sound.
AT_IMAGE_TGA = 18,
// Uncompressed image, non-square.
// Not appropriate for use as a texture.
AT_IMAGE_JPEG = 19,
// Compressed image, non-square.
// Not appropriate for use as a texture.
AT_ANIMATION = 20,
// Animation.
AT_GESTURE = 21,
// Gesture, sequence of animations, sounds, chat, wait steps.
AT_SIMSTATE = 22,
// Simstate file.
AT_FAVORITE = 23,
// favorite items
AT_LINK = 24,
// Inventory symbolic link
AT_LINK_FOLDER = 25,
// Inventory folder link
AT_FOLDER_ENSEMBLE_START = 26,
AT_FOLDER_ENSEMBLE_END = 45,
// This range is reserved for special clothing folder types.
AT_CURRENT_OUTFIT = 46,
// Current outfit
AT_OUTFIT = 47,
// Predefined outfit ("look")
AT_MY_OUTFITS = 48,
// Folder that holds your outfits.
AT_COUNT = 49,
// +*********************************************************+
// | TO ADD AN ELEMENT TO THIS ENUM: |
// +*********************************************************+
// | 1. INSERT BEFORE AT_COUNT |
// | 2. INCREMENT AT_COUNT BY 1 |
// | 3. ADD TO LLAssetDictionary in LLAssetType.cpp |
// | 3. ADD TO DEFAULT_ASSET_FOR_INV in LLInventoryType.cpp |
// +*********************************************************+
AT_NONE = -1
};
// 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& type_name);
static const char* lookup(EType asset_type);
// translation from a type to a human readable form.
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);
// 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 asset_type,
std::string& description);
static EType getType(const std::string& desc_name);
static const std::string& getDesc(EType asset_type);
static EDragAndDropType lookupDragAndDropType(EType asset_type);
static bool lookupCanLink(EType asset_type);
static bool lookupIsLinkType(EType asset_type);
static const char* lookupCategoryName(EType asset_type);
static bool lookupIsProtectedCategoryType(EType asset_type);
static bool lookupIsEnsembleCategoryType(EType asset_type);
/* TODO: Change return types from "const char *" to "const std::string &".
This is fairly straightforward, but requires changing some calls to use .c_str().
e.g.:
- fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
+ fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType).c_str());
*/
private:
// don't instantiate or derive one of these objects
LLAssetType( void ) {}
~LLAssetType( void ) {}
};
#endif // LL_LLASSETTYPE_H
/**
* @file llassettype.h
* @brief Declaration of LLAssetType.
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLASSETTYPE_H
#define LL_LLASSETTYPE_H
#include <string>
#include "stdenums.h" // for EDragAndDropType
class LL_COMMON_API LLAssetType
{
public:
enum EType
{
AT_TEXTURE = 0,
// Used for painting the faces of geometry.
// Stored in typical j2c stream format.
AT_SOUND = 1,
// Used to fill the aural spectrum.
AT_CALLINGCARD = 2,
// Links instant message access to the user on the card.
// : E.G. A card for yourself, for linden support, for
// : the guy you were talking to in the coliseum.
AT_LANDMARK = 3,
// Links to places in the world with location and a screen shot or image saved.
// : E.G. Home, linden headquarters, the coliseum, destinations where
// : we want to increase traffic.
AT_SCRIPT = 4,
// Valid scripts that can be attached to an object.
// : E.G. Open a door, jump into the air.
AT_CLOTHING = 5,
// A collection of textures and parameters that can be worn by an avatar.
AT_OBJECT = 6,
// Any combination of textures, sounds, and scripts that are
// associated with a fixed piece of geometry.
// : E.G. A hot tub, a house with working door.
AT_NOTECARD = 7,
// Just text.
AT_CATEGORY = 8,
// Holds a collection of inventory items.
// It's treated as an item in the inventory and therefore needs a type.
AT_ROOT_CATEGORY = 9,
// A user's root inventory category.
// We decided to expose it visually, so it seems logical to fold
// it into the asset types.
AT_LSL_TEXT = 10,
AT_LSL_BYTECODE = 11,
// The LSL is the scripting language.
// We've split it into a text and bytecode representation.
AT_TEXTURE_TGA = 12,
// Uncompressed TGA texture.
AT_BODYPART = 13,
// A collection of textures and parameters that can be worn by an avatar.
AT_TRASH = 14,
// Only to be used as a marker for a category preferred type.
// Using this, we can throw things in the trash before completely deleting.
AT_SNAPSHOT_CATEGORY = 15,
// A marker for a folder meant for snapshots.
// No actual assets will be snapshots, though if there were, you
// could interpret them as textures.
AT_LOST_AND_FOUND = 16,
// Used to stuff lost&found items into.
AT_SOUND_WAV = 17,
// Uncompressed sound.
AT_IMAGE_TGA = 18,
// Uncompressed image, non-square.
// Not appropriate for use as a texture.
AT_IMAGE_JPEG = 19,
// Compressed image, non-square.
// Not appropriate for use as a texture.
AT_ANIMATION = 20,
// Animation.
AT_GESTURE = 21,
// Gesture, sequence of animations, sounds, chat, wait steps.
AT_SIMSTATE = 22,
// Simstate file.
AT_FAVORITE = 23,
// favorite items
AT_LINK = 24,
// Inventory symbolic link
AT_LINK_FOLDER = 25,
// Inventory folder link
AT_FOLDER_ENSEMBLE_START = 26,
AT_FOLDER_ENSEMBLE_END = 45,
// This range is reserved for special clothing folder types.
AT_CURRENT_OUTFIT = 46,
// Current outfit
AT_OUTFIT = 47,
// Predefined outfit ("look")
AT_MY_OUTFITS = 48,
// Folder that holds your outfits.
AT_COUNT = 49,
// +*********************************************************+
// | TO ADD AN ELEMENT TO THIS ENUM: |
// +*********************************************************+
// | 1. INSERT BEFORE AT_COUNT |
// | 2. INCREMENT AT_COUNT BY 1 |
// | 3. ADD TO LLAssetDictionary in LLAssetType.cpp |
// | 3. ADD TO DEFAULT_ASSET_FOR_INV in LLInventoryType.cpp |
// +*********************************************************+
AT_NONE = -1
};
// 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& type_name);
static const char* lookup(EType asset_type);
// translation from a type to a human readable form.
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);
// 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 asset_type,
std::string& description);
static EType getType(const std::string& desc_name);
static const std::string& getDesc(EType asset_type);
static EDragAndDropType lookupDragAndDropType(EType asset_type);
static bool lookupCanLink(EType asset_type);
static bool lookupIsLinkType(EType asset_type);
static const char* lookupCategoryName(EType asset_type);
static bool lookupIsProtectedCategoryType(EType asset_type);
static bool lookupIsEnsembleCategoryType(EType asset_type);
/* TODO: Change return types from "const char *" to "const std::string &".
This is fairly straightforward, but requires changing some calls to use .c_str().
e.g.:
- fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
+ fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType).c_str());
*/
private:
// don't instantiate or derive one of these objects
LLAssetType( void ) {}
~LLAssetType( void ) {}
};
#endif // LL_LLASSETTYPE_H

View File

@ -32,9 +32,9 @@
*/
#ifndef LLBASE32_H
#define LLBASE32_h
#define LLBASE32_H
class LLBase32
class LL_COMMON_API LLBase32
{
public:
static std::string encode(const U8* input, size_t input_size);

View File

@ -32,9 +32,9 @@
*/
#ifndef LLBASE64_H
#define LLBASE64_h
#define LLBASE64_H
class LLBase64
class LL_COMMON_API LLBase64
{
public:
static std::string encode(const U8* input, size_t input_size);

View File

@ -37,7 +37,7 @@
#include "lltimer.h"
#include "llfile.h"
class LLCommon
class LL_COMMON_API LLCommon
{
public:
static void initClass();

118
indra/llcommon/llcoros.cpp Normal file
View File

@ -0,0 +1,118 @@
/**
* @file llcoros.cpp
* @author Nat Goodspeed
* @date 2009-06-03
* @brief Implementation for llcoros.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
* Copyright (c) 2009, Linden Research, Inc.
* $/LicenseInfo$
*/
// Precompiled header
#include "linden_common.h"
// associated header
#include "llcoros.h"
// STL headers
// std headers
// external library headers
#include <boost/bind.hpp>
// other Linden headers
#include "llevents.h"
#include "llerror.h"
#include "stringize.h"
LLCoros::LLCoros()
{
// Register our cleanup() method for "mainloop" ticks
LLEventPumps::instance().obtain("mainloop").listen(
"LLCoros", boost::bind(&LLCoros::cleanup, this, _1));
}
bool LLCoros::cleanup(const LLSD&)
{
// Walk the mCoros map, checking and removing completed coroutines.
for (CoroMap::iterator mi(mCoros.begin()), mend(mCoros.end()); mi != mend; )
{
// Has this coroutine exited (normal return, exception, exit() call)
// since last tick?
if (mi->second->exited())
{
LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL;
// The erase() call will invalidate its passed iterator value --
// so increment mi FIRST -- but pass its original value to
// erase(). This is what postincrement is all about.
mCoros.erase(mi++);
}
else
{
// Still live, just skip this entry as if incrementing at the top
// of the loop as usual.
++mi;
}
}
return false;
}
std::string LLCoros::launchImpl(const std::string& prefix, coro* newCoro)
{
std::string name(generateDistinctName(prefix));
mCoros.insert(name, newCoro);
/* Run the coroutine until its first wait, then return here */
(*newCoro)(std::nothrow);
return name;
}
std::string LLCoros::generateDistinctName(const std::string& prefix) const
{
// Allowing empty name would make getName()'s not-found return ambiguous.
if (prefix.empty())
{
LL_ERRS("LLCoros") << "LLCoros::launch(): pass non-empty name string" << LL_ENDL;
}
// If the specified name isn't already in the map, just use that.
std::string name(prefix);
// Find the lowest numeric suffix that doesn't collide with an existing
// entry. Start with 2 just to make it more intuitive for any interested
// parties: e.g. "joe", "joe2", "joe3"...
for (int i = 2; ; name = STRINGIZE(prefix << i++))
{
if (mCoros.find(name) == mCoros.end())
{
LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL;
return name;
}
}
}
bool LLCoros::kill(const std::string& name)
{
CoroMap::iterator found = mCoros.find(name);
if (found == mCoros.end())
{
return false;
}
// Because this is a boost::ptr_map, erasing the map entry also destroys
// the referenced heap object, in this case the boost::coroutine object,
// which will terminate the coroutine.
mCoros.erase(found);
return true;
}
std::string LLCoros::getNameByID(const void* self_id) const
{
// Walk the existing coroutines, looking for one from which the 'self_id'
// passed to us comes.
for (CoroMap::const_iterator mi(mCoros.begin()), mend(mCoros.end()); mi != mend; ++mi)
{
namespace coro_private = boost::coroutines::detail;
if (static_cast<void*>(coro_private::coroutine_accessor::get_impl(const_cast<coro&>(*mi->second)).get())
== self_id)
{
return mi->first;
}
}
return "";
}

149
indra/llcommon/llcoros.h Normal file
View File

@ -0,0 +1,149 @@
/**
* @file llcoros.h
* @author Nat Goodspeed
* @date 2009-06-02
* @brief Manage running boost::coroutine instances
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
* Copyright (c) 2009, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_LLCOROS_H)
#define LL_LLCOROS_H
#include <boost/coroutine/coroutine.hpp>
#include "llsingleton.h"
#include <boost/ptr_container/ptr_map.hpp>
#include <string>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/iteration/local.hpp>
#include <stdexcept>
/**
* Registry of named Boost.Coroutine instances
*
* The Boost.Coroutine library supports the general case of a coroutine
* accepting arbitrary parameters and yielding multiple (sets of) results. For
* such use cases, it's natural for the invoking code to retain the coroutine
* instance: the consumer repeatedly calls into the coroutine, perhaps passing
* new parameter values, prompting it to yield its next result.
*
* Our typical coroutine usage is different, though. For us, coroutines
* provide an alternative to the @c Responder pattern. Our typical coroutine
* has @c void return, invoked in fire-and-forget mode: the handler for some
* user gesture launches the coroutine and promptly returns to the main loop.
* The coroutine initiates some action that will take multiple frames (e.g. a
* capability request), waits for its result, processes it and silently steals
* away.
*
* This usage poses two (related) problems:
*
* # Who should own the coroutine instance? If it's simply local to the
* handler code that launches it, return from the handler will destroy the
* coroutine object, terminating the coroutine.
* # Once the coroutine terminates, in whatever way, who's responsible for
* cleaning up the coroutine object?
*
* LLCoros is a Singleton collection of currently-active coroutine instances.
* Each has a name. You ask LLCoros to launch a new coroutine with a suggested
* name prefix; from your prefix it generates a distinct name, registers the
* new coroutine and returns the actual name.
*
* The name can be used to kill off the coroutine prematurely, if needed. It
* can also provide diagnostic info: we can look up the name of the
* currently-running coroutine.
*
* Finally, the next frame ("mainloop" event) after the coroutine terminates,
* LLCoros will notice its demise and destroy it.
*/
class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
{
public:
/// Canonical boost::coroutines::coroutine signature we use
typedef boost::coroutines::coroutine<void()> coro;
/// Canonical 'self' type
typedef coro::self self;
/**
* Create and start running a new coroutine with specified name. The name
* string you pass is a suggestion; it will be tweaked for uniqueness. The
* actual name is returned to you.
*
* Usage looks like this, for (e.g.) two coroutine parameters:
* @code
* class MyClass
* {
* public:
* ...
* // Do NOT NOT NOT accept reference params other than 'self'!
* // Pass by value only!
* void myCoroutineMethod(LLCoros::self& self, std::string, LLSD);
* ...
* };
* ...
* std::string name = LLCoros::instance().launch(
* "mycoro", boost::bind(&MyClass::myCoroutineMethod, this, _1,
* "somestring", LLSD(17));
* @endcode
*
* Your function/method must accept LLCoros::self& as its first parameter.
* It can accept any other parameters you want -- but ONLY BY VALUE!
* Other reference parameters are a BAD IDEA! You Have Been Warned. See
* DEV-32777 comments for an explanation.
*
* Pass a callable that accepts the single LLCoros::self& parameter. It
* may work to pass a free function whose only parameter is 'self'; for
* all other cases use boost::bind(). Of course, for a non-static class
* method, the first parameter must be the class instance. Use the
* placeholder _1 for the 'self' parameter. Any other parameters should be
* passed via the bind() expression.
*
* launch() tweaks the suggested name so it won't collide with any
* existing coroutine instance, creates the coroutine instance, registers
* it with the tweaked name and runs it until its first wait. At that
* point it returns the tweaked name.
*/
template <typename CALLABLE>
std::string launch(const std::string& prefix, const CALLABLE& callable)
{
return launchImpl(prefix, new coro(callable));
}
/**
* Abort a running coroutine by name. Normally, when a coroutine either
* runs to completion or terminates with an exception, LLCoros quietly
* cleans it up. This is for use only when you must explicitly interrupt
* one prematurely. Returns @c true if the specified name was found and
* still running at the time.
*/
bool kill(const std::string& name);
/**
* From within a coroutine, pass its @c self object to look up the
* (tweaked) name string by which this coroutine is registered. Returns
* the empty string if not found (e.g. if the coroutine was launched by
* hand rather than using LLCoros::launch()).
*/
template <typename COROUTINE_SELF>
std::string getName(const COROUTINE_SELF& self) const
{
return getNameByID(self.get_id());
}
/// getName() by self.get_id()
std::string getNameByID(const void* self_id) const;
private:
friend class LLSingleton<LLCoros>;
LLCoros();
std::string launchImpl(const std::string& prefix, coro* newCoro);
std::string generateDistinctName(const std::string& prefix) const;
bool cleanup(const LLSD&);
typedef boost::ptr_map<std::string, coro> CoroMap;
CoroMap mCoros;
};
#endif /* ! defined(LL_LLCOROS_H) */

View File

@ -50,7 +50,7 @@
// llinfos << "File crc: " << crc.getCRC() << llendl;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLCRC
class LL_COMMON_API LLCRC
{
protected:
U32 mCurrent;

View File

@ -38,7 +38,7 @@
#include "llframetimer.h"
class LLCriticalDamp
class LL_COMMON_API LLCriticalDamp
{
public:
LLCriticalDamp();

View File

@ -77,6 +77,6 @@ enum ECursorType {
UI_CURSOR_COUNT // Number of elements in this enum (NOT a cursor)
};
ECursorType getCursorFromString(const std::string& cursor_string);
LL_COMMON_API ECursorType getCursorFromString(const std::string& cursor_string);
#endif // LL_LLCURSORTYPES_H

View File

@ -46,7 +46,7 @@
*
* The date class represents a point in time after epoch - 1970-01-01.
*/
class LLDate
class LL_COMMON_API LLDate
{
public:
/**
@ -155,10 +155,10 @@ private:
};
// Helper function to stream out a date
std::ostream& operator<<(std::ostream& s, const LLDate& date);
LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLDate& date);
// Helper function to stream in a date
std::istream& operator>>(std::istream& s, LLDate& date);
LL_COMMON_API std::istream& operator>>(std::istream& s, LLDate& date);
const static std::string weekdays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

View File

@ -81,7 +81,7 @@ struct instance_from_range: public TYPE
* LLDependencies components that should not be reinstantiated for each KEY,
* NODE specialization
*/
class LLDependenciesBase
class LL_COMMON_API LLDependenciesBase
{
public:
virtual ~LLDependenciesBase() {}

View File

@ -131,7 +131,7 @@ namespace LLError
class CallSite;
class Log
class LL_COMMON_API Log
{
public:
static bool shouldLog(CallSite&);
@ -140,7 +140,7 @@ namespace LLError
static void flush(std::ostringstream*, const CallSite&);
};
class CallSite
class LL_COMMON_API CallSite
{
// Represents a specific place in the code where a message is logged
// This is public because it is used by the macros below. It is not
@ -189,7 +189,7 @@ namespace LLError
//LLCallStacks is designed not to be thread-safe.
//so try not to use it in multiple parallel threads at same time.
//Used in a single thread at a time is fine.
class LLCallStacks
class LL_COMMON_API LLCallStacks
{
private:
static char** sBuffer ;

View File

@ -52,12 +52,12 @@ class LLSD;
namespace LLError
{
void initForServer(const std::string& identity);
LL_COMMON_API void initForServer(const std::string& identity);
// resets all logging settings to defaults needed by server processes
// logs to stderr, syslog, and windows debug log
// the identity string is used for in the syslog
void initForApplication(const std::string& dir);
LL_COMMON_API void initForApplication(const std::string& dir);
// resets all logging settings to defaults needed by applicaitons
// logs to stderr and windows debug log
// sets up log configuration from the file logcontrol.xml in dir
@ -68,14 +68,14 @@ namespace LLError
Setting a level means log messages at that level or above.
*/
void setPrintLocation(bool);
void setDefaultLevel(LLError::ELevel);
void setFunctionLevel(const std::string& function_name, LLError::ELevel);
void setClassLevel(const std::string& class_name, LLError::ELevel);
void setFileLevel(const std::string& file_name, LLError::ELevel);
LL_COMMON_API void setPrintLocation(bool);
LL_COMMON_API void setDefaultLevel(LLError::ELevel);
LL_COMMON_API void setFunctionLevel(const std::string& function_name, LLError::ELevel);
LL_COMMON_API void setClassLevel(const std::string& class_name, LLError::ELevel);
LL_COMMON_API void setFileLevel(const std::string& file_name, LLError::ELevel);
void setTagLevel(const std::string& file_name, LLError::ELevel);
void configure(const LLSD&);
LL_COMMON_API void configure(const LLSD&);
// the LLSD can configure all of the settings
// usually read automatically from the live errorlog.xml file
@ -85,21 +85,21 @@ namespace LLError
*/
typedef boost::function<void(const std::string&)> FatalFunction;
void crashAndLoop(const std::string& message);
LL_COMMON_API void crashAndLoop(const std::string& message);
// Default fatal function: access null pointer and loops forever
void setFatalFunction(const FatalFunction&);
LL_COMMON_API void setFatalFunction(const FatalFunction&);
// The fatal function will be called when an message of LEVEL_ERROR
// is logged. Note: supressing a LEVEL_ERROR message from being logged
// (by, for example, setting a class level to LEVEL_NONE), will keep
// the that message from causing the fatal funciton to be invoked.
FatalFunction getFatalFunction();
LL_COMMON_API FatalFunction getFatalFunction();
// Retrieve the previously-set FatalFunction
/// temporarily override the FatalFunction for the duration of a
/// particular scope, e.g. for unit tests
class OverrideFatalFunction
class LL_COMMON_API OverrideFatalFunction
{
public:
OverrideFatalFunction(const FatalFunction& func):
@ -117,15 +117,15 @@ namespace LLError
};
typedef std::string (*TimeFunction)();
std::string utcTime();
LL_COMMON_API std::string utcTime();
void setTimeFunction(TimeFunction);
LL_COMMON_API void setTimeFunction(TimeFunction);
// The function is use to return the current time, formatted for
// display by those error recorders that want the time included.
class Recorder
class LL_COMMON_API Recorder
{
// An object that handles the actual output or error messages.
public:
@ -139,17 +139,17 @@ namespace LLError
// included in the text of the message
};
void addRecorder(Recorder*);
void removeRecorder(Recorder*);
LL_COMMON_API void addRecorder(Recorder*);
LL_COMMON_API void removeRecorder(Recorder*);
// each error message is passed to each recorder via recordMessage()
void logToFile(const std::string& filename);
void logToFixedBuffer(LLFixedBuffer*);
LL_COMMON_API void logToFile(const std::string& filename);
LL_COMMON_API void logToFixedBuffer(LLFixedBuffer*);
// Utilities to add recorders for logging to a file or a fixed buffer
// A second call to the same function will remove the logger added
// with the first.
// Passing the empty string or NULL to just removes any prior.
std::string logFileName();
LL_COMMON_API std::string logFileName();
// returns name of current logging file, empty string if none
@ -158,11 +158,11 @@ namespace LLError
*/
class Settings;
Settings* saveAndResetSettings();
void restoreSettings(Settings *);
LL_COMMON_API Settings* saveAndResetSettings();
LL_COMMON_API void restoreSettings(Settings *);
std::string abbreviateFile(const std::string& filePath);
int shouldLogCallCount();
LL_COMMON_API std::string abbreviateFile(const std::string& filePath);
LL_COMMON_API int shouldLogCallCount();
};

View File

@ -35,7 +35,7 @@
#include "llthread.h"
class LLErrorThread : public LLThread
class LL_COMMON_API LLErrorThread : public LLThread
{
public:
LLErrorThread();

View File

@ -47,7 +47,7 @@ class LLEventDispatcher;
class LLObservable;
// Abstract event. All events derive from LLEvent
class LLEvent : public LLThreadSafeRefCount
class LL_COMMON_API LLEvent : public LLThreadSafeRefCount
{
protected:
virtual ~LLEvent();
@ -75,7 +75,7 @@ private:
};
// Abstract listener. All listeners derive from LLEventListener
class LLEventListener : public LLThreadSafeRefCount
class LL_COMMON_API LLEventListener : public LLThreadSafeRefCount
{
protected:
virtual ~LLEventListener();
@ -92,7 +92,7 @@ public:
};
// A listener which tracks references to it and cleans up when it's deallocated
class LLSimpleListener : public LLEventListener
class LL_COMMON_API LLSimpleListener : public LLEventListener
{
public:
void clearDispatchers();
@ -117,7 +117,7 @@ struct LLListenerEntry
// Base class for a dispatcher - an object which listens
// to events being fired and relays them to their
// appropriate destinations.
class LLEventDispatcher : public LLThreadSafeRefCount
class LL_COMMON_API LLEventDispatcher : public LLThreadSafeRefCount
{
protected:
virtual ~LLEventDispatcher();
@ -160,7 +160,7 @@ private:
// In order for this class to work properly, it needs
// an instance of an LLEventDispatcher to route events to their
// listeners.
class LLObservable
class LL_COMMON_API LLObservable
{
public:
// Initialize with the default Dispatcher

View File

@ -0,0 +1,129 @@
/**
* @file lleventcoro.cpp
* @author Nat Goodspeed
* @date 2009-04-29
* @brief Implementation for lleventcoro.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
* Copyright (c) 2009, Linden Research, Inc.
* $/LicenseInfo$
*/
// Precompiled header
#include "linden_common.h"
// associated header
#include "lleventcoro.h"
// STL headers
#include <map>
// std headers
// external library headers
// other Linden headers
#include "llsdserialize.h"
#include "llerror.h"
#include "llcoros.h"
std::string LLEventDetail::listenerNameForCoroImpl(const void* self_id)
{
// First, if this coroutine was launched by LLCoros::launch(), find that name.
std::string name(LLCoros::instance().getNameByID(self_id));
if (! name.empty())
{
return name;
}
// Apparently this coroutine wasn't launched by LLCoros::launch(). Check
// whether we have a memo for this self_id.
typedef std::map<const void*, std::string> MapType;
static MapType memo;
MapType::const_iterator found = memo.find(self_id);
if (found != memo.end())
{
// this coroutine instance has called us before, reuse same name
return found->second;
}
// this is the first time we've been called for this coroutine instance
name = LLEventPump::inventName("coro");
memo[self_id] = name;
LL_INFOS("LLEventCoro") << "listenerNameForCoroImpl(" << self_id << "): inventing coro name '"
<< name << "'" << LL_ENDL;
return name;
}
void LLEventDetail::storeToLLSDPath(LLSD& dest, const LLSD& rawPath, const LLSD& value)
{
if (rawPath.isUndefined())
{
// no-op case
return;
}
// Arrange to treat rawPath uniformly as an array. If it's not already an
// array, store it as the only entry in one.
LLSD path;
if (rawPath.isArray())
{
path = rawPath;
}
else
{
path.append(rawPath);
}
// Need to indicate a current destination -- but that current destination
// needs to change as we step through the path array. Where normally we'd
// use an LLSD& to capture a subscripted LLSD lvalue, this time we must
// instead use a pointer -- since it must be reassigned.
LLSD* pdest = &dest;
// Now loop through that array
for (LLSD::Integer i = 0; i < path.size(); ++i)
{
if (path[i].isString())
{
// *pdest is an LLSD map
pdest = &((*pdest)[path[i].asString()]);
}
else if (path[i].isInteger())
{
// *pdest is an LLSD array
pdest = &((*pdest)[path[i].asInteger()]);
}
else
{
// What do we do with Real or Array or Map or ...?
// As it's a coder error -- not a user error -- rub the coder's
// face in it so it gets fixed.
LL_ERRS("lleventcoro") << "storeToLLSDPath(" << dest << ", " << rawPath << ", " << value
<< "): path[" << i << "] bad type " << path[i].type() << LL_ENDL;
}
}
// Here *pdest is where we should store value.
*pdest = value;
}
LLSD errorException(const LLEventWithID& result, const std::string& desc)
{
// If the result arrived on the error pump (pump 1), instead of
// returning it, deliver it via exception.
if (result.second)
{
throw LLErrorEvent(desc, result.first);
}
// That way, our caller knows a simple return must be from the reply
// pump (pump 0).
return result.first;
}
LLSD errorLog(const LLEventWithID& result, const std::string& desc)
{
// If the result arrived on the error pump (pump 1), log it as a fatal
// error.
if (result.second)
{
LL_ERRS("errorLog") << desc << ":" << std::endl;
LLSDSerialize::toPrettyXML(result.first, LL_CONT);
LL_CONT << LL_ENDL;
}
// A simple return must therefore be from the reply pump (pump 0).
return result.first;
}

View File

@ -0,0 +1,549 @@
/**
* @file lleventcoro.h
* @author Nat Goodspeed
* @date 2009-04-29
* @brief Utilities to interface between coroutines and events.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
* Copyright (c) 2009, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_LLEVENTCORO_H)
#define LL_LLEVENTCORO_H
#include <boost/coroutine/coroutine.hpp>
#include <boost/coroutine/future.hpp>
#include <boost/optional.hpp>
#include <string>
#include <stdexcept>
#include "llevents.h"
#include "llerror.h"
/**
* Like LLListenerOrPumpName, this is a class intended for parameter lists:
* accept a <tt>const LLEventPumpOrPumpName&</tt> and you can accept either an
* <tt>LLEventPump&</tt> or its string name. For a single parameter that could
* be either, it's not hard to overload the function -- but as soon as you
* want to accept two such parameters, this is cheaper than four overloads.
*/
class LLEventPumpOrPumpName
{
public:
/// Pass an actual LLEventPump&
LLEventPumpOrPumpName(LLEventPump& pump):
mPump(pump)
{}
/// Pass the string name of an LLEventPump
LLEventPumpOrPumpName(const std::string& pumpname):
mPump(LLEventPumps::instance().obtain(pumpname))
{}
/// Pass string constant name of an LLEventPump. This override must be
/// explicit, since otherwise passing <tt>const char*</tt> to a function
/// accepting <tt>const LLEventPumpOrPumpName&</tt> would require two
/// different implicit conversions: <tt>const char*</tt> -> <tt>const
/// std::string&</tt> -> <tt>const LLEventPumpOrPumpName&</tt>.
LLEventPumpOrPumpName(const char* pumpname):
mPump(LLEventPumps::instance().obtain(pumpname))
{}
/// Unspecified: "I choose not to identify an LLEventPump."
LLEventPumpOrPumpName() {}
operator LLEventPump& () const { return *mPump; }
LLEventPump& getPump() const { return *mPump; }
operator bool() const { return mPump; }
bool operator!() const { return ! mPump; }
private:
boost::optional<LLEventPump&> mPump;
};
/// This is an adapter for a signature like void LISTENER(const LLSD&), which
/// isn't a valid LLEventPump listener: such listeners should return bool.
template <typename LISTENER>
class LLVoidListener
{
public:
LLVoidListener(const LISTENER& listener):
mListener(listener)
{}
bool operator()(const LLSD& event)
{
mListener(event);
// don't swallow the event, let other listeners see it
return false;
}
private:
LISTENER mListener;
};
/// LLVoidListener helper function to infer the type of the LISTENER
template <typename LISTENER>
LLVoidListener<LISTENER> voidlistener(const LISTENER& listener)
{
return LLVoidListener<LISTENER>(listener);
}
namespace LLEventDetail
{
/**
* waitForEventOn() permits a coroutine to temporarily listen on an
* LLEventPump any number of times. We don't really want to have to ask
* the caller to label each such call with a distinct string; the whole
* point of waitForEventOn() is to present a nice sequential interface to
* the underlying LLEventPump-with-named-listeners machinery. So we'll use
* LLEventPump::inventName() to generate a distinct name for each
* temporary listener. On the other hand, because a given coroutine might
* call waitForEventOn() any number of times, we don't really want to
* consume an arbitrary number of generated inventName()s: that namespace,
* though large, is nonetheless finite. So we memoize an invented name for
* each distinct coroutine instance (each different 'self' object). We
* can't know the type of 'self', because it depends on the coroutine
* body's signature. So we cast its address to void*, looking for distinct
* pointer values. Yes, that means that an early coroutine could cache a
* value here, then be destroyed, only to be supplanted by a later
* coroutine (of the same or different type), and we'll end up
* "recognizing" the second one and reusing the listener name -- but
* that's okay, since it won't collide with any listener name used by the
* earlier coroutine since that earlier coroutine no longer exists.
*/
template <typename COROUTINE_SELF>
std::string listenerNameForCoro(COROUTINE_SELF& self)
{
return listenerNameForCoroImpl(self.get_id());
}
/// Implementation for listenerNameForCoro()
LL_COMMON_API std::string listenerNameForCoroImpl(const void* self_id);
/**
* Implement behavior described for postAndWait()'s @a replyPumpNamePath
* parameter:
*
* * If <tt>path.isUndefined()</tt>, do nothing.
* * If <tt>path.isString()</tt>, @a dest is an LLSD map: store @a value
* into <tt>dest[path.asString()]</tt>.
* * If <tt>path.isInteger()</tt>, @a dest is an LLSD array: store @a
* value into <tt>dest[path.asInteger()]</tt>.
* * If <tt>path.isArray()</tt>, iteratively apply the rules above to step
* down through the structure of @a dest. The last array entry in @a
* path specifies the entry in the lowest-level structure in @a dest
* into which to store @a value.
*
* @note
* In the degenerate case in which @a path is an empty array, @a dest will
* @em become @a value rather than @em containing it.
*/
LL_COMMON_API void storeToLLSDPath(LLSD& dest, const LLSD& path, const LLSD& value);
} // namespace LLEventDetail
/**
* Post specified LLSD event on the specified LLEventPump, then wait for a
* response on specified other LLEventPump. This is more than mere
* convenience: the difference between this function and the sequence
* @code
* requestPump.post(myEvent);
* LLSD reply = waitForEventOn(self, replyPump);
* @endcode
* is that the sequence above fails if the reply is posted immediately on
* @a replyPump, that is, before <tt>requestPump.post()</tt> returns. In the
* sequence above, the running coroutine isn't even listening on @a replyPump
* until <tt>requestPump.post()</tt> returns and @c waitForEventOn() is
* entered. Therefore, the coroutine completely misses an immediate reply
* event, making it wait indefinitely.
*
* By contrast, postAndWait() listens on the @a replyPump @em before posting
* the specified LLSD event on the specified @a requestPump.
*
* @param self The @c self object passed into a coroutine
* @param event LLSD data to be posted on @a requestPump
* @param requestPump an LLEventPump on which to post @a event. Pass either
* the LLEventPump& or its string name. However, if you pass a
* default-constructed @c LLEventPumpOrPumpName, we skip the post() call.
* @param replyPump an LLEventPump on which postAndWait() will listen for a
* reply. Pass either the LLEventPump& or its string name. The calling
* coroutine will wait until that reply arrives. (If you're concerned about a
* reply that might not arrive, please see also LLEventTimeout.)
* @param replyPumpNamePath specifies the location within @a event in which to
* store <tt>replyPump.getName()</tt>. This is a strictly optional convenience
* feature; obviously you can store the name in @a event "by hand" if desired.
* @a replyPumpNamePath can be specified in any of four forms:
* * @c isUndefined() (default-constructed LLSD object): do nothing. This is
* the default behavior if you omit @a replyPumpNamePath.
* * @c isInteger(): @a event is an array. Store <tt>replyPump.getName()</tt>
* in <tt>event[replyPumpNamePath.asInteger()]</tt>.
* * @c isString(): @a event is a map. Store <tt>replyPump.getName()</tt> in
* <tt>event[replyPumpNamePath.asString()]</tt>.
* * @c isArray(): @a event has several levels of structure, e.g. map of
* maps, array of arrays, array of maps, map of arrays, ... Store
* <tt>replyPump.getName()</tt> in
* <tt>event[replyPumpNamePath[0]][replyPumpNamePath[1]]...</tt> In other
* words, examine each array entry in @a replyPumpNamePath in turn. If it's an
* <tt>LLSD::String</tt>, the current level of @a event is a map; step down to
* that map entry. If it's an <tt>LLSD::Integer</tt>, the current level of @a
* event is an array; step down to that array entry. The last array entry in
* @a replyPumpNamePath specifies the entry in the lowest-level structure in
* @a event into which to store <tt>replyPump.getName()</tt>.
*/
template <typename SELF>
LLSD postAndWait(SELF& self, const LLSD& event, const LLEventPumpOrPumpName& requestPump,
const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath=LLSD())
{
// declare the future
boost::coroutines::future<LLSD> future(self);
// make a callback that will assign a value to the future, and listen on
// the specified LLEventPump with that callback
std::string listenerName(LLEventDetail::listenerNameForCoro(self));
LLTempBoundListener connection(
replyPump.getPump().listen(listenerName,
voidlistener(boost::coroutines::make_callback(future))));
// skip the "post" part if requestPump is default-constructed
if (requestPump)
{
// If replyPumpNamePath is non-empty, store the replyPump name in the
// request event.
LLSD modevent(event);
LLEventDetail::storeToLLSDPath(modevent, replyPumpNamePath, replyPump.getPump().getName());
LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName
<< " posting to " << requestPump.getPump().getName()
<< ": " << modevent << LL_ENDL;
requestPump.getPump().post(modevent);
}
LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName
<< " about to wait on LLEventPump " << replyPump.getPump().getName()
<< LL_ENDL;
// trying to dereference ("resolve") the future makes us wait for it
LLSD value(*future);
LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName
<< " resuming with " << value << LL_ENDL;
// returning should disconnect the connection
return value;
}
/// Wait for the next event on the specified LLEventPump. Pass either the
/// LLEventPump& or its string name.
template <typename SELF>
LLSD waitForEventOn(SELF& self, const LLEventPumpOrPumpName& pump)
{
// This is now a convenience wrapper for postAndWait().
return postAndWait(self, LLSD(), LLEventPumpOrPumpName(), pump);
}
/// return type for two-pump variant of waitForEventOn()
typedef std::pair<LLSD, int> LLEventWithID;
namespace LLEventDetail
{
/**
* This helper is specifically for the two-pump version of waitForEventOn().
* We use a single future object, but we want to listen on two pumps with it.
* Since we must still adapt from (the callable constructed by)
* boost::coroutines::make_callback() (void return) to provide an event
* listener (bool return), we've adapted LLVoidListener for the purpose. The
* basic idea is that we construct a distinct instance of WaitForEventOnHelper
* -- binding different instance data -- for each of the pumps. Then, when a
* pump delivers an LLSD value to either WaitForEventOnHelper, it can combine
* that LLSD with its discriminator to feed the future object.
*/
template <typename LISTENER>
class WaitForEventOnHelper
{
public:
WaitForEventOnHelper(const LISTENER& listener, int discriminator):
mListener(listener),
mDiscrim(discriminator)
{}
// this signature is required for an LLEventPump listener
bool operator()(const LLSD& event)
{
// our future object is defined to accept LLEventWithID
mListener(LLEventWithID(event, mDiscrim));
// don't swallow the event, let other listeners see it
return false;
}
private:
LISTENER mListener;
const int mDiscrim;
};
/// WaitForEventOnHelper type-inference helper
template <typename LISTENER>
WaitForEventOnHelper<LISTENER> wfeoh(const LISTENER& listener, int discriminator)
{
return WaitForEventOnHelper<LISTENER>(listener, discriminator);
}
} // namespace LLEventDetail
/**
* This function waits for a reply on either of two specified LLEventPumps.
* Otherwise, it closely resembles postAndWait(); please see the documentation
* for that function for detailed parameter info.
*
* While we could have implemented the single-pump variant in terms of this
* one, there's enough added complexity here to make it worthwhile to give the
* single-pump variant its own straightforward implementation. Conversely,
* though we could use preprocessor logic to generate n-pump overloads up to
* BOOST_COROUTINE_WAIT_MAX, we don't foresee a use case. This two-pump
* overload exists because certain event APIs are defined in terms of a reply
* LLEventPump and an error LLEventPump.
*
* The LLEventWithID return value provides not only the received event, but
* the index of the pump on which it arrived (0 or 1).
*
* @note
* I'd have preferred to overload the name postAndWait() for both signatures.
* But consider the following ambiguous call:
* @code
* postAndWait(self, LLSD(), requestPump, replyPump, "someString");
* @endcode
* "someString" could be converted to either LLSD (@a replyPumpNamePath for
* the single-pump function) or LLEventOrPumpName (@a replyPump1 for two-pump
* function).
*
* It seems less burdensome to write postAndWait2() than to write either
* LLSD("someString") or LLEventOrPumpName("someString").
*/
template <typename SELF>
LLEventWithID postAndWait2(SELF& self, const LLSD& event,
const LLEventPumpOrPumpName& requestPump,
const LLEventPumpOrPumpName& replyPump0,
const LLEventPumpOrPumpName& replyPump1,
const LLSD& replyPump0NamePath=LLSD(),
const LLSD& replyPump1NamePath=LLSD())
{
// declare the future
boost::coroutines::future<LLEventWithID> future(self);
// either callback will assign a value to this future; listen on
// each specified LLEventPump with a callback
std::string name(LLEventDetail::listenerNameForCoro(self));
LLTempBoundListener connection0(
replyPump0.getPump().listen(name + "a",
LLEventDetail::wfeoh(boost::coroutines::make_callback(future), 0)));
LLTempBoundListener connection1(
replyPump1.getPump().listen(name + "b",
LLEventDetail::wfeoh(boost::coroutines::make_callback(future), 1)));
// skip the "post" part if requestPump is default-constructed
if (requestPump)
{
// If either replyPumpNamePath is non-empty, store the corresponding
// replyPump name in the request event.
LLSD modevent(event);
LLEventDetail::storeToLLSDPath(modevent, replyPump0NamePath,
replyPump0.getPump().getName());
LLEventDetail::storeToLLSDPath(modevent, replyPump1NamePath,
replyPump1.getPump().getName());
LL_DEBUGS("lleventcoro") << "postAndWait2(): coroutine " << name
<< " posting to " << requestPump.getPump().getName()
<< ": " << modevent << LL_ENDL;
requestPump.getPump().post(modevent);
}
LL_DEBUGS("lleventcoro") << "postAndWait2(): coroutine " << name
<< " about to wait on LLEventPumps " << replyPump0.getPump().getName()
<< ", " << replyPump1.getPump().getName() << LL_ENDL;
// trying to dereference ("resolve") the future makes us wait for it
LLEventWithID value(*future);
LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << name
<< " resuming with (" << value.first << ", " << value.second << ")"
<< LL_ENDL;
// returning should disconnect both connections
return value;
}
/**
* Wait for the next event on either of two specified LLEventPumps.
*/
template <typename SELF>
LLEventWithID
waitForEventOn(SELF& self,
const LLEventPumpOrPumpName& pump0, const LLEventPumpOrPumpName& pump1)
{
// This is now a convenience wrapper for postAndWait2().
return postAndWait2(self, LLSD(), LLEventPumpOrPumpName(), pump0, pump1);
}
/**
* Helper for the two-pump variant of waitForEventOn(), e.g.:
*
* @code
* LLSD reply = errorException(waitForEventOn(self, replyPump, errorPump),
* "error response from login.cgi");
* @endcode
*
* Examines an LLEventWithID, assuming that the second pump (pump 1) is
* listening for an error indication. If the incoming data arrived on pump 1,
* throw an LLErrorEvent exception. If the incoming data arrived on pump 0,
* just return it. Since a normal return can only be from pump 0, we no longer
* need the LLEventWithID's discriminator int; we can just return the LLSD.
*
* @note I'm not worried about introducing the (fairly generic) name
* errorException() into global namespace, because how many other overloads of
* the same name are going to accept an LLEventWithID parameter?
*/
LLSD errorException(const LLEventWithID& result, const std::string& desc);
/**
* Exception thrown by errorException(). We don't call this LLEventError
* because it's not an error in event processing: rather, this exception
* announces an event that bears error information (for some other API).
*/
class LL_COMMON_API LLErrorEvent: public std::runtime_error
{
public:
LLErrorEvent(const std::string& what, const LLSD& data):
std::runtime_error(what),
mData(data)
{}
virtual ~LLErrorEvent() throw() {}
LLSD getData() const { return mData; }
private:
LLSD mData;
};
/**
* Like errorException(), save that this trips a fatal error using LL_ERRS
* rather than throwing an exception.
*/
LL_COMMON_API LLSD errorLog(const LLEventWithID& result, const std::string& desc);
/**
* Certain event APIs require the name of an LLEventPump on which they should
* post results. While it works to invent a distinct name and let
* LLEventPumps::obtain() instantiate the LLEventPump as a "named singleton,"
* in a certain sense it's more robust to instantiate a local LLEventPump and
* provide its name instead. This class packages the following idiom:
*
* 1. Instantiate a local LLCoroEventPump, with an optional name prefix.
* 2. Provide its actual name to the event API in question as the name of the
* reply LLEventPump.
* 3. Initiate the request to the event API.
* 4. Call your LLEventTempStream's wait() method to wait for the reply.
* 5. Let the LLCoroEventPump go out of scope.
*/
class LL_COMMON_API LLCoroEventPump
{
public:
LLCoroEventPump(const std::string& name="coro"):
mPump(name, true) // allow tweaking the pump instance name
{}
/// It's typical to request the LLEventPump name to direct an event API to
/// send its response to this pump.
std::string getName() const { return mPump.getName(); }
/// Less typically, we'd request the pump itself for some reason.
LLEventPump& getPump() { return mPump; }
/**
* Wait for an event on this LLEventPump.
*
* @note
* The other major usage pattern we considered was to bind @c self at
* LLCoroEventPump construction time, which would avoid passing the
* parameter to each wait() call. But if we were going to bind @c self as
* a class member, we'd need to specify a class template parameter
* indicating its type. The big advantage of passing it to the wait() call
* is that the type can be implicit.
*/
template <typename SELF>
LLSD wait(SELF& self)
{
return waitForEventOn(self, mPump);
}
template <typename SELF>
LLSD postAndWait(SELF& self, const LLSD& event, const LLEventPumpOrPumpName& requestPump,
const LLSD& replyPumpNamePath=LLSD())
{
return ::postAndWait(self, event, requestPump, mPump, replyPumpNamePath);
}
private:
LLEventStream mPump;
};
/**
* Other event APIs require the names of two different LLEventPumps: one for
* success response, the other for error response. Extend LLCoroEventPump
* for the two-pump use case.
*/
class LL_COMMON_API LLCoroEventPumps
{
public:
LLCoroEventPumps(const std::string& name="coro",
const std::string& suff0="Reply",
const std::string& suff1="Error"):
mPump0(name + suff0, true), // allow tweaking the pump instance name
mPump1(name + suff1, true)
{}
/// request pump 0's name
std::string getName0() const { return mPump0.getName(); }
/// request pump 1's name
std::string getName1() const { return mPump1.getName(); }
/// request both names
std::pair<std::string, std::string> getNames() const
{
return std::pair<std::string, std::string>(mPump0.getName(), mPump1.getName());
}
/// request pump 0
LLEventPump& getPump0() { return mPump0; }
/// request pump 1
LLEventPump& getPump1() { return mPump1; }
/// waitForEventOn(self, either of our two LLEventPumps)
template <typename SELF>
LLEventWithID wait(SELF& self)
{
return waitForEventOn(self, mPump0, mPump1);
}
/// errorException(wait(self))
template <typename SELF>
LLSD waitWithException(SELF& self)
{
return errorException(wait(self), std::string("Error event on ") + getName1());
}
/// errorLog(wait(self))
template <typename SELF>
LLSD waitWithLog(SELF& self)
{
return errorLog(wait(self), std::string("Error event on ") + getName1());
}
template <typename SELF>
LLEventWithID postAndWait(SELF& self, const LLSD& event,
const LLEventPumpOrPumpName& requestPump,
const LLSD& replyPump0NamePath=LLSD(),
const LLSD& replyPump1NamePath=LLSD())
{
return postAndWait2(self, event, requestPump, mPump0, mPump1,
replyPump0NamePath, replyPump1NamePath);
}
template <typename SELF>
LLSD postAndWaitWithException(SELF& self, const LLSD& event,
const LLEventPumpOrPumpName& requestPump,
const LLSD& replyPump0NamePath=LLSD(),
const LLSD& replyPump1NamePath=LLSD())
{
return errorException(postAndWait(self, event, requestPump,
replyPump0NamePath, replyPump1NamePath),
std::string("Error event on ") + getName1());
}
template <typename SELF>
LLSD postAndWaitWithLog(SELF& self, const LLSD& event,
const LLEventPumpOrPumpName& requestPump,
const LLSD& replyPump0NamePath=LLSD(),
const LLSD& replyPump1NamePath=LLSD())
{
return errorLog(postAndWait(self, event, requestPump,
replyPump0NamePath, replyPump1NamePath),
std::string("Error event on ") + getName1());
}
private:
LLEventStream mPump0, mPump1;
};
#endif /* ! defined(LL_LLEVENTCORO_H) */

View File

@ -0,0 +1,123 @@
/**
* @file lleventdispatcher.cpp
* @author Nat Goodspeed
* @date 2009-06-18
* @brief Implementation for lleventdispatcher.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
* Copyright (c) 2009, Linden Research, Inc.
* $/LicenseInfo$
*/
#if LL_WINDOWS
#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
#endif
// Precompiled header
#include "linden_common.h"
// associated header
#include "lleventdispatcher.h"
// STL headers
// std headers
// external library headers
// other Linden headers
#include "llevents.h"
#include "llerror.h"
#include "llsdutil.h"
LLEventDispatcher::LLEventDispatcher(const std::string& desc, const std::string& key):
mDesc(desc),
mKey(key)
{
}
LLEventDispatcher::~LLEventDispatcher()
{
}
/// Register a callable by name
void LLEventDispatcher::add(const std::string& name, const Callable& callable, const LLSD& required)
{
mDispatch[name] = DispatchMap::mapped_type(callable, required);
}
void LLEventDispatcher::addFail(const std::string& name, const std::string& classname) const
{
LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << ")::add(" << name
<< "): " << classname << " is not a subclass "
<< "of LLEventDispatcher" << LL_ENDL;
}
/// Unregister a callable
bool LLEventDispatcher::remove(const std::string& name)
{
DispatchMap::iterator found = mDispatch.find(name);
if (found == mDispatch.end())
{
return false;
}
mDispatch.erase(found);
return true;
}
/// Call a registered callable with an explicitly-specified name. If no
/// such callable exists, die with LL_ERRS.
void LLEventDispatcher::operator()(const std::string& name, const LLSD& event) const
{
if (! attemptCall(name, event))
{
LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << "): '" << name
<< "' not found" << LL_ENDL;
}
}
/// Extract the @a key value from the incoming @a event, and call the
/// callable whose name is specified by that map @a key. If no such
/// callable exists, die with LL_ERRS.
void LLEventDispatcher::operator()(const LLSD& event) const
{
// This could/should be implemented in terms of the two-arg overload.
// However -- we can produce a more informative error message.
std::string name(event[mKey]);
if (! attemptCall(name, event))
{
LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << "): bad " << mKey
<< " value '" << name << "'" << LL_ENDL;
}
}
bool LLEventDispatcher::attemptCall(const std::string& name, const LLSD& event) const
{
DispatchMap::const_iterator found = mDispatch.find(name);
if (found == mDispatch.end())
{
// The reason we only return false, leaving it up to our caller to die
// with LL_ERRS, is that different callers have different amounts of
// available information.
return false;
}
// Found the name, so it's plausible to even attempt the call. But first,
// validate the syntax of the event itself.
std::string mismatch(llsd_matches(found->second.second, event));
if (! mismatch.empty())
{
LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << ") calling '" << name
<< "': bad request: " << mismatch << LL_ENDL;
}
// Event syntax looks good, go for it!
(found->second.first)(event);
return true; // tell caller we were able to call
}
LLDispatchListener::LLDispatchListener(const std::string& pumpname, const std::string& key):
LLEventDispatcher(pumpname, key),
mPump(pumpname, true), // allow tweaking for uniqueness
mBoundListener(mPump.listen("self", boost::bind(&LLDispatchListener::process, this, _1)))
{
}
bool LLDispatchListener::process(const LLSD& event)
{
(*this)(event);
return false;
}

View File

@ -0,0 +1,126 @@
/**
* @file lleventdispatcher.h
* @author Nat Goodspeed
* @date 2009-06-18
* @brief Central mechanism for dispatching events by string name. This is
* useful when you have a single LLEventPump listener on which you can
* request different operations, vs. instantiating a different
* LLEventPump for each such operation.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
* Copyright (c) 2009, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_LLEVENTDISPATCHER_H)
#define LL_LLEVENTDISPATCHER_H
#include <string>
#include <map>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <typeinfo>
#include "llevents.h"
class LLSD;
/**
* Given an LLSD map, examine a string-valued key and call a corresponding
* callable. This class is designed to be contained by an LLEventPump
* listener class that will register some of its own methods, though any
* callable can be used.
*/
class LL_COMMON_API LLEventDispatcher
{
public:
LLEventDispatcher(const std::string& desc, const std::string& key);
virtual ~LLEventDispatcher();
/// Accept any C++ callable, typically a boost::bind() expression
typedef boost::function<void(const LLSD&)> Callable;
/**
* Register a @a callable by @a name. The optional @a required parameter
* is used to validate the structure of each incoming event (see
* llsd_matches()).
*/
void add(const std::string& name, const Callable& callable, const LLSD& required=LLSD());
/**
* Special case: a subclass of this class can pass an unbound member
* function pointer without explicitly specifying the
* <tt>boost::bind()</tt> expression.
*/
template <class CLASS>
void add(const std::string& name, void (CLASS::*method)(const LLSD&),
const LLSD& required=LLSD())
{
addMethod<CLASS>(name, method, required);
}
/// Overload for both const and non-const methods
template <class CLASS>
void add(const std::string& name, void (CLASS::*method)(const LLSD&) const,
const LLSD& required=LLSD())
{
addMethod<CLASS>(name, method, required);
}
/// Unregister a callable
bool remove(const std::string& name);
/// Call a registered callable with an explicitly-specified name. If no
/// such callable exists, die with LL_ERRS. If the @a event fails to match
/// the @a required prototype specified at add() time, die with LL_ERRS.
void operator()(const std::string& name, const LLSD& event) const;
/// Extract the @a key value from the incoming @a event, and call the
/// callable whose name is specified by that map @a key. If no such
/// callable exists, die with LL_ERRS. If the @a event fails to match the
/// @a required prototype specified at add() time, die with LL_ERRS.
void operator()(const LLSD& event) const;
private:
template <class CLASS, typename METHOD>
void addMethod(const std::string& name, const METHOD& method, const LLSD& required)
{
CLASS* downcast = dynamic_cast<CLASS*>(this);
if (! downcast)
{
addFail(name, typeid(CLASS).name());
}
else
{
add(name, boost::bind(method, downcast, _1), required);
}
}
void addFail(const std::string& name, const std::string& classname) const;
/// try to dispatch, return @c true if success
bool attemptCall(const std::string& name, const LLSD& event) const;
std::string mDesc, mKey;
typedef std::map<std::string, std::pair<Callable, LLSD> > DispatchMap;
DispatchMap mDispatch;
};
/**
* Bundle an LLEventPump and a listener with an LLEventDispatcher. A class
* that contains (or derives from) LLDispatchListener need only specify the
* LLEventPump name and dispatch key, and add() its methods. Incoming events
* will automatically be dispatched.
*/
class LL_COMMON_API LLDispatchListener: public LLEventDispatcher
{
public:
LLDispatchListener(const std::string& pumpname, const std::string& key);
std::string getPumpName() const { return mPump.getName(); }
private:
bool process(const LLSD& event);
LLEventStream mPump;
LLTempBoundListener mBoundListener;
};
#endif /* ! defined(LL_LLEVENTDISPATCHER_H) */

View File

@ -0,0 +1,149 @@
/**
* @file lleventfilter.cpp
* @author Nat Goodspeed
* @date 2009-03-05
* @brief Implementation for lleventfilter.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
* Copyright (c) 2009, Linden Research, Inc.
* $/LicenseInfo$
*/
// Precompiled header
#include "linden_common.h"
// associated header
#include "lleventfilter.h"
// STL headers
// std headers
// external library headers
#include <boost/bind.hpp>
// other Linden headers
#include "llerror.h" // LL_ERRS
#include "llsdutil.h" // llsd_matches()
LLEventFilter::LLEventFilter(LLEventPump& source, const std::string& name, bool tweak):
LLEventStream(name, tweak)
{
source.listen(getName(), boost::bind(&LLEventFilter::post, this, _1));
}
LLEventMatching::LLEventMatching(const LLSD& pattern):
LLEventFilter("matching"),
mPattern(pattern)
{
}
LLEventMatching::LLEventMatching(LLEventPump& source, const LLSD& pattern):
LLEventFilter(source, "matching"),
mPattern(pattern)
{
}
bool LLEventMatching::post(const LLSD& event)
{
if (! llsd_matches(mPattern, event).empty())
return false;
return LLEventStream::post(event);
}
LLEventTimeoutBase::LLEventTimeoutBase():
LLEventFilter("timeout")
{
}
LLEventTimeoutBase::LLEventTimeoutBase(LLEventPump& source):
LLEventFilter(source, "timeout")
{
}
void LLEventTimeoutBase::actionAfter(F32 seconds, const Action& action)
{
setCountdown(seconds);
mAction = action;
if (! mMainloop.connected())
{
LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
mMainloop = mainloop.listen(getName(), boost::bind(&LLEventTimeoutBase::tick, this, _1));
}
}
class ErrorAfter
{
public:
ErrorAfter(const std::string& message): mMessage(message) {}
void operator()()
{
LL_ERRS("LLEventTimeout") << mMessage << LL_ENDL;
}
private:
std::string mMessage;
};
void LLEventTimeoutBase::errorAfter(F32 seconds, const std::string& message)
{
actionAfter(seconds, ErrorAfter(message));
}
class EventAfter
{
public:
EventAfter(LLEventPump& pump, const LLSD& event):
mPump(pump),
mEvent(event)
{}
void operator()()
{
mPump.post(mEvent);
}
private:
LLEventPump& mPump;
LLSD mEvent;
};
void LLEventTimeoutBase::eventAfter(F32 seconds, const LLSD& event)
{
actionAfter(seconds, EventAfter(*this, event));
}
bool LLEventTimeoutBase::post(const LLSD& event)
{
cancel();
return LLEventStream::post(event);
}
void LLEventTimeoutBase::cancel()
{
mMainloop.disconnect();
}
bool LLEventTimeoutBase::tick(const LLSD&)
{
if (countdownElapsed())
{
cancel();
mAction();
}
return false; // show event to other listeners
}
LLEventTimeout::LLEventTimeout() {}
LLEventTimeout::LLEventTimeout(LLEventPump& source):
LLEventTimeoutBase(source)
{
}
void LLEventTimeout::setCountdown(F32 seconds)
{
mTimer.setTimerExpirySec(seconds);
}
bool LLEventTimeout::countdownElapsed() const
{
return mTimer.hasExpired();
}

View File

@ -0,0 +1,186 @@
/**
* @file lleventfilter.h
* @author Nat Goodspeed
* @date 2009-03-05
* @brief Define LLEventFilter: LLEventStream subclass with conditions
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
* Copyright (c) 2009, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_LLEVENTFILTER_H)
#define LL_LLEVENTFILTER_H
#include "llevents.h"
#include "stdtypes.h"
#include "lltimer.h"
#include <boost/function.hpp>
/**
* Generic base class
*/
class LL_COMMON_API LLEventFilter: public LLEventStream
{
public:
/// construct a standalone LLEventFilter
LLEventFilter(const std::string& name="filter", bool tweak=true):
LLEventStream(name, tweak)
{}
/// construct LLEventFilter and connect it to the specified LLEventPump
LLEventFilter(LLEventPump& source, const std::string& name="filter", bool tweak=true);
/// Post an event to all listeners
virtual bool post(const LLSD& event) = 0;
};
/**
* Pass through only events matching a specified pattern
*/
class LLEventMatching: public LLEventFilter
{
public:
/// Pass an LLSD map with keys and values the incoming event must match
LLEventMatching(const LLSD& pattern);
/// instantiate and connect
LLEventMatching(LLEventPump& source, const LLSD& pattern);
/// Only pass through events matching the pattern
virtual bool post(const LLSD& event);
private:
LLSD mPattern;
};
/**
* Wait for an event to be posted. If no such event arrives within a specified
* time, take a specified action. See LLEventTimeout for production
* implementation.
*
* @NOTE This is an abstract base class so that, for testing, we can use an
* alternate "timer" that doesn't actually consume real time.
*/
class LL_COMMON_API LLEventTimeoutBase: public LLEventFilter
{
public:
/// construct standalone
LLEventTimeoutBase();
/// construct and connect
LLEventTimeoutBase(LLEventPump& source);
/// Callable, can be constructed with boost::bind()
typedef boost::function<void()> Action;
/**
* Start countdown timer for the specified number of @a seconds. Forward
* all events. If any event arrives before timer expires, cancel timer. If
* no event arrives before timer expires, take specified @a action.
*
* This is a one-shot timer. Once it has either expired or been canceled,
* it is inert until another call to actionAfter().
*
* Calling actionAfter() while an existing timer is running cheaply
* replaces that original timer. Thus, a valid use case is to detect
* idleness of some event source by calling actionAfter() on each new
* event. A rapid sequence of events will keep the timer from expiring;
* the first gap in events longer than the specified timer will fire the
* specified Action.
*
* Any post() call cancels the timer. To be satisfied with only a
* particular event, chain on an LLEventMatching that only passes such
* events:
*
* @code
* event ultimate
* source ---> LLEventMatching ---> LLEventTimeout ---> listener
* @endcode
*
* @NOTE
* The implementation relies on frequent events on the LLEventPump named
* "mainloop".
*/
void actionAfter(F32 seconds, const Action& action);
/**
* Like actionAfter(), but where the desired Action is LL_ERRS
* termination. Pass the timeout time and the desired LL_ERRS @a message.
*
* This method is useful when, for instance, some async API guarantees an
* event, whether success or failure, within a stated time window.
* Instantiate an LLEventTimeout listening to that API and call
* errorAfter() on each async request with a timeout comfortably longer
* than the API's time guarantee (much longer than the anticipated
* "mainloop" granularity).
*
* Then if the async API breaks its promise, the program terminates with
* the specified LL_ERRS @a message. The client of the async API can
* therefore assume the guarantee is upheld.
*
* @NOTE
* errorAfter() is implemented in terms of actionAfter(), so all remarks
* about calling actionAfter() also apply to errorAfter().
*/
void errorAfter(F32 seconds, const std::string& message);
/**
* Like actionAfter(), but where the desired Action is a particular event
* for all listeners. Pass the timeout time and the desired @a event data.
*
* Suppose the timeout should only be satisfied by a particular event, but
* the ultimate listener must see all other incoming events as well, plus
* the timeout @a event if any:
*
* @code
* some LLEventMatching LLEventMatching
* event ---> for particular ---> LLEventTimeout ---> for timeout
* source event event \
* \ \ ultimate
* `-----------------------------------------------------> listener
* @endcode
*
* Since a given listener can listen on more than one LLEventPump, we can
* set things up so it sees the set union of events from LLEventTimeout
* and the original event source. However, as LLEventTimeout passes
* through all incoming events, the "particular event" that satisfies the
* left LLEventMatching would reach the ultimate listener twice. So we add
* an LLEventMatching that only passes timeout events.
*
* @NOTE
* eventAfter() is implemented in terms of actionAfter(), so all remarks
* about calling actionAfter() also apply to eventAfter().
*/
void eventAfter(F32 seconds, const LLSD& event);
/// Pass event through, canceling the countdown timer
virtual bool post(const LLSD& event);
/// Cancel timer without event
void cancel();
protected:
virtual void setCountdown(F32 seconds) = 0;
virtual bool countdownElapsed() const = 0;
private:
bool tick(const LLSD&);
LLBoundListener mMainloop;
Action mAction;
};
/// Production implementation of LLEventTimoutBase
class LL_COMMON_API LLEventTimeout: public LLEventTimeoutBase
{
public:
LLEventTimeout();
LLEventTimeout(LLEventPump& source);
protected:
virtual void setCountdown(F32 seconds);
virtual bool countdownElapsed() const;
private:
LLTimer mTimer;
};
#endif /* ! defined(LL_LLEVENTFILTER_H) */

View File

@ -38,6 +38,9 @@
#pragma warning (pop)
#endif
// other Linden headers
#include "stringize.h"
#include "llerror.h"
#include "llsdutil.h"
/*****************************************************************************
* queue_names: specify LLEventPump names that should be instantiated as
@ -56,14 +59,12 @@ const char* queue_names[] =
/*****************************************************************************
* If there's a "mainloop" pump, listen on that to flush all LLEventQueues
*****************************************************************************/
struct RegisterFlush
struct RegisterFlush : public LLEventTrackable
{
RegisterFlush():
pumps(LLEventPumps::instance()),
mainloop(pumps.obtain("mainloop")),
name("flushLLEventQueues")
pumps(LLEventPumps::instance())
{
mainloop.listen(name, boost::bind(&RegisterFlush::flush, this, _1));
pumps.obtain("mainloop").listen("flushLLEventQueues", boost::bind(&RegisterFlush::flush, this, _1));
}
bool flush(const LLSD&)
{
@ -72,11 +73,9 @@ struct RegisterFlush
}
~RegisterFlush()
{
mainloop.stopListening(name);
// LLEventTrackable handles stopListening for us.
}
LLEventPumps& pumps;
LLEventPump& mainloop;
const std::string name;
};
static RegisterFlush registerFlush;
@ -256,6 +255,12 @@ LLEventPump::~LLEventPump()
// static data member
const LLEventPump::NameList LLEventPump::empty;
std::string LLEventPump::inventName(const std::string& pfx)
{
static long suffix = 0;
return STRINGIZE(pfx << suffix++);
}
LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventListener& listener,
const NameList& after,
const NameList& before)
@ -499,3 +504,26 @@ bool LLListenerOrPumpName::operator()(const LLSD& event) const
}
return (*mListener)(event);
}
void LLReqID::stamp(LLSD& response) const
{
if (! (response.isUndefined() || response.isMap()))
{
// If 'response' was previously completely empty, it's okay to
// turn it into a map. If it was already a map, then it should be
// okay to add a key. But if it was anything else (e.g. a scalar),
// assigning a ["reqid"] key will DISCARD the previous value,
// replacing it with a map. That would be Bad.
LL_INFOS("LLReqID") << "stamp(" << mReqid << ") leaving non-map response unmodified: "
<< response << LL_ENDL;
return;
}
LLSD oldReqid(response["reqid"]);
if (! (oldReqid.isUndefined() || llsd_equals(oldReqid, mReqid)))
{
LL_INFOS("LLReqID") << "stamp(" << mReqid << ") preserving existing [\"reqid\"] value "
<< oldReqid << " in response: " << response << LL_ENDL;
return;
}
response["reqid"] = mReqid;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,244 +1,244 @@
/**
* @file llfasttimer.h
* @brief Declaration of a fast timer.
*
* $LicenseInfo:firstyear=2004&license=viewergpl$
*
* Copyright (c) 2004-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_FASTTIMER_H
#define LL_FASTTIMER_H
#include "llinstancetracker.h"
#define FAST_TIMER_ON 1
U64 get_cpu_clock_count();
class LLMutex;
#include <queue>
#include "llsd.h"
class LLFastTimer
{
public:
// stores a "named" timer instance to be reused via multiple LLFastTimer stack instances
class NamedTimer
: public LLInstanceTracker<NamedTimer>
{
public:
~NamedTimer();
enum { HISTORY_NUM = 60 };
const std::string& getName() { return mName; }
NamedTimer* getParent() { return mParent; }
void setParent(NamedTimer* parent);
S32 getDepth();
std::string getToolTip(S32 history_index = -1);
typedef std::vector<NamedTimer*>::const_iterator child_const_iter;
child_const_iter beginChildren();
child_const_iter endChildren();
std::vector<NamedTimer*>& getChildren();
void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
bool getCollapsed() const { return mCollapsed; }
U64 getCountAverage() const { return mCountAverage; }
U64 getCallAverage() const { return mCallAverage; }
U64 getHistoricalCount(S32 history_index = 0) const;
U64 getHistoricalCalls(S32 history_index = 0) const;
static NamedTimer& getRootNamedTimer();
struct FrameState
{
FrameState(NamedTimer* timerp);
U64 mSelfTimeCounter;
U64 mLastStartTime; // most recent time when this timer was started
U32 mCalls;
FrameState* mParent; // info for caller timer
FrameState* mLastCaller; // used to bootstrap tree construction
NamedTimer* mTimer;
U16 mActiveCount; // number of timers with this ID active on stack
bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame
};
FrameState& getFrameStateFast() const
{
return (*sTimerInfos)[mFrameStateIndex];
}
S32 getFrameStateIndex() const { return mFrameStateIndex; }
FrameState& getFrameState() const;
private:
friend class LLFastTimer;
friend class NamedTimerFactory;
//
// methods
//
NamedTimer(const std::string& name);
// recursive call to gather total time from children
static void accumulateTimings();
// called once per frame by LLFastTimer
static void processFrame();
static void buildHierarchy();
static void resetFrame();
static void reset();
typedef std::vector<FrameState> info_list_t;
static info_list_t& getFrameStateList();
static void createFrameStateList(); // must call before any call to getFrameStateList()
//
// members
//
S32 mFrameStateIndex;
std::string mName;
U64 mTotalTimeCounter;
U64 mCountAverage;
U64 mCallAverage;
U64* mCountHistory;
U64* mCallHistory;
// tree structure
NamedTimer* mParent; // NamedTimer of caller(parent)
std::vector<NamedTimer*> mChildren;
bool mCollapsed; // don't show children
bool mNeedsSorting; // sort children whenever child added
static info_list_t* sTimerInfos;
};
// used to statically declare a new named timer
class DeclareTimer
{
public:
DeclareTimer(const std::string& name, bool open);
DeclareTimer(const std::string& name);
// convertable to NamedTimer::FrameState for convenient usage of LLFastTimer(declared_timer)
operator NamedTimer::FrameState&() { return mNamedTimer.getFrameStateFast(); }
private:
NamedTimer& mNamedTimer;
};
public:
enum RootTimerMarker { ROOT };
static LLMutex* sLogLock;
static std::queue<LLSD> sLogQueue;
static BOOL sLog;
static BOOL sMetricLog;
LLFastTimer(RootTimerMarker);
LLFastTimer(NamedTimer::FrameState& timer)
: mFrameState(&timer)
{
#if FAST_TIMER_ON
NamedTimer::FrameState* frame_state = mFrameState;
frame_state->mLastStartTime = get_cpu_clock_count();
mStartSelfTime = frame_state->mLastStartTime;
frame_state->mActiveCount++;
frame_state->mCalls++;
// keep current parent as long as it is active when we are
frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0);
mLastTimer = sCurTimer;
sCurTimer = this;
#endif
}
~LLFastTimer()
{
#if FAST_TIMER_ON
NamedTimer::FrameState* frame_state = mFrameState;
U64 cur_time = get_cpu_clock_count();
frame_state->mSelfTimeCounter += cur_time - mStartSelfTime;
frame_state->mActiveCount--;
LLFastTimer* last_timer = mLastTimer;
sCurTimer = last_timer;
// store last caller to bootstrap tree creation
frame_state->mLastCaller = last_timer->mFrameState;
// we are only tracking self time, so subtract our total time delta from parents
U64 total_time = cur_time - frame_state->mLastStartTime;
last_timer->mStartSelfTime += total_time;
#endif
}
// call this once a frame to reset timers
static void nextFrame();
// call this to reset timer hierarchy, averages, etc.
static void reset();
static U64 countsPerSecond();
static S32 getLastFrameIndex() { return sLastFrameIndex; }
static S32 getCurFrameIndex() { return sCurFrameIndex; }
static void writeLog(std::ostream& os);
static const NamedTimer* getTimerByName(const std::string& name);
public:
static bool sPauseHistory;
static bool sResetHistory;
private:
typedef std::vector<LLFastTimer*> timer_stack_t;
static LLFastTimer* sCurTimer;
static S32 sCurFrameIndex;
static S32 sLastFrameIndex;
static F64 sCPUClockFrequency;
U64 mStartSelfTime; // start time + time of all child timers
NamedTimer::FrameState* mFrameState;
LLFastTimer* mLastTimer;
};
#endif // LL_LLFASTTIMER_H
/**
* @file llfasttimer.h
* @brief Declaration of a fast timer.
*
* $LicenseInfo:firstyear=2004&license=viewergpl$
*
* Copyright (c) 2004-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_FASTTIMER_H
#define LL_FASTTIMER_H
#include "llinstancetracker.h"
#define FAST_TIMER_ON 1
LL_COMMON_API U64 get_cpu_clock_count();
class LLMutex;
#include <queue>
#include "llsd.h"
class LL_COMMON_API LLFastTimer
{
public:
// stores a "named" timer instance to be reused via multiple LLFastTimer stack instances
class LL_COMMON_API NamedTimer
: public LLInstanceTracker<NamedTimer>
{
public:
~NamedTimer();
enum { HISTORY_NUM = 60 };
const std::string& getName() { return mName; }
NamedTimer* getParent() { return mParent; }
void setParent(NamedTimer* parent);
S32 getDepth();
std::string getToolTip(S32 history_index = -1);
typedef std::vector<NamedTimer*>::const_iterator child_const_iter;
child_const_iter beginChildren();
child_const_iter endChildren();
std::vector<NamedTimer*>& getChildren();
void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
bool getCollapsed() const { return mCollapsed; }
U64 getCountAverage() const { return mCountAverage; }
U64 getCallAverage() const { return mCallAverage; }
U64 getHistoricalCount(S32 history_index = 0) const;
U64 getHistoricalCalls(S32 history_index = 0) const;
static NamedTimer& getRootNamedTimer();
struct FrameState
{
FrameState(NamedTimer* timerp);
U64 mSelfTimeCounter;
U64 mLastStartTime; // most recent time when this timer was started
U32 mCalls;
FrameState* mParent; // info for caller timer
FrameState* mLastCaller; // used to bootstrap tree construction
NamedTimer* mTimer;
U16 mActiveCount; // number of timers with this ID active on stack
bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame
};
FrameState& getFrameStateFast() const
{
return (*sTimerInfos)[mFrameStateIndex];
}
S32 getFrameStateIndex() const { return mFrameStateIndex; }
FrameState& getFrameState() const;
private:
friend class LLFastTimer;
friend class NamedTimerFactory;
//
// methods
//
NamedTimer(const std::string& name);
// recursive call to gather total time from children
static void accumulateTimings();
// called once per frame by LLFastTimer
static void processFrame();
static void buildHierarchy();
static void resetFrame();
static void reset();
typedef std::vector<FrameState> info_list_t;
static info_list_t& getFrameStateList();
static void createFrameStateList(); // must call before any call to getFrameStateList()
//
// members
//
S32 mFrameStateIndex;
std::string mName;
U64 mTotalTimeCounter;
U64 mCountAverage;
U64 mCallAverage;
U64* mCountHistory;
U64* mCallHistory;
// tree structure
NamedTimer* mParent; // NamedTimer of caller(parent)
std::vector<NamedTimer*> mChildren;
bool mCollapsed; // don't show children
bool mNeedsSorting; // sort children whenever child added
static info_list_t* sTimerInfos;
};
// used to statically declare a new named timer
class LL_COMMON_API DeclareTimer
{
public:
DeclareTimer(const std::string& name, bool open);
DeclareTimer(const std::string& name);
// convertable to NamedTimer::FrameState for convenient usage of LLFastTimer(declared_timer)
operator NamedTimer::FrameState&() { return mNamedTimer.getFrameStateFast(); }
private:
NamedTimer& mNamedTimer;
};
public:
enum RootTimerMarker { ROOT };
static LLMutex* sLogLock;
static std::queue<LLSD> sLogQueue;
static BOOL sLog;
static BOOL sMetricLog;
LLFastTimer(RootTimerMarker);
LLFastTimer(NamedTimer::FrameState& timer)
: mFrameState(&timer)
{
#if FAST_TIMER_ON
NamedTimer::FrameState* frame_state = mFrameState;
frame_state->mLastStartTime = get_cpu_clock_count();
mStartSelfTime = frame_state->mLastStartTime;
frame_state->mActiveCount++;
frame_state->mCalls++;
// keep current parent as long as it is active when we are
frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0);
mLastTimer = sCurTimer;
sCurTimer = this;
#endif
}
~LLFastTimer()
{
#if FAST_TIMER_ON
NamedTimer::FrameState* frame_state = mFrameState;
U64 cur_time = get_cpu_clock_count();
frame_state->mSelfTimeCounter += cur_time - mStartSelfTime;
frame_state->mActiveCount--;
LLFastTimer* last_timer = mLastTimer;
sCurTimer = last_timer;
// store last caller to bootstrap tree creation
frame_state->mLastCaller = last_timer->mFrameState;
// we are only tracking self time, so subtract our total time delta from parents
U64 total_time = cur_time - frame_state->mLastStartTime;
last_timer->mStartSelfTime += total_time;
#endif
}
// call this once a frame to reset timers
static void nextFrame();
// call this to reset timer hierarchy, averages, etc.
static void reset();
static U64 countsPerSecond();
static S32 getLastFrameIndex() { return sLastFrameIndex; }
static S32 getCurFrameIndex() { return sCurFrameIndex; }
static void writeLog(std::ostream& os);
static const NamedTimer* getTimerByName(const std::string& name);
public:
static bool sPauseHistory;
static bool sResetHistory;
private:
typedef std::vector<LLFastTimer*> timer_stack_t;
static LLFastTimer* sCurTimer;
static S32 sCurFrameIndex;
static S32 sLastFrameIndex;
static F64 sCPUClockFrequency;
U64 mStartSelfTime; // start time + time of all child timers
NamedTimer::FrameState* mFrameState;
LLFastTimer* mLastTimer;
};
#endif // LL_LLFASTTIMER_H

View File

@ -70,7 +70,7 @@ typedef struct stat llstat;
#include "llstring.h" // safe char* -> std::string conversion
class LLFile
class LL_COMMON_API LLFile
{
public:
// All these functions take UTF8 path/filenames.
@ -95,7 +95,7 @@ public:
#if USE_LLFILESTREAMS
class llifstream : public std::basic_istream < char , std::char_traits < char > >
class LL_COMMON_API llifstream : public std::basic_istream < char , std::char_traits < char > >
{
// input stream associated with a C stream
public:
@ -136,7 +136,7 @@ private:
};
class llofstream : public std::basic_ostream< char , std::char_traits < char > >
class LL_COMMON_API llofstream : public std::basic_ostream< char , std::char_traits < char > >
{
public:
typedef std::basic_ostream< char , std::char_traits < char > > _Myt;
@ -185,7 +185,7 @@ private:
//#define llifstream std::ifstream
//#define llofstream std::ofstream
class llifstream : public std::ifstream
class LL_COMMON_API llifstream : public std::ifstream
{
public:
llifstream() : std::ifstream()
@ -203,7 +203,7 @@ public:
};
class llofstream : public std::ofstream
class LL_COMMON_API llofstream : public std::ofstream
{
public:
llofstream() : std::ofstream()
@ -231,7 +231,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

@ -59,8 +59,8 @@ typedef enum {
/* This allocates/fills in a FL_Locale structure with pointers to
strings (which should be treated as static), or NULL for inappropriate /
undetected fields. */
FL_Success FL_FindLocale(FL_Locale **locale, FL_Domain domain);
LL_COMMON_API FL_Success FL_FindLocale(FL_Locale **locale, FL_Domain domain);
/* This should be used to free the struct written by FL_FindLocale */
void FL_FreeLocale(FL_Locale **locale);
LL_COMMON_API void FL_FreeLocale(FL_Locale **locale);
#endif /*__findlocale_h_*/

View File

@ -41,7 +41,7 @@
// Fixed size buffer for console output and other things.
class LLFixedBuffer
class LL_COMMON_API LLFixedBuffer
{
public:
LLFixedBuffer(const U32 max_lines = 20);

View File

@ -40,6 +40,6 @@
// *NOTE: buffer limited to 1024, (but vsnprintf prevents overrun)
// should perhaps be replaced with boost::format.
std::string llformat(const char *fmt, ...);
std::string LL_COMMON_API llformat(const char *fmt, ...);
#endif // LL_LLFORMAT_H

View File

@ -43,7 +43,7 @@
#include "lltimer.h"
#include "timing.h"
class LLFrameTimer
class LL_COMMON_API LLFrameTimer
{
public:
LLFrameTimer() : mStartTime( sFrameTime ), mExpiry(0), mStarted(TRUE) {}

View File

@ -40,7 +40,7 @@
// Note: Win32 does not support the heartbeat/smackdown system;
// heartbeat-delivery turns into a no-op there.
class LLHeartbeat
class LL_COMMON_API LLHeartbeat
{
public:
// secs_between_heartbeat: after a heartbeat is successfully delivered,

View File

@ -45,7 +45,7 @@
* loop. The traditional name for it is live_config. Be sure to call
* <code>live_config.checkAndReload()</code> periodically.
*/
class LLLiveAppConfig : public LLLiveFile
class LL_COMMON_API LLLiveAppConfig : public LLLiveFile
{
public:

View File

@ -36,7 +36,7 @@
extern const F32 DEFAULT_CONFIG_FILE_REFRESH;
class LLLiveFile
class LL_COMMON_API LLLiveFile
{
public:
LLLiveFile(const std::string& filename, const F32 refresh_period = 5.f);

View File

@ -41,7 +41,7 @@ class LLLogImpl;
class LLApp;
class LLSD;
class LLLog
class LL_COMMON_API LLLog
{
public:
LLLog(LLApp* app);

View File

@ -80,7 +80,7 @@ const int MD5RAW_BYTES = 16;
const int MD5HEX_STR_SIZE = 33; // char hex[MD5HEX_STR_SIZE]; with null
const int MD5HEX_STR_BYTES = 32; // message system fixed size
class LLMD5 {
class LL_COMMON_API LLMD5 {
// first, some types:
typedef unsigned int uint4; // assumes integer is 4 words long
typedef unsigned short int uint2; // assumes short integer is 2 words long

View File

@ -1,65 +1,65 @@
/**
* @file llmemory.h
* @brief Memory allocation/deallocation header-stuff goes here.
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LLMEMORY_H
#define LLMEMORY_H
extern S32 gTotalDAlloc;
extern S32 gTotalDAUse;
extern S32 gDACount;
extern void* ll_allocate (size_t size);
extern void ll_release (void *p);
class LLMemory
{
public:
static void initClass();
static void cleanupClass();
static void freeReserve();
// Return the resident set size of the current process, in bytes.
// Return value is zero if not known.
static U64 getCurrentRSS();
private:
static char* reserveMem;
};
// LLRefCount moved to llrefcount.h
// LLPointer moved to llpointer.h
// LLSafeHandle moved to llsafehandle.h
// LLSingleton moved to llsingleton.h
#endif
/**
* @file llmemory.h
* @brief Memory allocation/deallocation header-stuff goes here.
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LLMEMORY_H
#define LLMEMORY_H
extern S32 gTotalDAlloc;
extern S32 gTotalDAUse;
extern S32 gDACount;
extern void* ll_allocate (size_t size);
extern void ll_release (void *p);
class LL_COMMON_API LLMemory
{
public:
static void initClass();
static void cleanupClass();
static void freeReserve();
// Return the resident set size of the current process, in bytes.
// Return value is zero if not known.
static U64 getCurrentRSS();
private:
static char* reserveMem;
};
// LLRefCount moved to llrefcount.h
// LLPointer moved to llpointer.h
// LLSafeHandle moved to llsafehandle.h
// LLSingleton moved to llsingleton.h
#endif

View File

@ -52,7 +52,7 @@
* be careful to always pass in a valid memory location that exists
* for at least as long as this streambuf.
*/
class LLMemoryStreamBuf : public std::streambuf
class LL_COMMON_API LLMemoryStreamBuf : public std::streambuf
{
public:
LLMemoryStreamBuf(const U8* start, S32 length);
@ -74,7 +74,7 @@ protected:
* be careful to always pass in a valid memory location that exists
* for at least as long as this streambuf.
*/
class LLMemoryStream : public std::istream
class LL_COMMON_API LLMemoryStream : public std::istream
{
public:
LLMemoryStream(const U8* start, S32 length);

View File

@ -1,248 +1,248 @@
/**
* @file llmemtype.h
* @brief Runtime memory usage debugging utilities.
*
* $LicenseInfo:firstyear=2005&license=viewergpl$
*
* Copyright (c) 2005-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_MEMTYPE_H
#define LL_MEMTYPE_H
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#include "linden_common.h"
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// WARNING: Never commit with MEM_TRACK_MEM == 1
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#define MEM_TRACK_MEM (0 && LL_WINDOWS)
#include <vector>
#define MEM_TYPE_NEW(T)
class LLMemType
{
public:
// class we'll initialize all instances of as
// static members of MemType. Then use
// to construct any new mem type.
class DeclareMemType
{
public:
DeclareMemType(char const * st);
~DeclareMemType();
S32 mID;
char const * mName;
// array so we can map an index ID to Name
static std::vector<char const *> mNameList;
};
LLMemType(DeclareMemType& dt);
~LLMemType();
static char const * getNameFromID(S32 id);
static DeclareMemType MTYPE_INIT;
static DeclareMemType MTYPE_STARTUP;
static DeclareMemType MTYPE_MAIN;
static DeclareMemType MTYPE_FRAME;
static DeclareMemType MTYPE_GATHER_INPUT;
static DeclareMemType MTYPE_JOY_KEY;
static DeclareMemType MTYPE_IDLE;
static DeclareMemType MTYPE_IDLE_PUMP;
static DeclareMemType MTYPE_IDLE_NETWORK;
static DeclareMemType MTYPE_IDLE_UPDATE_REGIONS;
static DeclareMemType MTYPE_IDLE_UPDATE_VIEWER_REGION;
static DeclareMemType MTYPE_IDLE_UPDATE_SURFACE;
static DeclareMemType MTYPE_IDLE_UPDATE_PARCEL_OVERLAY;
static DeclareMemType MTYPE_IDLE_AUDIO;
static DeclareMemType MTYPE_CACHE_PROCESS_PENDING;
static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_ASKS;
static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_REPLIES;
static DeclareMemType MTYPE_MESSAGE_CHECK_ALL;
static DeclareMemType MTYPE_MESSAGE_PROCESS_ACKS;
static DeclareMemType MTYPE_RENDER;
static DeclareMemType MTYPE_SLEEP;
static DeclareMemType MTYPE_NETWORK;
static DeclareMemType MTYPE_PHYSICS;
static DeclareMemType MTYPE_INTERESTLIST;
static DeclareMemType MTYPE_IMAGEBASE;
static DeclareMemType MTYPE_IMAGERAW;
static DeclareMemType MTYPE_IMAGEFORMATTED;
static DeclareMemType MTYPE_APPFMTIMAGE;
static DeclareMemType MTYPE_APPRAWIMAGE;
static DeclareMemType MTYPE_APPAUXRAWIMAGE;
static DeclareMemType MTYPE_DRAWABLE;
static DeclareMemType MTYPE_OBJECT;
static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE;
static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE_CORE;
static DeclareMemType MTYPE_DISPLAY;
static DeclareMemType MTYPE_DISPLAY_UPDATE;
static DeclareMemType MTYPE_DISPLAY_UPDATE_CAMERA;
static DeclareMemType MTYPE_DISPLAY_UPDATE_GEOM;
static DeclareMemType MTYPE_DISPLAY_SWAP;
static DeclareMemType MTYPE_DISPLAY_UPDATE_HUD;
static DeclareMemType MTYPE_DISPLAY_GEN_REFLECTION;
static DeclareMemType MTYPE_DISPLAY_IMAGE_UPDATE;
static DeclareMemType MTYPE_DISPLAY_STATE_SORT;
static DeclareMemType MTYPE_DISPLAY_SKY;
static DeclareMemType MTYPE_DISPLAY_RENDER_GEOM;
static DeclareMemType MTYPE_DISPLAY_RENDER_FLUSH;
static DeclareMemType MTYPE_DISPLAY_RENDER_UI;
static DeclareMemType MTYPE_DISPLAY_RENDER_ATTACHMENTS;
static DeclareMemType MTYPE_VERTEX_DATA;
static DeclareMemType MTYPE_VERTEX_CONSTRUCTOR;
static DeclareMemType MTYPE_VERTEX_DESTRUCTOR;
static DeclareMemType MTYPE_VERTEX_CREATE_VERTICES;
static DeclareMemType MTYPE_VERTEX_CREATE_INDICES;
static DeclareMemType MTYPE_VERTEX_DESTROY_BUFFER;
static DeclareMemType MTYPE_VERTEX_DESTROY_INDICES;
static DeclareMemType MTYPE_VERTEX_UPDATE_VERTS;
static DeclareMemType MTYPE_VERTEX_UPDATE_INDICES;
static DeclareMemType MTYPE_VERTEX_ALLOCATE_BUFFER;
static DeclareMemType MTYPE_VERTEX_RESIZE_BUFFER;
static DeclareMemType MTYPE_VERTEX_MAP_BUFFER;
static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_VERTICES;
static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_INDICES;
static DeclareMemType MTYPE_VERTEX_UNMAP_BUFFER;
static DeclareMemType MTYPE_VERTEX_SET_STRIDE;
static DeclareMemType MTYPE_VERTEX_SET_BUFFER;
static DeclareMemType MTYPE_VERTEX_SETUP_VERTEX_BUFFER;
static DeclareMemType MTYPE_VERTEX_CLEANUP_CLASS;
static DeclareMemType MTYPE_SPACE_PARTITION;
static DeclareMemType MTYPE_PIPELINE;
static DeclareMemType MTYPE_PIPELINE_INIT;
static DeclareMemType MTYPE_PIPELINE_CREATE_BUFFERS;
static DeclareMemType MTYPE_PIPELINE_RESTORE_GL;
static DeclareMemType MTYPE_PIPELINE_UNLOAD_SHADERS;
static DeclareMemType MTYPE_PIPELINE_LIGHTING_DETAIL;
static DeclareMemType MTYPE_PIPELINE_GET_POOL_TYPE;
static DeclareMemType MTYPE_PIPELINE_ADD_POOL;
static DeclareMemType MTYPE_PIPELINE_ALLOCATE_DRAWABLE;
static DeclareMemType MTYPE_PIPELINE_ADD_OBJECT;
static DeclareMemType MTYPE_PIPELINE_CREATE_OBJECTS;
static DeclareMemType MTYPE_PIPELINE_UPDATE_MOVE;
static DeclareMemType MTYPE_PIPELINE_UPDATE_GEOM;
static DeclareMemType MTYPE_PIPELINE_MARK_VISIBLE;
static DeclareMemType MTYPE_PIPELINE_MARK_MOVED;
static DeclareMemType MTYPE_PIPELINE_MARK_SHIFT;
static DeclareMemType MTYPE_PIPELINE_SHIFT_OBJECTS;
static DeclareMemType MTYPE_PIPELINE_MARK_TEXTURED;
static DeclareMemType MTYPE_PIPELINE_MARK_REBUILD;
static DeclareMemType MTYPE_PIPELINE_UPDATE_CULL;
static DeclareMemType MTYPE_PIPELINE_STATE_SORT;
static DeclareMemType MTYPE_PIPELINE_POST_SORT;
static DeclareMemType MTYPE_PIPELINE_RENDER_HUD_ELS;
static DeclareMemType MTYPE_PIPELINE_RENDER_HL;
static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM;
static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED;
static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_POST_DEF;
static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_SHADOW;
static DeclareMemType MTYPE_PIPELINE_RENDER_SELECT;
static DeclareMemType MTYPE_PIPELINE_REBUILD_POOLS;
static DeclareMemType MTYPE_PIPELINE_QUICK_LOOKUP;
static DeclareMemType MTYPE_PIPELINE_RENDER_OBJECTS;
static DeclareMemType MTYPE_PIPELINE_GENERATE_IMPOSTOR;
static DeclareMemType MTYPE_PIPELINE_RENDER_BLOOM;
static DeclareMemType MTYPE_UPKEEP_POOLS;
static DeclareMemType MTYPE_AVATAR;
static DeclareMemType MTYPE_AVATAR_MESH;
static DeclareMemType MTYPE_PARTICLES;
static DeclareMemType MTYPE_REGIONS;
static DeclareMemType MTYPE_INVENTORY;
static DeclareMemType MTYPE_INVENTORY_DRAW;
static DeclareMemType MTYPE_INVENTORY_BUILD_NEW_VIEWS;
static DeclareMemType MTYPE_INVENTORY_DO_FOLDER;
static DeclareMemType MTYPE_INVENTORY_POST_BUILD;
static DeclareMemType MTYPE_INVENTORY_FROM_XML;
static DeclareMemType MTYPE_INVENTORY_CREATE_NEW_ITEM;
static DeclareMemType MTYPE_INVENTORY_VIEW_INIT;
static DeclareMemType MTYPE_INVENTORY_VIEW_SHOW;
static DeclareMemType MTYPE_INVENTORY_VIEW_TOGGLE;
static DeclareMemType MTYPE_ANIMATION;
static DeclareMemType MTYPE_VOLUME;
static DeclareMemType MTYPE_PRIMITIVE;
static DeclareMemType MTYPE_SCRIPT;
static DeclareMemType MTYPE_SCRIPT_RUN;
static DeclareMemType MTYPE_SCRIPT_BYTECODE;
static DeclareMemType MTYPE_IO_PUMP;
static DeclareMemType MTYPE_IO_TCP;
static DeclareMemType MTYPE_IO_BUFFER;
static DeclareMemType MTYPE_IO_HTTP_SERVER;
static DeclareMemType MTYPE_IO_SD_SERVER;
static DeclareMemType MTYPE_IO_SD_CLIENT;
static DeclareMemType MTYPE_IO_URL_REQUEST;
static DeclareMemType MTYPE_DIRECTX_INIT;
static DeclareMemType MTYPE_TEMP1;
static DeclareMemType MTYPE_TEMP2;
static DeclareMemType MTYPE_TEMP3;
static DeclareMemType MTYPE_TEMP4;
static DeclareMemType MTYPE_TEMP5;
static DeclareMemType MTYPE_TEMP6;
static DeclareMemType MTYPE_TEMP7;
static DeclareMemType MTYPE_TEMP8;
static DeclareMemType MTYPE_TEMP9;
static DeclareMemType MTYPE_OTHER; // Special; used by display code
S32 mTypeIndex;
};
//----------------------------------------------------------------------------
#endif
/**
* @file llmemtype.h
* @brief Runtime memory usage debugging utilities.
*
* $LicenseInfo:firstyear=2005&license=viewergpl$
*
* Copyright (c) 2005-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_MEMTYPE_H
#define LL_MEMTYPE_H
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#include "linden_common.h"
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// WARNING: Never commit with MEM_TRACK_MEM == 1
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#define MEM_TRACK_MEM (0 && LL_WINDOWS)
#include <vector>
#define MEM_TYPE_NEW(T)
class LL_COMMON_API LLMemType
{
public:
// class we'll initialize all instances of as
// static members of MemType. Then use
// to construct any new mem type.
class LL_COMMON_API DeclareMemType
{
public:
DeclareMemType(char const * st);
~DeclareMemType();
S32 mID;
char const * mName;
// array so we can map an index ID to Name
static std::vector<char const *> mNameList;
};
LLMemType(DeclareMemType& dt);
~LLMemType();
static char const * getNameFromID(S32 id);
static DeclareMemType MTYPE_INIT;
static DeclareMemType MTYPE_STARTUP;
static DeclareMemType MTYPE_MAIN;
static DeclareMemType MTYPE_FRAME;
static DeclareMemType MTYPE_GATHER_INPUT;
static DeclareMemType MTYPE_JOY_KEY;
static DeclareMemType MTYPE_IDLE;
static DeclareMemType MTYPE_IDLE_PUMP;
static DeclareMemType MTYPE_IDLE_NETWORK;
static DeclareMemType MTYPE_IDLE_UPDATE_REGIONS;
static DeclareMemType MTYPE_IDLE_UPDATE_VIEWER_REGION;
static DeclareMemType MTYPE_IDLE_UPDATE_SURFACE;
static DeclareMemType MTYPE_IDLE_UPDATE_PARCEL_OVERLAY;
static DeclareMemType MTYPE_IDLE_AUDIO;
static DeclareMemType MTYPE_CACHE_PROCESS_PENDING;
static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_ASKS;
static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_REPLIES;
static DeclareMemType MTYPE_MESSAGE_CHECK_ALL;
static DeclareMemType MTYPE_MESSAGE_PROCESS_ACKS;
static DeclareMemType MTYPE_RENDER;
static DeclareMemType MTYPE_SLEEP;
static DeclareMemType MTYPE_NETWORK;
static DeclareMemType MTYPE_PHYSICS;
static DeclareMemType MTYPE_INTERESTLIST;
static DeclareMemType MTYPE_IMAGEBASE;
static DeclareMemType MTYPE_IMAGERAW;
static DeclareMemType MTYPE_IMAGEFORMATTED;
static DeclareMemType MTYPE_APPFMTIMAGE;
static DeclareMemType MTYPE_APPRAWIMAGE;
static DeclareMemType MTYPE_APPAUXRAWIMAGE;
static DeclareMemType MTYPE_DRAWABLE;
static DeclareMemType MTYPE_OBJECT;
static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE;
static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE_CORE;
static DeclareMemType MTYPE_DISPLAY;
static DeclareMemType MTYPE_DISPLAY_UPDATE;
static DeclareMemType MTYPE_DISPLAY_UPDATE_CAMERA;
static DeclareMemType MTYPE_DISPLAY_UPDATE_GEOM;
static DeclareMemType MTYPE_DISPLAY_SWAP;
static DeclareMemType MTYPE_DISPLAY_UPDATE_HUD;
static DeclareMemType MTYPE_DISPLAY_GEN_REFLECTION;
static DeclareMemType MTYPE_DISPLAY_IMAGE_UPDATE;
static DeclareMemType MTYPE_DISPLAY_STATE_SORT;
static DeclareMemType MTYPE_DISPLAY_SKY;
static DeclareMemType MTYPE_DISPLAY_RENDER_GEOM;
static DeclareMemType MTYPE_DISPLAY_RENDER_FLUSH;
static DeclareMemType MTYPE_DISPLAY_RENDER_UI;
static DeclareMemType MTYPE_DISPLAY_RENDER_ATTACHMENTS;
static DeclareMemType MTYPE_VERTEX_DATA;
static DeclareMemType MTYPE_VERTEX_CONSTRUCTOR;
static DeclareMemType MTYPE_VERTEX_DESTRUCTOR;
static DeclareMemType MTYPE_VERTEX_CREATE_VERTICES;
static DeclareMemType MTYPE_VERTEX_CREATE_INDICES;
static DeclareMemType MTYPE_VERTEX_DESTROY_BUFFER;
static DeclareMemType MTYPE_VERTEX_DESTROY_INDICES;
static DeclareMemType MTYPE_VERTEX_UPDATE_VERTS;
static DeclareMemType MTYPE_VERTEX_UPDATE_INDICES;
static DeclareMemType MTYPE_VERTEX_ALLOCATE_BUFFER;
static DeclareMemType MTYPE_VERTEX_RESIZE_BUFFER;
static DeclareMemType MTYPE_VERTEX_MAP_BUFFER;
static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_VERTICES;
static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_INDICES;
static DeclareMemType MTYPE_VERTEX_UNMAP_BUFFER;
static DeclareMemType MTYPE_VERTEX_SET_STRIDE;
static DeclareMemType MTYPE_VERTEX_SET_BUFFER;
static DeclareMemType MTYPE_VERTEX_SETUP_VERTEX_BUFFER;
static DeclareMemType MTYPE_VERTEX_CLEANUP_CLASS;
static DeclareMemType MTYPE_SPACE_PARTITION;
static DeclareMemType MTYPE_PIPELINE;
static DeclareMemType MTYPE_PIPELINE_INIT;
static DeclareMemType MTYPE_PIPELINE_CREATE_BUFFERS;
static DeclareMemType MTYPE_PIPELINE_RESTORE_GL;
static DeclareMemType MTYPE_PIPELINE_UNLOAD_SHADERS;
static DeclareMemType MTYPE_PIPELINE_LIGHTING_DETAIL;
static DeclareMemType MTYPE_PIPELINE_GET_POOL_TYPE;
static DeclareMemType MTYPE_PIPELINE_ADD_POOL;
static DeclareMemType MTYPE_PIPELINE_ALLOCATE_DRAWABLE;
static DeclareMemType MTYPE_PIPELINE_ADD_OBJECT;
static DeclareMemType MTYPE_PIPELINE_CREATE_OBJECTS;
static DeclareMemType MTYPE_PIPELINE_UPDATE_MOVE;
static DeclareMemType MTYPE_PIPELINE_UPDATE_GEOM;
static DeclareMemType MTYPE_PIPELINE_MARK_VISIBLE;
static DeclareMemType MTYPE_PIPELINE_MARK_MOVED;
static DeclareMemType MTYPE_PIPELINE_MARK_SHIFT;
static DeclareMemType MTYPE_PIPELINE_SHIFT_OBJECTS;
static DeclareMemType MTYPE_PIPELINE_MARK_TEXTURED;
static DeclareMemType MTYPE_PIPELINE_MARK_REBUILD;
static DeclareMemType MTYPE_PIPELINE_UPDATE_CULL;
static DeclareMemType MTYPE_PIPELINE_STATE_SORT;
static DeclareMemType MTYPE_PIPELINE_POST_SORT;
static DeclareMemType MTYPE_PIPELINE_RENDER_HUD_ELS;
static DeclareMemType MTYPE_PIPELINE_RENDER_HL;
static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM;
static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED;
static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_POST_DEF;
static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_SHADOW;
static DeclareMemType MTYPE_PIPELINE_RENDER_SELECT;
static DeclareMemType MTYPE_PIPELINE_REBUILD_POOLS;
static DeclareMemType MTYPE_PIPELINE_QUICK_LOOKUP;
static DeclareMemType MTYPE_PIPELINE_RENDER_OBJECTS;
static DeclareMemType MTYPE_PIPELINE_GENERATE_IMPOSTOR;
static DeclareMemType MTYPE_PIPELINE_RENDER_BLOOM;
static DeclareMemType MTYPE_UPKEEP_POOLS;
static DeclareMemType MTYPE_AVATAR;
static DeclareMemType MTYPE_AVATAR_MESH;
static DeclareMemType MTYPE_PARTICLES;
static DeclareMemType MTYPE_REGIONS;
static DeclareMemType MTYPE_INVENTORY;
static DeclareMemType MTYPE_INVENTORY_DRAW;
static DeclareMemType MTYPE_INVENTORY_BUILD_NEW_VIEWS;
static DeclareMemType MTYPE_INVENTORY_DO_FOLDER;
static DeclareMemType MTYPE_INVENTORY_POST_BUILD;
static DeclareMemType MTYPE_INVENTORY_FROM_XML;
static DeclareMemType MTYPE_INVENTORY_CREATE_NEW_ITEM;
static DeclareMemType MTYPE_INVENTORY_VIEW_INIT;
static DeclareMemType MTYPE_INVENTORY_VIEW_SHOW;
static DeclareMemType MTYPE_INVENTORY_VIEW_TOGGLE;
static DeclareMemType MTYPE_ANIMATION;
static DeclareMemType MTYPE_VOLUME;
static DeclareMemType MTYPE_PRIMITIVE;
static DeclareMemType MTYPE_SCRIPT;
static DeclareMemType MTYPE_SCRIPT_RUN;
static DeclareMemType MTYPE_SCRIPT_BYTECODE;
static DeclareMemType MTYPE_IO_PUMP;
static DeclareMemType MTYPE_IO_TCP;
static DeclareMemType MTYPE_IO_BUFFER;
static DeclareMemType MTYPE_IO_HTTP_SERVER;
static DeclareMemType MTYPE_IO_SD_SERVER;
static DeclareMemType MTYPE_IO_SD_CLIENT;
static DeclareMemType MTYPE_IO_URL_REQUEST;
static DeclareMemType MTYPE_DIRECTX_INIT;
static DeclareMemType MTYPE_TEMP1;
static DeclareMemType MTYPE_TEMP2;
static DeclareMemType MTYPE_TEMP3;
static DeclareMemType MTYPE_TEMP4;
static DeclareMemType MTYPE_TEMP5;
static DeclareMemType MTYPE_TEMP6;
static DeclareMemType MTYPE_TEMP7;
static DeclareMemType MTYPE_TEMP8;
static DeclareMemType MTYPE_TEMP9;
static DeclareMemType MTYPE_OTHER; // Special; used by display code
S32 mTypeIndex;
};
//----------------------------------------------------------------------------
#endif

View File

@ -38,7 +38,7 @@
class LLMetricsImpl;
class LLSD;
class LLMetrics
class LL_COMMON_API LLMetrics
{
public:
LLMetrics();

View File

@ -35,7 +35,7 @@
#include "stdtypes.h"
class LLMortician
class LL_COMMON_API LLMortician
{
public:
LLMortician() { mIsDead = FALSE; }

View File

@ -1,140 +1,161 @@
/**
* @file llpreprocessor.h
* @brief This file should be included in all Linden Lab files and
* should only contain special preprocessor directives
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LLPREPROCESSOR_H
#define LLPREPROCESSOR_H
// Figure out endianness of platform
#ifdef LL_LINUX
#define __ENABLE_WSTRING
#include <endian.h>
#endif // LL_LINUX
#if LL_SOLARIS
# ifdef __sparc // Since we're talking Solaris 10 and up, only 64 bit is supported.
# define LL_BIG_ENDIAN 1
# define LL_SOLARIS_ALIGNED_CPU 1 // used to designate issues where SPARC alignment is addressed
# define LL_SOLARIS_NON_MESA_GL 1 // The SPARC GL does not provide a MESA-based GL API
# endif
# include <sys/isa_defs.h> // ensure we know which end is up
#endif // LL_SOLARIS
#if (defined(LL_WINDOWS) || (defined(LL_LINUX) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(LL_DARWIN) && defined(__LITTLE_ENDIAN__)) || (defined(LL_SOLARIS) && defined(__i386)))
#define LL_LITTLE_ENDIAN 1
#else
#define LL_BIG_ENDIAN 1
#endif
// Per-compiler switches
#ifdef __GNUC__
#define LL_FORCE_INLINE inline __attribute__((always_inline))
#else
#define LL_FORCE_INLINE __forceinline
#endif
// Figure out differences between compilers
#if defined(__GNUC__)
#define GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
#ifndef LL_GNUC
#define LL_GNUC 1
#endif
#elif defined(__MSVC_VER__) || defined(_MSC_VER)
#ifndef LL_MSVC
#define LL_MSVC 1
#endif
#if _MSC_VER < 1400
#define LL_MSVC7 //Visual C++ 2003 or earlier
#endif
#endif
// Deal with minor differences on Unixy OSes.
#if LL_DARWIN || LL_LINUX
// Different name, same functionality.
#define stricmp strcasecmp
#define strnicmp strncasecmp
// Not sure why this is different, but...
#ifndef MAX_PATH
#define MAX_PATH PATH_MAX
#endif // not MAX_PATH
#endif
// Deal with the differeneces on Windows
#if LL_MSVC
namespace snprintf_hack
{
int snprintf(char *str, size_t size, const char *format, ...);
}
// #define snprintf safe_snprintf /* Flawfinder: ignore */
using snprintf_hack::snprintf;
#endif // LL_MSVC
// Static linking with apr on windows needs to be declared.
#ifdef LL_WINDOWS
#ifndef APR_DECLARE_STATIC
#define APR_DECLARE_STATIC // For APR on Windows
#endif
#ifndef APU_DECLARE_STATIC
#define APU_DECLARE_STATIC // For APR util on Windows
#endif
#endif
#if defined(LL_WINDOWS)
#define BOOST_REGEX_NO_LIB 1
#define CURL_STATICLIB 1
#define XML_STATIC
#endif // LL_WINDOWS
// Deal with VC6 problems
#if LL_MSVC
#pragma warning( 3 : 4701 ) // "local variable used without being initialized" Treat this as level 3, not level 4.
#pragma warning( 3 : 4702 ) // "unreachable code" Treat this as level 3, not level 4.
#pragma warning( 3 : 4189 ) // "local variable initialized but not referenced" Treat this as level 3, not level 4.
//#pragma warning( 3 : 4018 ) // "signed/unsigned mismatch" Treat this as level 3, not level 4.
#pragma warning( 3 : 4263 ) // 'function' : member function does not override any base class virtual member function
#pragma warning( 3 : 4264 ) // "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden"
#pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual"
#pragma warning( 3 : 4266 ) // 'function' : no override available for virtual member function from base 'type'; function is hidden
#pragma warning( disable : 4284 ) // silly MS warning deep inside their <map> include file
#pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation.
#pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)
#pragma warning( disable : 4996 ) // warning: deprecated
#endif // LL_MSVC
#endif // not LL_LINDEN_PREPROCESSOR_H
/**
* @file llpreprocessor.h
* @brief This file should be included in all Linden Lab files and
* should only contain special preprocessor directives
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LLPREPROCESSOR_H
#define LLPREPROCESSOR_H
// Figure out endianness of platform
#ifdef LL_LINUX
#define __ENABLE_WSTRING
#include <endian.h>
#endif // LL_LINUX
#if LL_SOLARIS
# ifdef __sparc // Since we're talking Solaris 10 and up, only 64 bit is supported.
# define LL_BIG_ENDIAN 1
# define LL_SOLARIS_ALIGNED_CPU 1 // used to designate issues where SPARC alignment is addressed
# define LL_SOLARIS_NON_MESA_GL 1 // The SPARC GL does not provide a MESA-based GL API
# endif
# include <sys/isa_defs.h> // ensure we know which end is up
#endif // LL_SOLARIS
#if (defined(LL_WINDOWS) || (defined(LL_LINUX) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(LL_DARWIN) && defined(__LITTLE_ENDIAN__)) || (defined(LL_SOLARIS) && defined(__i386)))
#define LL_LITTLE_ENDIAN 1
#else
#define LL_BIG_ENDIAN 1
#endif
// Per-compiler switches
#ifdef __GNUC__
#define LL_FORCE_INLINE inline __attribute__((always_inline))
#else
#define LL_FORCE_INLINE __forceinline
#endif
// Figure out differences between compilers
#if defined(__GNUC__)
#define GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
#ifndef LL_GNUC
#define LL_GNUC 1
#endif
#elif defined(__MSVC_VER__) || defined(_MSC_VER)
#ifndef LL_MSVC
#define LL_MSVC 1
#endif
#if _MSC_VER < 1400
#define LL_MSVC7 //Visual C++ 2003 or earlier
#endif
#endif
// Deal with minor differences on Unixy OSes.
#if LL_DARWIN || LL_LINUX
// Different name, same functionality.
#define stricmp strcasecmp
#define strnicmp strncasecmp
// Not sure why this is different, but...
#ifndef MAX_PATH
#define MAX_PATH PATH_MAX
#endif // not MAX_PATH
#endif
// Static linking with apr on windows needs to be declared.
#if LL_WINDOWS && !LL_COMMON_LINK_SHARED
#ifndef APR_DECLARE_STATIC
#define APR_DECLARE_STATIC // For APR on Windows
#endif
#ifndef APU_DECLARE_STATIC
#define APU_DECLARE_STATIC // For APR util on Windows
#endif
#endif
#if defined(LL_WINDOWS)
#define BOOST_REGEX_NO_LIB 1
#define CURL_STATICLIB 1
#define XML_STATIC
#endif // LL_WINDOWS
// Deal with VC6 problems
#if LL_MSVC
#pragma warning( 3 : 4701 ) // "local variable used without being initialized" Treat this as level 3, not level 4.
#pragma warning( 3 : 4702 ) // "unreachable code" Treat this as level 3, not level 4.
#pragma warning( 3 : 4189 ) // "local variable initialized but not referenced" Treat this as level 3, not level 4.
//#pragma warning( 3 : 4018 ) // "signed/unsigned mismatch" Treat this as level 3, not level 4.
#pragma warning( 3 : 4263 ) // 'function' : member function does not override any base class virtual member function
#pragma warning( 3 : 4264 ) // "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden"
#pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual"
#pragma warning( 3 : 4266 ) // 'function' : no override available for virtual member function from base 'type'; function is hidden
#pragma warning( disable : 4284 ) // silly MS warning deep inside their <map> include file
#pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation.
#pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)
#pragma warning( disable : 4996 ) // warning: deprecated
// level 4 warnings that we need to disable:
#pragma warning (disable : 4100) // unreferenced formal parameter
#pragma warning (disable : 4127) // conditional expression is constant (e.g. while(1) )
#pragma warning (disable : 4244) // possible loss of data on conversions
#pragma warning (disable : 4396) // the inline specifier cannot be used when a friend declaration refers to a specialization of a function template
#pragma warning (disable : 4512) // assignment operator could not be generated
#pragma warning (disable : 4706) // assignment within conditional (even if((x = y)) )
#pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class
#pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class
#endif // LL_MSVC
#if LL_WINDOWS
#define LL_DLLEXPORT __declspec(dllexport)
#define LL_DLLIMPORT __declspec(dllimport)
#elif LL_LINUX
#define LL_DLLEXPORT __attribute__ ((visibility("default")))
#define LL_DLLIMPORT
#else
#define LL_DLLEXPORT
#define LL_DLLIMPORT
#endif // LL_WINDOWS
#if LL_COMMON_LINK_SHARED
# if LL_COMMON_BUILD
# define LL_COMMON_API LL_DLLEXPORT
# else //LL_COMMON_BUILD
# define LL_COMMON_API LL_DLLIMPORT
# endif //LL_COMMON_BUILD
#else // LL_COMMON_LINK_SHARED
# define LL_COMMON_API
#endif // LL_COMMON_LINK_SHARED
#endif // not LL_LINDEN_PREPROCESSOR_H

View File

@ -47,7 +47,7 @@
// Note: ~LLQueuedThread is O(N) N=# of queued threads, assumed to be small
// It is assumed that LLQueuedThreads are rarely created/destroyed.
class LLQueuedThread : public LLThread
class LL_COMMON_API LLQueuedThread : public LLThread
{
//------------------------------------------------------------------------
public:
@ -80,7 +80,7 @@ public:
//------------------------------------------------------------------------
public:
class QueuedRequest : public LLSimpleHashEntry<handle_t>
class LL_COMMON_API QueuedRequest : public LLSimpleHashEntry<handle_t>
{
friend class LLQueuedThread;
@ -148,6 +148,7 @@ protected:
}
};
//------------------------------------------------------------------------
public:

View File

@ -65,32 +65,32 @@
/**
*@brief Generate a float from [0, RAND_MAX).
*/
S32 ll_rand();
S32 LL_COMMON_API ll_rand();
/**
*@brief Generate a float from [0, val) or (val, 0].
*/
S32 ll_rand(S32 val);
S32 LL_COMMON_API ll_rand(S32 val);
/**
*@brief Generate a float from [0, 1.0).
*/
F32 ll_frand();
F32 LL_COMMON_API ll_frand();
/**
*@brief Generate a float from [0, val) or (val, 0].
*/
F32 ll_frand(F32 val);
F32 LL_COMMON_API ll_frand(F32 val);
/**
*@brief Generate a double from [0, 1.0).
*/
F64 ll_drand();
F64 LL_COMMON_API ll_drand();
/**
*@brief Generate a double from [0, val) or (val, 0].
*/
F64 ll_drand(F64 val);
F64 LL_COMMON_API ll_drand(F64 val);
/**
* @brief typedefs for good boost lagged fibonacci.

View File

@ -39,9 +39,9 @@
// see llthread.h for LLThreadSafeRefCount
//----------------------------------------------------------------------------
class LLRefCount
class LL_COMMON_API LLRefCount
{
protected:
private:
LLRefCount(const LLRefCount& other); // no implementation
private:
LLRefCount& operator=(const LLRefCount&); // no implementation

View File

@ -48,7 +48,7 @@ class LLRunnable;
* which are scheduled to run on a repeating or one time basis.
* @see LLRunnable
*/
class LLRunner
class LL_COMMON_API LLRunner
{
public:
/**
@ -149,7 +149,7 @@ protected:
* something useful.
* @see LLRunner
*/
class LLRunnable
class LL_COMMON_API LLRunnable
{
public:
LLRunnable();

View File

@ -89,7 +89,7 @@
@nosubgrouping
*/
class LLSD
class LL_COMMON_API LLSD
{
public:
LLSD(); ///< initially Undefined
@ -387,7 +387,7 @@ struct llsd_select_string : public std::unary_function<LLSD, LLSD::String>
}
};
std::ostream& operator<<(std::ostream& s, const LLSD& llsd);
LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd);
/** QUESTIONS & TO DOS
- Would Binary be more convenient as usigned char* buffer semantics?

View File

@ -44,7 +44,7 @@
* @class LLSDParser
* @brief Abstract base class for LLSD parsers.
*/
class LLSDParser : public LLRefCount
class LL_COMMON_API LLSDParser : public LLRefCount
{
protected:
/**
@ -221,7 +221,7 @@ protected:
* @class LLSDNotationParser
* @brief Parser which handles the original notation format for LLSD.
*/
class LLSDNotationParser : public LLSDParser
class LL_COMMON_API LLSDNotationParser : public LLSDParser
{
protected:
/**
@ -294,7 +294,7 @@ private:
* @class LLSDXMLParser
* @brief Parser which handles XML format LLSD.
*/
class LLSDXMLParser : public LLSDParser
class LL_COMMON_API LLSDXMLParser : public LLSDParser
{
protected:
/**
@ -342,7 +342,7 @@ private:
* @class LLSDBinaryParser
* @brief Parser which handles binary formatted LLSD.
*/
class LLSDBinaryParser : public LLSDParser
class LL_COMMON_API LLSDBinaryParser : public LLSDParser
{
protected:
/**
@ -407,7 +407,7 @@ private:
* @class LLSDFormatter
* @brief Abstract base class for formatting LLSD.
*/
class LLSDFormatter : public LLRefCount
class LL_COMMON_API LLSDFormatter : public LLRefCount
{
protected:
/**
@ -479,7 +479,7 @@ protected:
* @class LLSDNotationFormatter
* @brief Formatter which outputs the original notation format for LLSD.
*/
class LLSDNotationFormatter : public LLSDFormatter
class LL_COMMON_API LLSDNotationFormatter : public LLSDFormatter
{
protected:
/**
@ -520,7 +520,7 @@ public:
* @class LLSDXMLFormatter
* @brief Formatter which outputs the LLSD as XML.
*/
class LLSDXMLFormatter : public LLSDFormatter
class LL_COMMON_API LLSDXMLFormatter : public LLSDFormatter
{
protected:
/**
@ -588,7 +588,7 @@ protected:
* Map: '{' + 4 byte integer size every(key + value) + '}'<br>
* map keys are serialized as 'k' + 4 byte integer size + string
*/
class LLSDBinaryFormatter : public LLSDFormatter
class LL_COMMON_API LLSDBinaryFormatter : public LLSDFormatter
{
protected:
/**
@ -638,9 +638,14 @@ protected:
* params << "[{'version':i1}," << LLSDOStreamer<LLSDNotationFormatter>(sd)
* << "]";
* </code>
*
* *NOTE - formerly this class inherited from its template parameter Formatter,
* but all insnatiations passed in LLRefCount subclasses. This conflicted with
* the auto allocation intended for this class template (demonstrated in the
* example above). -brad
*/
template <class Formatter>
class LLSDOStreamer : public Formatter
class LLSDOStreamer
{
public:
/**
@ -661,7 +666,8 @@ public:
std::ostream& str,
const LLSDOStreamer<Formatter>& formatter)
{
formatter.format(formatter.mSD, str, formatter.mOptions);
LLPointer<Formatter> f = new Formatter;
f->format(formatter.mSD, str, formatter.mOptions);
return str;
}
@ -677,7 +683,7 @@ typedef LLSDOStreamer<LLSDXMLFormatter> LLSDXMLStreamer;
* @class LLSDSerialize
* @brief Serializer / deserializer for the various LLSD formats
*/
class LLSDSerialize
class LL_COMMON_API LLSDSerialize
{
public:
enum ELLSD_Serialize

View File

@ -46,6 +46,11 @@
#endif
#include "llsdserialize.h"
#include "stringize.h"
#include <map>
#include <set>
#include <boost/range.hpp>
// U32
LLSD ll_sd_from_U32(const U32 val)
@ -313,3 +318,353 @@ BOOL compare_llsd_with_template(
return TRUE;
}
/*****************************************************************************
* Helpers for llsd_matches()
*****************************************************************************/
// raw data used for LLSD::Type lookup
struct Data
{
LLSD::Type type;
const char* name;
} typedata[] =
{
#define def(type) { LLSD::type, #type + 4 }
def(TypeUndefined),
def(TypeBoolean),
def(TypeInteger),
def(TypeReal),
def(TypeString),
def(TypeUUID),
def(TypeDate),
def(TypeURI),
def(TypeBinary),
def(TypeMap),
def(TypeArray)
#undef def
};
// LLSD::Type lookup class into which we load the above static data
class TypeLookup
{
typedef std::map<LLSD::Type, std::string> MapType;
public:
TypeLookup()
{
for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di)
{
mMap[di->type] = di->name;
}
}
std::string lookup(LLSD::Type type) const
{
MapType::const_iterator found = mMap.find(type);
if (found != mMap.end())
{
return found->second;
}
return STRINGIZE("<unknown LLSD type " << type << ">");
}
private:
MapType mMap;
};
// static instance of the lookup class
static const TypeLookup sTypes;
// describe a mismatch; phrasing may want tweaking
const std::string op(" required instead of ");
// llsd_matches() wants to identify specifically where in a complex prototype
// structure the mismatch occurred. This entails passing a prefix string,
// empty for the top-level call. If the prototype contains an array of maps,
// and the mismatch occurs in the second map in a key 'foo', we want to
// decorate the returned string with: "[1]['foo']: etc." On the other hand, we
// want to omit the entire prefix -- including colon -- if the mismatch is at
// top level. This helper accepts the (possibly empty) recursively-accumulated
// prefix string, returning either empty or the original string with colon
// appended.
static std::string colon(const std::string& pfx)
{
if (pfx.empty())
return pfx;
return pfx + ": ";
}
// param type for match_types
typedef std::vector<LLSD::Type> TypeVector;
// The scalar cases in llsd_matches() use this helper. In most cases, we can
// accept not only the exact type specified in the prototype, but also other
// types convertible to the expected type. That implies looping over an array
// of such types. If the actual type doesn't match any of them, we want to
// provide a list of acceptable conversions as well as the exact type, e.g.:
// "Integer (or Boolean, Real, String) required instead of UUID". Both the
// implementation and the calling logic are simplified by separating out the
// expected type from the convertible types.
static std::string match_types(LLSD::Type expect, // prototype.type()
const TypeVector& accept, // types convertible to that type
LLSD::Type actual, // type we're checking
const std::string& pfx) // as for llsd_matches
{
// Trivial case: if the actual type is exactly what we expect, we're good.
if (actual == expect)
return "";
// For the rest of the logic, build up a suitable error string as we go so
// we only have to make a single pass over the list of acceptable types.
// If we detect success along the way, we'll simply discard the partial
// error string.
std::ostringstream out;
out << colon(pfx) << sTypes.lookup(expect);
// If there are any convertible types, append that list.
if (! accept.empty())
{
out << " (";
const char* sep = "or ";
for (TypeVector::const_iterator ai(accept.begin()), aend(accept.end());
ai != aend; ++ai, sep = ", ")
{
// Don't forget to return success if we match any of those types...
if (actual == *ai)
return "";
out << sep << sTypes.lookup(*ai);
}
out << ')';
}
// If we got this far, it's because 'actual' was not one of the acceptable
// types, so we must return an error. 'out' already contains colon(pfx)
// and the formatted list of acceptable types, so just append the mismatch
// phrase and the actual type.
out << op << sTypes.lookup(actual);
return out.str();
}
// see docstring in .h file
std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx)
{
// An undefined prototype means that any data is valid.
// An undefined slot in an array or map prototype means that any data
// may fill that slot.
if (prototype.isUndefined())
return "";
// A prototype array must match a data array with at least as many
// entries. Moreover, every prototype entry must match the
// corresponding data entry.
if (prototype.isArray())
{
if (! data.isArray())
{
return STRINGIZE(colon(pfx) << "Array" << op << sTypes.lookup(data.type()));
}
if (data.size() < prototype.size())
{
return STRINGIZE(colon(pfx) << "Array size " << prototype.size() << op
<< "Array size " << data.size());
}
for (LLSD::Integer i = 0; i < prototype.size(); ++i)
{
std::string match(llsd_matches(prototype[i], data[i], STRINGIZE('[' << i << ']')));
if (! match.empty())
{
return match;
}
}
return "";
}
// A prototype map must match a data map. Every key in the prototype
// must have a corresponding key in the data map; every value in the
// prototype must match the corresponding key's value in the data.
if (prototype.isMap())
{
if (! data.isMap())
{
return STRINGIZE(colon(pfx) << "Map" << op << sTypes.lookup(data.type()));
}
// If there are a number of keys missing from the data, it would be
// frustrating to a coder to discover them one at a time, with a big
// build each time. Enumerate all missing keys.
std::ostringstream out;
out << colon(pfx);
const char* init = "Map missing keys: ";
const char* sep = init;
for (LLSD::map_const_iterator mi = prototype.beginMap(); mi != prototype.endMap(); ++mi)
{
if (! data.has(mi->first))
{
out << sep << mi->first;
sep = ", ";
}
}
// So... are we missing any keys?
if (sep != init)
{
return out.str();
}
// Good, the data block contains all the keys required by the
// prototype. Now match the prototype entries.
for (LLSD::map_const_iterator mi2 = prototype.beginMap(); mi2 != prototype.endMap(); ++mi2)
{
std::string match(llsd_matches(mi2->second, data[mi2->first],
STRINGIZE("['" << mi2->first << "']")));
if (! match.empty())
{
return match;
}
}
return "";
}
// A String prototype can match String, Boolean, Integer, Real, UUID,
// Date and URI, because any of these can be converted to String.
if (prototype.isString())
{
static LLSD::Type accept[] =
{
LLSD::TypeBoolean,
LLSD::TypeInteger,
LLSD::TypeReal,
LLSD::TypeUUID,
LLSD::TypeDate,
LLSD::TypeURI
};
return match_types(prototype.type(),
TypeVector(boost::begin(accept), boost::end(accept)),
data.type(),
pfx);
}
// Boolean, Integer, Real match each other or String. TBD: ensure that
// a String value is numeric.
if (prototype.isBoolean() || prototype.isInteger() || prototype.isReal())
{
static LLSD::Type all[] =
{
LLSD::TypeBoolean,
LLSD::TypeInteger,
LLSD::TypeReal,
LLSD::TypeString
};
// Funny business: shuffle the set of acceptable types to include all
// but the prototype's type. Get the acceptable types in a set.
std::set<LLSD::Type> rest(boost::begin(all), boost::end(all));
// Remove the prototype's type because we pass that separately.
rest.erase(prototype.type());
return match_types(prototype.type(),
TypeVector(rest.begin(), rest.end()),
data.type(),
pfx);
}
// UUID, Date and URI match themselves or String.
if (prototype.isUUID() || prototype.isDate() || prototype.isURI())
{
static LLSD::Type accept[] =
{
LLSD::TypeString
};
return match_types(prototype.type(),
TypeVector(boost::begin(accept), boost::end(accept)),
data.type(),
pfx);
}
// We don't yet know the conversion semantics associated with any new LLSD
// data type that might be added, so until we've been extended to handle
// them, assume it's strict: the new type matches only itself. (This is
// true of Binary, which is why we don't handle that case separately.) Too
// bad LLSD doesn't define isConvertible(Type to, Type from).
return match_types(prototype.type(), TypeVector(), data.type(), pfx);
}
bool llsd_equals(const LLSD& lhs, const LLSD& rhs)
{
// We're comparing strict equality of LLSD representation rather than
// performing any conversions. So if the types aren't equal, the LLSD
// values aren't equal.
if (lhs.type() != rhs.type())
{
return false;
}
// Here we know both types are equal. Now compare values.
switch (lhs.type())
{
case LLSD::TypeUndefined:
// Both are TypeUndefined. There's nothing more to know.
return true;
#define COMPARE_SCALAR(type) \
case LLSD::Type##type: \
/* LLSD::URI has operator!=() but not operator==() */ \
/* rely on the optimizer for all others */ \
return (! (lhs.as##type() != rhs.as##type()))
COMPARE_SCALAR(Boolean);
COMPARE_SCALAR(Integer);
// The usual caveats about comparing floating-point numbers apply. This is
// only useful when we expect identical bit representation for a given
// Real value, e.g. for integer-valued Reals.
COMPARE_SCALAR(Real);
COMPARE_SCALAR(String);
COMPARE_SCALAR(UUID);
COMPARE_SCALAR(Date);
COMPARE_SCALAR(URI);
COMPARE_SCALAR(Binary);
#undef COMPARE_SCALAR
case LLSD::TypeArray:
{
LLSD::array_const_iterator
lai(lhs.beginArray()), laend(lhs.endArray()),
rai(rhs.beginArray()), raend(rhs.endArray());
// Compare array elements, walking the two arrays in parallel.
for ( ; lai != laend && rai != raend; ++lai, ++rai)
{
// If any one array element is unequal, the arrays are unequal.
if (! llsd_equals(*lai, *rai))
return false;
}
// Here we've reached the end of one or the other array. They're equal
// only if they're BOTH at end: that is, if they have equal length too.
return (lai == laend && rai == raend);
}
case LLSD::TypeMap:
{
// Build a set of all rhs keys.
std::set<LLSD::String> rhskeys;
for (LLSD::map_const_iterator rmi(rhs.beginMap()), rmend(rhs.endMap());
rmi != rmend; ++rmi)
{
rhskeys.insert(rmi->first);
}
// Now walk all the lhs keys.
for (LLSD::map_const_iterator lmi(lhs.beginMap()), lmend(lhs.endMap());
lmi != lmend; ++lmi)
{
// Try to erase this lhs key from the set of rhs keys. If rhs has
// no such key, the maps are unequal. erase(key) returns count of
// items erased.
if (rhskeys.erase(lmi->first) != 1)
return false;
// Both maps have the current key. Compare values.
if (! llsd_equals(lmi->second, rhs[lmi->first]))
return false;
}
// We've now established that all the lhs keys have equal values in
// both maps. The maps are equal unless rhs contains a superset of
// those keys.
return rhskeys.empty();
}
default:
// We expect that every possible type() value is specifically handled
// above. Failing to extend this switch to support a new LLSD type is
// an error that must be brought to the coder's attention.
LL_ERRS("llsd_equals") << "llsd_equals(" << lhs << ", " << rhs << "): "
"unknown type " << lhs.type() << LL_ENDL;
return false; // pacify the compiler
}
}

View File

@ -35,62 +35,32 @@
#ifndef LL_LLSDUTIL_H
#define LL_LLSDUTIL_H
#include "llsd.h"
// vector3
class LLVector3;
LLSD ll_sd_from_vector3(const LLVector3& vec);
LLVector3 ll_vector3_from_sd(const LLSD& sd, S32 start_index = 0);
// vector4
class LLVector4;
LLSD ll_sd_from_vector4(const LLVector4& vec);
LLVector4 ll_vector4_from_sd(const LLSD& sd, S32 start_index = 0);
// vector3d (double)
class LLVector3d;
LLSD ll_sd_from_vector3d(const LLVector3d& vec);
LLVector3d ll_vector3d_from_sd(const LLSD& sd, S32 start_index = 0);
// vector2
class LLVector2;
LLSD ll_sd_from_vector2(const LLVector2& vec);
LLVector2 ll_vector2_from_sd(const LLSD& sd);
// Quaternion
class LLQuaternion;
LLSD ll_sd_from_quaternion(const LLQuaternion& quat);
LLQuaternion ll_quaternion_from_sd(const LLSD& sd);
// color4
class LLColor4;
LLSD ll_sd_from_color4(const LLColor4& c);
LLColor4 ll_color4_from_sd(const LLSD& sd);
class LLSD;
// U32
LLSD ll_sd_from_U32(const U32);
U32 ll_U32_from_sd(const LLSD& sd);
LL_COMMON_API LLSD ll_sd_from_U32(const U32);
LL_COMMON_API U32 ll_U32_from_sd(const LLSD& sd);
// U64
LLSD ll_sd_from_U64(const U64);
U64 ll_U64_from_sd(const LLSD& sd);
LL_COMMON_API LLSD ll_sd_from_U64(const U64);
LL_COMMON_API U64 ll_U64_from_sd(const LLSD& sd);
// IP Address
LLSD ll_sd_from_ipaddr(const U32);
U32 ll_ipaddr_from_sd(const LLSD& sd);
LL_COMMON_API LLSD ll_sd_from_ipaddr(const U32);
LL_COMMON_API U32 ll_ipaddr_from_sd(const LLSD& sd);
// Binary to string
LLSD ll_string_from_binary(const LLSD& sd);
LL_COMMON_API LLSD ll_string_from_binary(const LLSD& sd);
//String to binary
LLSD ll_binary_from_string(const LLSD& sd);
LL_COMMON_API LLSD ll_binary_from_string(const LLSD& sd);
// Serializes sd to static buffer and returns pointer, useful for gdb debugging.
char* ll_print_sd(const LLSD& sd);
LL_COMMON_API char* ll_print_sd(const LLSD& sd);
// Serializes sd to static buffer and returns pointer, using "pretty printing" mode.
char* ll_pretty_print_sd_ptr(const LLSD* sd);
char* ll_pretty_print_sd(const LLSD& sd);
LL_COMMON_API char* ll_pretty_print_sd_ptr(const LLSD* sd);
LL_COMMON_API char* ll_pretty_print_sd(const LLSD& sd);
//compares the structure of an LLSD to a template LLSD and stores the
//"valid" values in a 3rd LLSD. Default values
@ -99,11 +69,69 @@ char* ll_pretty_print_sd(const LLSD& sd);
//Returns false if the test is of same type but values differ in type
//Otherwise, returns true
BOOL compare_llsd_with_template(
LL_COMMON_API BOOL compare_llsd_with_template(
const LLSD& llsd_to_test,
const LLSD& template_llsd,
LLSD& resultant_llsd);
/**
* Recursively determine whether a given LLSD data block "matches" another
* LLSD prototype. The returned string is empty() on success, non-empty() on
* mismatch.
*
* This function tests structure (types) rather than data values. It is
* intended for when a consumer expects an LLSD block with a particular
* structure, and must succinctly detect whether the arriving block is
* well-formed. For instance, a test of the form:
* @code
* if (! (data.has("request") && data.has("target") && data.has("modifier") ...))
* @endcode
* could instead be expressed by initializing a prototype LLSD map with the
* required keys and writing:
* @code
* if (! llsd_matches(prototype, data).empty())
* @endcode
*
* A non-empty return value is an error-message fragment intended to indicate
* to (English-speaking) developers where in the prototype structure the
* mismatch occurred.
*
* * If a slot in the prototype isUndefined(), then anything is valid at that
* place in the real object. (Passing prototype == LLSD() matches anything
* at all.)
* * An array in the prototype must match a data array at least that large.
* (Additional entries in the data array are ignored.) Every isDefined()
* entry in the prototype array must match the corresponding entry in the
* data array.
* * A map in the prototype must match a map in the data. Every key in the
* prototype map must match a corresponding key in the data map. (Additional
* keys in the data map are ignored.) Every isDefined() value in the
* prototype map must match the corresponding key's value in the data map.
* * Scalar values in the prototype are tested for @em type rather than value.
* For instance, a String in the prototype matches any String at all. In
* effect, storing an Integer at a particular place in the prototype asserts
* that the caller intends to apply asInteger() to the corresponding slot in
* the data.
* * A String in the prototype matches String, Boolean, Integer, Real, UUID,
* Date and URI, because asString() applied to any of these produces a
* meaningful result.
* * Similarly, a Boolean, Integer or Real in the prototype can match any of
* Boolean, Integer or Real in the data -- or even String.
* * UUID matches UUID or String.
* * Date matches Date or String.
* * URI matches URI or String.
* * Binary in the prototype matches only Binary in the data.
*
* @TODO: when a Boolean, Integer or Real in the prototype matches a String in
* the data, we should examine the String @em value to ensure it can be
* meaningfully converted to the requested type. The same goes for UUID, Date
* and URI.
*/
LL_COMMON_API std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx="");
/// Deep equality
LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs);
// Simple function to copy data out of input & output iterators if
// there is no need for casting.
template<typename Input> LLSD llsd_copy_array(Input iter, Input end)

View File

@ -34,49 +34,49 @@
#define LL_LLSECONDLIFEURLS_H
/*
// Account registration web page
extern const std::string CREATE_ACCOUNT_URL;
LL_COMMON_API extern const std::string CREATE_ACCOUNT_URL;
// Manage Account
extern const std::string MANAGE_ACCOUNT;
LL_COMMON_API extern const std::string MANAGE_ACCOUNT;
extern const std::string AUCTION_URL;
LL_COMMON_API extern const std::string AUCTION_URL;
extern const std::string EVENTS_URL;
LL_COMMON_API extern const std::string EVENTS_URL;
*/
// Tier up to a new land level.
extern const std::string TIER_UP_URL;
LL_COMMON_API extern const std::string TIER_UP_URL;
// Tier up to a new land level.
extern const std::string LAND_URL;
LL_COMMON_API extern const std::string LAND_URL;
// How to get DirectX 9
extern const std::string DIRECTX_9_URL;
LL_COMMON_API extern const std::string DIRECTX_9_URL;
/*
// Upgrade from basic membership to premium membership
extern const std::string UPGRADE_TO_PREMIUM_URL;
LL_COMMON_API extern const std::string UPGRADE_TO_PREMIUM_URL;
// Out of date VIA chipset
extern const std::string VIA_URL;
LL_COMMON_API extern const std::string VIA_URL;
// Support URL
extern const std::string SUPPORT_URL;
LL_COMMON_API extern const std::string SUPPORT_URL;
// Linden Blogs page
extern const std::string BLOGS_URL;
LL_COMMON_API extern const std::string BLOGS_URL;
// Currency page
extern const std::string BUY_CURRENCY_URL;
LL_COMMON_API extern const std::string BUY_CURRENCY_URL;
// LSL script wiki
extern const std::string LSL_DOC_URL;
LL_COMMON_API extern const std::string LSL_DOC_URL;
// SL KnowledgeBase page
extern const std::string SL_KB_URL;
LL_COMMON_API extern const std::string SL_KB_URL;
// Release Notes Redirect URL for Server and Viewer
extern const std::string RELEASE_NOTES_BASE_URL;
LL_COMMON_API extern const std::string RELEASE_NOTES_BASE_URL;
*/
#endif

View File

@ -64,7 +64,7 @@ public:
};
template <typename HASH_KEY_TYPE, int TABLE_SIZE>
class LLSimpleHash
class LL_COMMON_API LLSimpleHash
{
public:
LLSimpleHash()

View File

@ -0,0 +1,38 @@
/**
* @file llsingleton.cpp
* @author Brad Kittenbrink
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
* Copyright (c) 2009-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llsingleton.h"
std::map<std::string, void *> * LLSingletonRegistry::sSingletonMap = NULL;

View File

@ -33,7 +33,41 @@
#include "llerror.h" // *TODO: eliminate this
#include <typeinfo>
#include <boost/noncopyable.hpp>
#include <boost/any.hpp>
/// @brief A global registry of all singletons to prevent duplicate allocations
/// across shared library boundaries
class LL_COMMON_API LLSingletonRegistry {
private:
typedef std::map<std::string, void *> TypeMap;
static TypeMap * sSingletonMap;
static void checkInit()
{
if(sSingletonMap == NULL)
{
sSingletonMap = new TypeMap();
}
}
public:
template<typename T> static void * & get()
{
std::string name(typeid(T).name());
checkInit();
// the first entry of the pair returned by insert will be either the existing
// iterator matching our key, or the newly inserted NULL initialized entry
// see "Insert element" in http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
TypeMap::iterator result =
sSingletonMap->insert(std::make_pair(name, (void*)NULL)).first;
return result->second;
}
};
// LLSingleton implements the getInstance() method part of the Singleton
// pattern. It can't make the derived class constructors protected, though, so
@ -107,8 +141,17 @@ public:
static SingletonInstanceData& getData()
{
static SingletonInstanceData data;
return data;
// this is static to cache the lookup results
static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>();
// *TODO - look into making this threadsafe
if(NULL == registry)
{
static SingletonInstanceData data;
registry = &data;
}
return *static_cast<SingletonInstanceData *>(registry);
}
static DERIVED_TYPE* getInstance()

View File

@ -1,141 +1,142 @@
/**
* @file llstacktrace.cpp
* @brief stack tracing functionality
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#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
/**
* @file llstacktrace.cpp
* @brief stack tracing functionality
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#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,44 +1,44 @@
/**
* @file llstacktrace.h
* @brief stack trace functions
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLSTACKTRACE_H
#define LL_LLSTACKTRACE_H
#include "stdtypes.h"
#include <vector>
#include <string>
bool ll_get_stack_trace(std::vector<std::string>& lines);
#endif
/**
* @file llstacktrace.h
* @brief stack trace functions
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_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

@ -52,7 +52,7 @@ class LLSD;
// amounts of time with very low memory cost.
//
class LLStatAccum
class LL_COMMON_API LLStatAccum
{
protected:
LLStatAccum(bool use_frame_timer);
@ -116,7 +116,7 @@ public:
F64 mLastSampleValue;
};
class LLStatMeasure : public LLStatAccum
class LL_COMMON_API LLStatMeasure : public LLStatAccum
// gathers statistics about things that are measured
// ex.: tempature, time dilation
{
@ -131,7 +131,7 @@ public:
};
class LLStatRate : public LLStatAccum
class LL_COMMON_API LLStatRate : public LLStatAccum
// gathers statistics about things that can be counted over time
// ex.: LSL instructions executed, messages sent, simulator frames completed
// renders it in terms of rate of thing per second
@ -147,7 +147,7 @@ public:
};
class LLStatTime : public LLStatAccum
class LL_COMMON_API LLStatTime : public LLStatAccum
// gathers statistics about time spent in a block of code
// measure average duration per second in the block
{
@ -178,7 +178,7 @@ private:
// Use this class on the stack to record statistics about an area of code
class LLPerfBlock
class LL_COMMON_API LLPerfBlock
{
public:
struct StatEntry
@ -220,7 +220,7 @@ private:
// ----------------------------------------------------------------------------
class LLPerfStats
class LL_COMMON_API LLPerfStats
{
public:
LLPerfStats(const std::string& process_name = "unknown", S32 process_pid = 0);
@ -256,7 +256,7 @@ private:
};
// ----------------------------------------------------------------------------
class LLStat
class LL_COMMON_API LLStat
{
private:
typedef std::multimap<std::string, LLStat*> stat_map_t;

View File

@ -39,23 +39,23 @@
// unless specifed otherwise these all return input_stream.good()
// skips spaces and tabs
bool skip_whitespace(std::istream& input_stream);
LL_COMMON_API bool skip_whitespace(std::istream& input_stream);
// skips whitespace and newlines
bool skip_emptyspace(std::istream& input_stream);
LL_COMMON_API bool skip_emptyspace(std::istream& input_stream);
// skips emptyspace and lines that start with a #
bool skip_comments_and_emptyspace(std::istream& input_stream);
LL_COMMON_API bool skip_comments_and_emptyspace(std::istream& input_stream);
// skips to character after next newline
bool skip_line(std::istream& input_stream);
LL_COMMON_API bool skip_line(std::istream& input_stream);
// skips to beginning of next non-emptyspace
bool skip_to_next_word(std::istream& input_stream);
LL_COMMON_API bool skip_to_next_word(std::istream& input_stream);
// skips to character after the end of next keyword
// a 'keyword' is defined as the first word on a line
bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream);
LL_COMMON_API bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream);
// skip_to_start_of_next_keyword() is disabled -- might tickle corruption bug
// in windows iostream
@ -65,14 +65,14 @@ bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream
// characters are pulled out of input_stream and appended to output_string
// returns result of input_stream.good() after characters are pulled
bool get_word(std::string& output_string, std::istream& input_stream);
bool get_line(std::string& output_string, std::istream& input_stream);
LL_COMMON_API bool get_word(std::string& output_string, std::istream& input_stream);
LL_COMMON_API bool get_line(std::string& output_string, std::istream& input_stream);
// characters are pulled out of input_stream (up to a max of 'n')
// and appended to output_string
// returns result of input_stream.good() after characters are pulled
bool get_word(std::string& output_string, std::istream& input_stream, int n);
bool get_line(std::string& output_string, std::istream& input_stream, int n);
LL_COMMON_API bool get_word(std::string& output_string, std::istream& input_stream, int n);
LL_COMMON_API bool get_line(std::string& output_string, std::istream& input_stream, int n);
// unget_line() is disabled -- might tickle corruption bug in windows iostream
//// backs up the input_stream by line_size + 1 characters
@ -82,28 +82,28 @@ bool get_line(std::string& output_string, std::istream& input_stream, int n);
// removes the last char in 'line' if it matches 'c'
// returns true if removed last char
bool remove_last_char(char c, std::string& line);
LL_COMMON_API bool remove_last_char(char c, std::string& line);
// replaces escaped characters with the correct characters from left to right
// "\\" ---> '\\'
// "\n" ---> '\n'
void unescape_string(std::string& line);
LL_COMMON_API void unescape_string(std::string& line);
// replaces unescaped characters with expanded equivalents from left to right
// '\\' ---> "\\"
// '\n' ---> "\n"
void escape_string(std::string& line);
LL_COMMON_API void escape_string(std::string& line);
// replaces each '\n' character with ' '
void replace_newlines_with_whitespace(std::string& line);
LL_COMMON_API void replace_newlines_with_whitespace(std::string& line);
// erases any double-quote characters in line
void remove_double_quotes(std::string& line);
LL_COMMON_API void remove_double_quotes(std::string& line);
// the 'keyword' is defined as the first word on a line
// the 'value' is everything after the keyword on the same line
// starting at the first non-whitespace and ending right before the newline
void get_keyword_and_value(std::string& keyword,
LL_COMMON_API void get_keyword_and_value(std::string& keyword,
std::string& value,
const std::string& line);
@ -111,13 +111,13 @@ void get_keyword_and_value(std::string& keyword,
// read anymore or until we hit the count. Some istream
// implimentations have a max that they will read.
// Returns the number of bytes read.
std::streamsize fullread(
LL_COMMON_API std::streamsize fullread(
std::istream& istr,
char* buf,
std::streamsize requested);
std::istream& operator>>(std::istream& str, const char *tocheck);
LL_COMMON_API std::istream& operator>>(std::istream& str, const char *tocheck);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -56,7 +56,7 @@
const U32 MAX_STRINGS_LENGTH = 256;
class LLStringTableEntry
class LL_COMMON_API LLStringTableEntry
{
public:
LLStringTableEntry(const char *str)
@ -81,7 +81,7 @@ public:
S32 mCount;
};
class LLStringTable
class LL_COMMON_API LLStringTable
{
public:
LLStringTable(int tablesize);
@ -115,7 +115,7 @@ public:
#endif
};
extern LLStringTable gStringTable;
extern LL_COMMON_API LLStringTable gStringTable;
//============================================================================
@ -125,7 +125,7 @@ extern LLStringTable gStringTable;
typedef const std::string* LLStdStringHandle;
class LLStdStringTable
class LL_COMMON_API LLStdStringTable
{
public:
LLStdStringTable(S32 tablesize = 0)

View File

@ -128,8 +128,16 @@ LLOSInfo::LLOSInfo() :
mOSStringSimple = "Microsoft Windows Vista ";
else mOSStringSimple = "Microsoft Windows Vista Server ";
}
else if(osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1)
{
if(osvi.wProductType == VER_NT_WORKSTATION)
mOSStringSimple = "Microsoft Windows 7 ";
else mOSStringSimple = "Microsoft Windows 7 Server ";
}
else // Use the registry on early versions of Windows NT.
{
mOSStringSimple = "Microsoft Windows (unrecognized) ";
HKEY hKey;
WCHAR szProductType[80];
DWORD dwBufLen;

View File

@ -45,7 +45,7 @@
#include <iosfwd>
#include <string>
class LLOSInfo
class LL_COMMON_API LLOSInfo
{
public:
LLOSInfo();
@ -70,7 +70,7 @@ private:
};
class LLCPUInfo
class LL_COMMON_API LLCPUInfo
{
public:
LLCPUInfo();
@ -99,7 +99,7 @@ private:
//
// CLASS LLMemoryInfo
class LLMemoryInfo
class LL_COMMON_API LLMemoryInfo
/*! @brief Class to query the memory subsystem
@ -123,15 +123,15 @@ public:
};
std::ostream& operator<<(std::ostream& s, const LLOSInfo& info);
std::ostream& operator<<(std::ostream& s, const LLCPUInfo& info);
std::ostream& operator<<(std::ostream& s, const LLMemoryInfo& info);
LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLOSInfo& info);
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.
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.
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);
extern LLCPUInfo gSysCPU;
extern LL_COMMON_API LLCPUInfo gSysCPU;
#endif // LL_LLSYS_H

View File

@ -42,7 +42,7 @@ class LLThread;
class LLMutex;
class LLCondition;
class LLThread
class LL_COMMON_API LLThread
{
public:
typedef enum e_thread_status
@ -130,7 +130,7 @@ protected:
//============================================================================
class LLMutex
class LL_COMMON_API LLMutex
{
public:
LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex
@ -147,7 +147,7 @@ protected:
};
// Actually a condition/mutex pair (since each condition needs to be associated with a mutex).
class LLCondition : public LLMutex
class LL_COMMON_API LLCondition : public LLMutex
{
public:
LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well.
@ -194,7 +194,7 @@ void LLThread::unlockData()
// see llmemory.h for LLPointer<> definition
class LLThreadSafeRefCount
class LL_COMMON_API LLThreadSafeRefCount
{
public:
static void initThreadSafeRefCount(); // creates sMutex
@ -246,7 +246,7 @@ private:
// Simple responder for self destructing callbacks
// Pure virtual class
class LLResponder : public LLThreadSafeRefCount
class LL_COMMON_API LLResponder : public LLThreadSafeRefCount
{
protected:
virtual ~LLResponder();

View File

@ -55,7 +55,7 @@ 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;
class LLTimer
class LL_COMMON_API LLTimer
{
public:
static LLTimer *sTimer; // global timer
@ -114,17 +114,17 @@ public:
//
// Various functions for initializing/accessing clock and timing stuff. Don't use these without REALLY knowing how they work.
//
U64 get_clock_count();
F64 calc_clock_frequency(U32 msecs);
void update_clock_frequencies();
LL_COMMON_API U64 get_clock_count();
LL_COMMON_API F64 calc_clock_frequency(U32 msecs);
LL_COMMON_API void update_clock_frequencies();
// Sleep for milliseconds
void ms_sleep(U32 ms);
U32 micro_sleep(U64 us, U32 max_yields = 0xFFFFFFFF);
LL_COMMON_API void ms_sleep(U32 ms);
LL_COMMON_API U32 micro_sleep(U64 us, U32 max_yields = 0xFFFFFFFF);
// Returns the correct UTC time in seconds, like time(NULL).
// Useful on the viewer, which may have its local clock set wrong.
time_t time_corrected();
LL_COMMON_API time_t time_corrected();
static inline time_t time_min()
{
@ -155,24 +155,24 @@ static inline time_t time_max()
}
// Correction factor used by time_corrected() above.
extern S32 gUTCOffset;
extern LL_COMMON_API S32 gUTCOffset;
// Is the current computer (in its current time zone)
// observing daylight savings time?
BOOL is_daylight_savings();
LL_COMMON_API BOOL is_daylight_savings();
// Converts internal "struct tm" time buffer to Pacific Standard/Daylight Time
// Usage:
// S32 utc_time;
// utc_time = time_corrected();
// struct tm* internal_time = utc_to_pacific_time(utc_time, gDaylight);
struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time);
LL_COMMON_API struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time);
void microsecondsToTimecodeString(U64 current_time, std::string& tcstring);
void secondsToTimecodeString(F32 current_time, std::string& tcstring);
LL_COMMON_API void microsecondsToTimecodeString(U64 current_time, std::string& tcstring);
LL_COMMON_API void secondsToTimecodeString(F32 current_time, std::string& tcstring);
// class for scheduling a function to be called at a given frequency (approximate, inprecise)
class LLEventTimer : protected LLInstanceTracker<LLEventTimer>
class LL_COMMON_API LLEventTimer : protected LLInstanceTracker<LLEventTimer>
{
public:
LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds
@ -190,4 +190,6 @@ protected:
F32 mPeriod;
};
U64 LL_COMMON_API totalTime(); // Returns current system time in microseconds
#endif

View File

@ -47,7 +47,7 @@ class LLApp;
* See: http://www.ietf.org/rfc/rfc3986.txt
*
*/
class LLURI
class LL_COMMON_API LLURI
{
public:
LLURI();

View File

@ -35,6 +35,7 @@
#include <iostream>
#include <set>
#include "stdtypes.h"
#include "llpreprocessor.h"
const S32 UUID_BYTES = 16;
const S32 UUID_WORDS = 4;
@ -47,7 +48,7 @@ struct uuid_time_t {
U32 low;
};
class LLUUID
class LL_COMMON_API LLUUID
{
public:
//
@ -106,8 +107,8 @@ public:
LLUUID combine(const LLUUID& other) const;
void combine(const LLUUID& other, LLUUID& result) const;
friend std::ostream& operator<<(std::ostream& s, const LLUUID &uuid);
friend std::istream& operator>>(std::istream& s, LLUUID &uuid);
friend LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLUUID &uuid);
friend LL_COMMON_API std::istream& operator>>(std::istream& s, LLUUID &uuid);
void toString(char *out) const; // Does not allocate memory, needs 36 characters (including \0)
void toString(std::string& out) const;
@ -323,7 +324,7 @@ typedef std::set<LLUUID, lluuid_less> uuid_list_t;
*/
typedef LLUUID LLAssetID;
class LLTransactionID : public LLUUID
class LL_COMMON_API LLTransactionID : public LLUUID
{
public:
LLTransactionID() : LLUUID() { }

View File

@ -50,7 +50,7 @@ class LLWorkerClass;
// Note: ~LLWorkerThread is O(N) N=# of worker threads, assumed to be small
// It is assumed that LLWorkerThreads are rarely created/destroyed.
class LLWorkerThread : public LLQueuedThread
class LL_COMMON_API LLWorkerThread : public LLQueuedThread
{
public:
class WorkRequest : public LLQueuedThread::QueuedRequest
@ -113,7 +113,7 @@ public:
// Only one background task can be active at a time (per instance).
// i.e. don't call addWork() if haveWork() returns true
class LLWorkerClass
class LL_COMMON_API LLWorkerClass
{
friend class LLWorkerThread;
friend class LLWorkerThread::WorkRequest;

View File

@ -43,7 +43,7 @@
class LLReflective;
class LLMetaProperty;
class LLMetaMethod;
class LLMetaClass
class LL_COMMON_API LLMetaClass
{
public:

View File

@ -41,7 +41,7 @@
class LLMetaClass;
class LLReflective;
class LLMetaProperty
class LL_COMMON_API LLMetaProperty
{
public:
LLMetaProperty(const std::string& name, const LLMetaClass& object_class);

View File

@ -36,7 +36,7 @@
#define LL_REFLECTIVE_H
class LLMetaClass;
class LLReflective
class LL_COMMON_API LLReflective
{
public:
LLReflective();

View File

@ -13,6 +13,7 @@
#define LL_STRINGIZE_H
#include <sstream>
#include <boost/lambda/lambda.hpp>
/**
* stringize(item) encapsulates an idiom we use constantly, using
@ -27,6 +28,17 @@ std::string stringize(const T& item)
return out.str();
}
/**
* stringize_f(functor)
*/
template <typename Functor>
std::string stringize_f(Functor const & f)
{
std::ostringstream out;
f(out);
return out.str();
}
/**
* STRINGIZE(item1 << item2 << item3 ...) effectively expands to the
* following:
@ -36,40 +48,43 @@ std::string stringize(const T& item)
* return out.str();
* @endcode
*/
#define STRINGIZE(EXPRESSION) (static_cast<std::ostringstream&>(Stringize() << EXPRESSION).str())
#define STRINGIZE(EXPRESSION) (stringize_f(boost::lambda::_1 << EXPRESSION))
/**
* Helper class for STRINGIZE() macro. Ideally the body of
* STRINGIZE(EXPRESSION) would look something like this:
* @code
* (std::ostringstream() << EXPRESSION).str()
* @endcode
* That doesn't work because each of the relevant operator<<() functions
* accepts a non-const std::ostream&, to which you can't pass a temp instance
* of std::ostringstream. Stringize plays the necessary const tricks to make
* the whole thing work.
* destringize(str)
* defined for symmetry with stringize
* *NOTE - this has distinct behavior from boost::lexical_cast<T> regarding
* leading/trailing whitespace and handling of bad_lexical_cast exceptions
*/
class Stringize
template <typename T>
T destringize(std::string const & str)
{
public:
/**
* This is the essence of Stringize. The leftmost << operator (the one
* coded in the STRINGIZE() macro) engages this operator<<() const method
* on the temp Stringize instance. Every other << operator (ones embedded
* in EXPRESSION) simply sees the std::ostream& returned by the first one.
*
* Finally, the STRINGIZE() macro downcasts that std::ostream& to
* std::ostringstream&.
*/
template <typename T>
std::ostream& operator<<(const T& item) const
{
mOut << item;
return mOut;
}
T val;
std::istringstream in(str);
in >> val;
return val;
}
/**
* destringize_f(str, functor)
*/
template <typename Functor>
void destringize_f(std::string const & str, Functor const & f)
{
std::istringstream in(str);
f(in);
}
/**
* DESTRINGIZE(str, item1 >> item2 >> item3 ...) effectively expands to the
* following:
* @code
* std::istringstream in(str);
* in >> item1 >> item2 >> item3 ... ;
* @endcode
*/
#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), (boost::lambda::_1 >> EXPRESSION)))
private:
mutable std::ostringstream mOut;
};
#endif /* ! defined(LL_STRINGIZE_H) */

View File

@ -0,0 +1,139 @@
/**
* @file listener.h
* @author Nat Goodspeed
* @date 2009-03-06
* @brief Useful for tests of the LLEventPump family of classes
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
* Copyright (c) 2009, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_LISTENER_H)
#define LL_LISTENER_H
#include "llsd.h"
#include <iostream>
/*****************************************************************************
* test listener class
*****************************************************************************/
class Listener;
std::ostream& operator<<(std::ostream&, const Listener&);
/// Bear in mind that this is strictly for testing
class Listener
{
public:
/// Every Listener is instantiated with a name
Listener(const std::string& name):
mName(name)
{
// std::cout << *this << ": ctor\n";
}
/*==========================================================================*|
// These methods are only useful when trying to track Listener instance
// lifespan
Listener(const Listener& that):
mName(that.mName),
mLastEvent(that.mLastEvent)
{
std::cout << *this << ": copy\n";
}
virtual ~Listener()
{
std::cout << *this << ": dtor\n";
}
|*==========================================================================*/
/// You can request the name
std::string getName() const { return mName; }
/// This is a typical listener method that returns 'false' when done,
/// allowing subsequent listeners on the LLEventPump to process the
/// incoming event.
bool call(const LLSD& event)
{
// std::cout << *this << "::call(" << event << ")\n";
mLastEvent = event;
return false;
}
/// This is an alternate listener that returns 'true' when done, which
/// stops processing of the incoming event.
bool callstop(const LLSD& event)
{
// std::cout << *this << "::callstop(" << event << ")\n";
mLastEvent = event;
return true;
}
/// ListenMethod can represent either call() or callstop().
typedef bool (Listener::*ListenMethod)(const LLSD&);
/**
* This helper method is only because our test code makes so many
* repetitive listen() calls to ListenerMethods. In real code, you should
* call LLEventPump::listen() directly so it can examine the specific
* object you pass to boost::bind().
*/
LLBoundListener listenTo(LLEventPump& pump,
ListenMethod method=&Listener::call,
const LLEventPump::NameList& after=LLEventPump::empty,
const LLEventPump::NameList& before=LLEventPump::empty)
{
return pump.listen(getName(), boost::bind(method, this, _1), after, before);
}
/// Both call() and callstop() set mLastEvent. Retrieve it.
LLSD getLastEvent() const
{
// std::cout << *this << "::getLastEvent() -> " << mLastEvent << "\n";
return mLastEvent;
}
/// Reset mLastEvent to a known state.
void reset(const LLSD& to = LLSD())
{
// std::cout << *this << "::reset(" << to << ")\n";
mLastEvent = to;
}
private:
std::string mName;
LLSD mLastEvent;
};
std::ostream& operator<<(std::ostream& out, const Listener& listener)
{
out << "Listener(" << listener.getName() /* << "@" << &listener */ << ')';
return out;
}
/**
* This class tests the relative order in which various listeners on a given
* LLEventPump are called. Each listen() call binds a particular string, which
* we collect for later examination. The actual event is ignored.
*/
struct Collect
{
bool add(const std::string& bound, const LLSD& event)
{
result.push_back(bound);
return false;
}
void clear() { result.clear(); }
typedef std::vector<std::string> StringList;
StringList result;
};
std::ostream& operator<<(std::ostream& out, const Collect::StringList& strings)
{
out << '(';
Collect::StringList::const_iterator begin(strings.begin()), end(strings.end());
if (begin != end)
{
out << '"' << *begin << '"';
while (++begin != end)
{
out << ", \"" << *begin << '"';
}
}
out << ')';
return out;
}
#endif /* ! defined(LL_LISTENER_H) */

View File

@ -0,0 +1,782 @@
/**
* @file coroutine_test.cpp
* @author Nat Goodspeed
* @date 2009-04-22
* @brief Test for coroutine.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
* Copyright (c) 2009, Linden Research, Inc.
* $/LicenseInfo$
*/
/*****************************************************************************/
// test<1>() is cloned from a Boost.Coroutine example program whose copyright
// info is reproduced here:
/*---------------------------------------------------------------------------*/
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
/*****************************************************************************/
// On some platforms, Boost.Coroutine must #define magic symbols before
// #including platform-API headers. Naturally, that's ineffective unless the
// Boost.Coroutine #include is the *first* #include of the platform header.
// That means that client code must generally #include Boost.Coroutine headers
// before anything else.
#include <boost/coroutine/coroutine.hpp>
// Normally, lleventcoro.h obviates future.hpp. We only include this because
// we implement a "by hand" test of future functionality.
#include <boost/coroutine/future.hpp>
#include <boost/bind.hpp>
#include <boost/range.hpp>
#include "linden_common.h"
#include <iostream>
#include <string>
#include "../test/lltut.h"
#include "llsd.h"
#include "llevents.h"
#include "tests/wrapllerrs.h"
#include "stringize.h"
#include "lleventcoro.h"
#include "../test/debug.h"
/*****************************************************************************
* from the banana.cpp example program borrowed for test<1>()
*****************************************************************************/
namespace coroutines = boost::coroutines;
using coroutines::coroutine;
template<typename Iter>
bool match(Iter first, Iter last, std::string match) {
std::string::iterator i = match.begin();
i != match.end();
for(; (first != last) && (i != match.end()); ++i) {
if (*first != *i)
return false;
++first;
}
return i == match.end();
}
template<typename BidirectionalIterator>
BidirectionalIterator
match_substring(BidirectionalIterator begin,
BidirectionalIterator end,
std::string xmatch,
BOOST_DEDUCED_TYPENAME coroutine<BidirectionalIterator(void)>::self& self) {
BidirectionalIterator begin_ = begin;
for(; begin != end; ++begin)
if(match(begin, end, xmatch)) {
self.yield(begin);
}
return end;
}
typedef coroutine<std::string::iterator(void)> match_coroutine_type;
/*****************************************************************************
* Test helpers
*****************************************************************************/
// I suspect this will be typical of coroutines used in Linden software
typedef boost::coroutines::coroutine<void()> coroutine_type;
/// Simulate an event API whose response is immediate: sent on receipt of the
/// initial request, rather than after some delay. This is the case that
/// distinguishes postAndWait() from calling post(), then calling
/// waitForEventOn().
class ImmediateAPI
{
public:
ImmediateAPI():
mPump("immediate", true)
{
mPump.listen("API", boost::bind(&ImmediateAPI::operator(), this, _1));
}
LLEventPump& getPump() { return mPump; }
// Invoke this with an LLSD map containing:
// ["value"]: Integer value. We will reply with ["value"] + 1.
// ["reply"]: Name of LLEventPump on which to send success response.
// ["error"]: Name of LLEventPump on which to send error response.
// ["fail"]: Presence of this key selects ["error"], else ["success"] as
// the name of the pump on which to send the response.
bool operator()(const LLSD& event) const
{
LLSD::Integer value(event["value"]);
LLSD::String replyPumpName(event.has("fail")? "error" : "reply");
LLEventPumps::instance().obtain(event[replyPumpName]).post(value + 1);
return false;
}
private:
LLEventStream mPump;
};
/*****************************************************************************
* TUT
*****************************************************************************/
namespace tut
{
struct coroutine_data
{
// Define coroutine bodies as methods here so they can use ensure*()
void explicit_wait(coroutine_type::self& self)
{
BEGIN
{
// ... do whatever preliminary stuff must happen ...
// declare the future
boost::coroutines::future<LLSD> future(self);
// tell the future what to wait for
LLTempBoundListener connection(
LLEventPumps::instance().obtain("source").listen("coro", voidlistener(boost::coroutines::make_callback(future))));
ensure("Not yet", ! future);
// attempting to dereference ("resolve") the future causes the calling
// coroutine to wait for it
debug("about to wait");
result = *future;
ensure("Got it", future);
}
END
}
void waitForEventOn1(coroutine_type::self& self)
{
BEGIN
{
result = waitForEventOn(self, "source");
}
END
}
void waitForEventOn2(coroutine_type::self& self)
{
BEGIN
{
LLEventWithID pair = waitForEventOn(self, "reply", "error");
result = pair.first;
which = pair.second;
debug(STRINGIZE("result = " << result << ", which = " << which));
}
END
}
void postAndWait1(coroutine_type::self& self)
{
BEGIN
{
result = postAndWait(self,
LLSD().insert("value", 17), // request event
immediateAPI.getPump(), // requestPump
"reply1", // replyPump
"reply"); // request["reply"] = name
}
END
}
void postAndWait2(coroutine_type::self& self)
{
BEGIN
{
LLEventWithID pair = ::postAndWait2(self,
LLSD().insert("value", 18),
immediateAPI.getPump(),
"reply2",
"error2",
"reply",
"error");
result = pair.first;
which = pair.second;
debug(STRINGIZE("result = " << result << ", which = " << which));
}
END
}
void postAndWait2_1(coroutine_type::self& self)
{
BEGIN
{
LLEventWithID pair = ::postAndWait2(self,
LLSD().insert("value", 18).insert("fail", LLSD()),
immediateAPI.getPump(),
"reply2",
"error2",
"reply",
"error");
result = pair.first;
which = pair.second;
debug(STRINGIZE("result = " << result << ", which = " << which));
}
END
}
void coroPump(coroutine_type::self& self)
{
BEGIN
{
LLCoroEventPump waiter;
replyName = waiter.getName();
result = waiter.wait(self);
}
END
}
void coroPumpPost(coroutine_type::self& self)
{
BEGIN
{
LLCoroEventPump waiter;
result = waiter.postAndWait(self, LLSD().insert("value", 17),
immediateAPI.getPump(), "reply");
}
END
}
void coroPumps(coroutine_type::self& self)
{
BEGIN
{
LLCoroEventPumps waiter;
replyName = waiter.getName0();
errorName = waiter.getName1();
LLEventWithID pair(waiter.wait(self));
result = pair.first;
which = pair.second;
}
END
}
void coroPumpsNoEx(coroutine_type::self& self)
{
BEGIN
{
LLCoroEventPumps waiter;
replyName = waiter.getName0();
errorName = waiter.getName1();
result = waiter.waitWithException(self);
}
END
}
void coroPumpsEx(coroutine_type::self& self)
{
BEGIN
{
LLCoroEventPumps waiter;
replyName = waiter.getName0();
errorName = waiter.getName1();
try
{
result = waiter.waitWithException(self);
debug("no exception");
}
catch (const LLErrorEvent& e)
{
debug(STRINGIZE("exception " << e.what()));
errordata = e.getData();
}
}
END
}
void coroPumpsNoLog(coroutine_type::self& self)
{
BEGIN
{
LLCoroEventPumps waiter;
replyName = waiter.getName0();
errorName = waiter.getName1();
result = waiter.waitWithLog(self);
}
END
}
void coroPumpsLog(coroutine_type::self& self)
{
BEGIN
{
LLCoroEventPumps waiter;
replyName = waiter.getName0();
errorName = waiter.getName1();
WrapLL_ERRS capture;
try
{
result = waiter.waitWithLog(self);
debug("no exception");
}
catch (const WrapLL_ERRS::FatalException& e)
{
debug(STRINGIZE("exception " << e.what()));
threw = e.what();
}
}
END
}
void coroPumpsPost(coroutine_type::self& self)
{
BEGIN
{
LLCoroEventPumps waiter;
LLEventWithID pair(waiter.postAndWait(self, LLSD().insert("value", 23),
immediateAPI.getPump(), "reply", "error"));
result = pair.first;
which = pair.second;
}
END
}
void coroPumpsPost_1(coroutine_type::self& self)
{
BEGIN
{
LLCoroEventPumps waiter;
LLEventWithID pair(
waiter.postAndWait(self, LLSD().insert("value", 23).insert("fail", LLSD()),
immediateAPI.getPump(), "reply", "error"));
result = pair.first;
which = pair.second;
}
END
}
void coroPumpsPostNoEx(coroutine_type::self& self)
{
BEGIN
{
LLCoroEventPumps waiter;
result = waiter.postAndWaitWithException(self, LLSD().insert("value", 8),
immediateAPI.getPump(), "reply", "error");
}
END
}
void coroPumpsPostEx(coroutine_type::self& self)
{
BEGIN
{
LLCoroEventPumps waiter;
try
{
result = waiter.postAndWaitWithException(self,
LLSD().insert("value", 9).insert("fail", LLSD()),
immediateAPI.getPump(), "reply", "error");
debug("no exception");
}
catch (const LLErrorEvent& e)
{
debug(STRINGIZE("exception " << e.what()));
errordata = e.getData();
}
}
END
}
void coroPumpsPostNoLog(coroutine_type::self& self)
{
BEGIN
{
LLCoroEventPumps waiter;
result = waiter.postAndWaitWithLog(self, LLSD().insert("value", 30),
immediateAPI.getPump(), "reply", "error");
}
END
}
void coroPumpsPostLog(coroutine_type::self& self)
{
BEGIN
{
LLCoroEventPumps waiter;
WrapLL_ERRS capture;
try
{
result = waiter.postAndWaitWithLog(self,
LLSD().insert("value", 31).insert("fail", LLSD()),
immediateAPI.getPump(), "reply", "error");
debug("no exception");
}
catch (const WrapLL_ERRS::FatalException& e)
{
debug(STRINGIZE("exception " << e.what()));
threw = e.what();
}
}
END
}
void ensure_done(coroutine_type& coro)
{
ensure("coroutine complete", ! coro);
}
ImmediateAPI immediateAPI;
std::string replyName, errorName, threw;
LLSD result, errordata;
int which;
};
typedef test_group<coroutine_data> coroutine_group;
typedef coroutine_group::object object;
coroutine_group coroutinegrp("coroutine");
template<> template<>
void object::test<1>()
{
set_test_name("From banana.cpp example program in Boost.Coroutine distro");
std::string buffer = "banananana";
std::string match = "nana";
std::string::iterator begin = buffer.begin();
std::string::iterator end = buffer.end();
#if defined(BOOST_CORO_POSIX_IMPL)
// std::cout << "Using Boost.Coroutine " << BOOST_CORO_POSIX_IMPL << '\n';
#else
// std::cout << "Using non-Posix Boost.Coroutine implementation" << std::endl;
#endif
typedef std::string::iterator signature(std::string::iterator,
std::string::iterator,
std::string,
match_coroutine_type::self&);
coroutine<std::string::iterator(void)> matcher
(boost::bind(static_cast<signature*>(match_substring),
begin,
end,
match,
_1));
std::string::iterator i = matcher();
/*==========================================================================*|
while(matcher && i != buffer.end()) {
std::cout <<"Match at: "<< std::distance(buffer.begin(), i)<<'\n';
i = matcher();
}
|*==========================================================================*/
size_t matches[] = { 2, 4, 6 };
for (size_t *mi(boost::begin(matches)), *mend(boost::end(matches));
mi != mend; ++mi, i = matcher())
{
ensure("more", matcher);
ensure("found", i != buffer.end());
ensure_equals("value", std::distance(buffer.begin(), i), *mi);
}
ensure("done", ! matcher);
}
template<> template<>
void object::test<2>()
{
set_test_name("explicit_wait");
DEBUG;
// Construct the coroutine instance that will run explicit_wait.
// Pass the ctor a callable that accepts the coroutine_type::self
// param passed by the library.
coroutine_type coro(boost::bind(&coroutine_data::explicit_wait, this, _1));
// Start the coroutine
coro(std::nothrow);
// When the coroutine waits for the event pump, it returns here.
debug("about to send");
// Satisfy the wait.
LLEventPumps::instance().obtain("source").post("received");
// Now wait for the coroutine to complete.
ensure_done(coro);
// ensure the coroutine ran and woke up again with the intended result
ensure_equals(result.asString(), "received");
}
template<> template<>
void object::test<3>()
{
set_test_name("waitForEventOn1");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn1, this, _1));
coro(std::nothrow);
debug("about to send");
LLEventPumps::instance().obtain("source").post("received");
debug("back from send");
ensure_done(coro);
ensure_equals(result.asString(), "received");
}
template<> template<>
void object::test<4>()
{
set_test_name("waitForEventOn2 reply");
{
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn2, this, _1));
coro(std::nothrow);
debug("about to send");
LLEventPumps::instance().obtain("reply").post("received");
debug("back from send");
ensure_done(coro);
}
ensure_equals(result.asString(), "received");
ensure_equals("which pump", which, 0);
}
template<> template<>
void object::test<5>()
{
set_test_name("waitForEventOn2 error");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn2, this, _1));
coro(std::nothrow);
debug("about to send");
LLEventPumps::instance().obtain("error").post("badness");
debug("back from send");
ensure_done(coro);
ensure_equals(result.asString(), "badness");
ensure_equals("which pump", which, 1);
}
template<> template<>
void object::test<6>()
{
set_test_name("coroPump");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::coroPump, this, _1));
coro(std::nothrow);
debug("about to send");
LLEventPumps::instance().obtain(replyName).post("received");
debug("back from send");
ensure_done(coro);
ensure_equals(result.asString(), "received");
}
template<> template<>
void object::test<7>()
{
set_test_name("coroPumps reply");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::coroPumps, this, _1));
coro(std::nothrow);
debug("about to send");
LLEventPumps::instance().obtain(replyName).post("received");
debug("back from send");
ensure_done(coro);
ensure_equals(result.asString(), "received");
ensure_equals("which pump", which, 0);
}
template<> template<>
void object::test<8>()
{
set_test_name("coroPumps error");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::coroPumps, this, _1));
coro(std::nothrow);
debug("about to send");
LLEventPumps::instance().obtain(errorName).post("badness");
debug("back from send");
ensure_done(coro);
ensure_equals(result.asString(), "badness");
ensure_equals("which pump", which, 1);
}
template<> template<>
void object::test<9>()
{
set_test_name("coroPumpsNoEx");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::coroPumpsNoEx, this, _1));
coro(std::nothrow);
debug("about to send");
LLEventPumps::instance().obtain(replyName).post("received");
debug("back from send");
ensure_done(coro);
ensure_equals(result.asString(), "received");
}
template<> template<>
void object::test<10>()
{
set_test_name("coroPumpsEx");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::coroPumpsEx, this, _1));
coro(std::nothrow);
debug("about to send");
LLEventPumps::instance().obtain(errorName).post("badness");
debug("back from send");
ensure_done(coro);
ensure("no result", result.isUndefined());
ensure_equals("got error", errordata.asString(), "badness");
}
template<> template<>
void object::test<11>()
{
set_test_name("coroPumpsNoLog");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::coroPumpsNoLog, this, _1));
coro(std::nothrow);
debug("about to send");
LLEventPumps::instance().obtain(replyName).post("received");
debug("back from send");
ensure_done(coro);
ensure_equals(result.asString(), "received");
}
template<> template<>
void object::test<12>()
{
set_test_name("coroPumpsLog");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::coroPumpsLog, this, _1));
coro(std::nothrow);
debug("about to send");
LLEventPumps::instance().obtain(errorName).post("badness");
debug("back from send");
ensure_done(coro);
ensure("no result", result.isUndefined());
ensure_contains("got error", threw, "badness");
}
template<> template<>
void object::test<13>()
{
set_test_name("postAndWait1");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::postAndWait1, this, _1));
coro(std::nothrow);
ensure_done(coro);
ensure_equals(result.asInteger(), 18);
}
template<> template<>
void object::test<14>()
{
set_test_name("postAndWait2");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::postAndWait2, this, _1));
coro(std::nothrow);
ensure_done(coro);
ensure_equals(result.asInteger(), 19);
ensure_equals(which, 0);
}
template<> template<>
void object::test<15>()
{
set_test_name("postAndWait2_1");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::postAndWait2_1, this, _1));
coro(std::nothrow);
ensure_done(coro);
ensure_equals(result.asInteger(), 19);
ensure_equals(which, 1);
}
template<> template<>
void object::test<16>()
{
set_test_name("coroPumpPost");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::coroPumpPost, this, _1));
coro(std::nothrow);
ensure_done(coro);
ensure_equals(result.asInteger(), 18);
}
template<> template<>
void object::test<17>()
{
set_test_name("coroPumpsPost reply");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPost, this, _1));
coro(std::nothrow);
ensure_done(coro);
ensure_equals(result.asInteger(), 24);
ensure_equals("which pump", which, 0);
}
template<> template<>
void object::test<18>()
{
set_test_name("coroPumpsPost error");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPost_1, this, _1));
coro(std::nothrow);
ensure_done(coro);
ensure_equals(result.asInteger(), 24);
ensure_equals("which pump", which, 1);
}
template<> template<>
void object::test<19>()
{
set_test_name("coroPumpsPostNoEx");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostNoEx, this, _1));
coro(std::nothrow);
ensure_done(coro);
ensure_equals(result.asInteger(), 9);
}
template<> template<>
void object::test<20>()
{
set_test_name("coroPumpsPostEx");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostEx, this, _1));
coro(std::nothrow);
ensure_done(coro);
ensure("no result", result.isUndefined());
ensure_equals("got error", errordata.asInteger(), 10);
}
template<> template<>
void object::test<21>()
{
set_test_name("coroPumpsPostNoLog");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostNoLog, this, _1));
coro(std::nothrow);
ensure_done(coro);
ensure_equals(result.asInteger(), 31);
}
template<> template<>
void object::test<22>()
{
set_test_name("coroPumpsPostLog");
DEBUG;
coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostLog, this, _1));
coro(std::nothrow);
ensure_done(coro);
ensure("no result", result.isUndefined());
ensure_contains("got error", threw, "32");
}
} // namespace tut

View File

@ -0,0 +1,276 @@
/**
* @file lleventfilter_test.cpp
* @author Nat Goodspeed
* @date 2009-03-06
* @brief Test for lleventfilter.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
* Copyright (c) 2009, Linden Research, Inc.
* $/LicenseInfo$
*/
// Precompiled header
#include "linden_common.h"
// associated header
#include "lleventfilter.h"
// STL headers
// std headers
// external library headers
// other Linden headers
#include "../test/lltut.h"
#include "stringize.h"
#include "listener.h"
#include "tests/wrapllerrs.h"
/*****************************************************************************
* Test classes
*****************************************************************************/
// Strictly speaking, we're testing LLEventTimeoutBase rather than the
// production LLEventTimeout (using LLTimer) because we don't want every test
// run to pause for some number of seconds until we reach a real timeout. But
// as we've carefully put all functionality except actual LLTimer calls into
// LLEventTimeoutBase, that should suffice. We're not not not trying to test
// LLTimer here.
class TestEventTimeout: public LLEventTimeoutBase
{
public:
TestEventTimeout():
mElapsed(true)
{}
TestEventTimeout(LLEventPump& source):
LLEventTimeoutBase(source),
mElapsed(true)
{}
// test hook
void forceTimeout(bool timeout=true) { mElapsed = timeout; }
protected:
virtual void setCountdown(F32 seconds) { mElapsed = false; }
virtual bool countdownElapsed() const { return mElapsed; }
private:
bool mElapsed;
};
/*****************************************************************************
* TUT
*****************************************************************************/
namespace tut
{
struct filter_data
{
// The resemblance between this test data and that in llevents_tut.cpp
// is not coincidental.
filter_data():
pumps(LLEventPumps::instance()),
mainloop(pumps.obtain("mainloop")),
listener0("first"),
listener1("second")
{}
LLEventPumps& pumps;
LLEventPump& mainloop;
Listener listener0;
Listener listener1;
void check_listener(const std::string& desc, const Listener& listener, const LLSD& got)
{
ensure_equals(STRINGIZE(listener << ' ' << desc),
listener.getLastEvent(), got);
}
};
typedef test_group<filter_data> filter_group;
typedef filter_group::object filter_object;
filter_group filtergrp("lleventfilter");
template<> template<>
void filter_object::test<1>()
{
set_test_name("LLEventMatching");
LLEventPump& driver(pumps.obtain("driver"));
listener0.reset(0);
// Listener isn't derived from LLEventTrackable specifically to test
// various connection-management mechanisms. But that means we have a
// couple of transient Listener objects, one of which is listening to
// a persistent LLEventPump. Capture those connections in local
// LLTempBoundListener instances so they'll disconnect
// on destruction.
LLTempBoundListener temp1(
listener0.listenTo(driver));
// Construct a pattern LLSD: desired Event must have a key "foo"
// containing string "bar"
LLEventMatching filter(driver, LLSD().insert("foo", "bar"));
listener1.reset(0);
LLTempBoundListener temp2(
listener1.listenTo(filter));
driver.post(1);
check_listener("direct", listener0, LLSD(1));
check_listener("filtered", listener1, LLSD(0));
// Okay, construct an LLSD map matching the pattern
LLSD data;
data["foo"] = "bar";
data["random"] = 17;
driver.post(data);
check_listener("direct", listener0, data);
check_listener("filtered", listener1, data);
}
template<> template<>
void filter_object::test<2>()
{
set_test_name("LLEventTimeout::actionAfter()");
LLEventPump& driver(pumps.obtain("driver"));
TestEventTimeout filter(driver);
listener0.reset(0);
LLTempBoundListener temp1(
listener0.listenTo(filter));
// Use listener1.call() as the Action for actionAfter(), since it
// already provides a way to sense the call
listener1.reset(0);
// driver --> filter --> listener0
filter.actionAfter(20,
boost::bind(&Listener::call, boost::ref(listener1), LLSD("timeout")));
// Okay, (fake) timer is ticking. 'filter' can only sense the timer
// when we pump mainloop. Do that right now to take the logic path
// before either the anticipated event arrives or the timer expires.
mainloop.post(17);
check_listener("no timeout 1", listener1, LLSD(0));
// Expected event arrives...
driver.post(1);
check_listener("event passed thru", listener0, LLSD(1));
// Should have canceled the timer. Verify that by asserting that the
// time has expired, then pumping mainloop again.
filter.forceTimeout();
mainloop.post(17);
check_listener("no timeout 2", listener1, LLSD(0));
// Verify chained actionAfter() calls, that is, that a second
// actionAfter() resets the timer established by the first
// actionAfter().
filter.actionAfter(20,
boost::bind(&Listener::call, boost::ref(listener1), LLSD("timeout")));
// Since our TestEventTimeout class isn't actually manipulating time
// (quantities of seconds), only a bool "elapsed" flag, sense that by
// forcing the flag between actionAfter() calls.
filter.forceTimeout();
// Pumping mainloop here would result in a timeout (as we'll verify
// below). This state simulates a ticking timer that has not yet timed
// out. But now, before a mainloop event lets 'filter' recognize
// timeout on the previous actionAfter() call, pretend we're pushing
// that timeout farther into the future.
filter.actionAfter(20,
boost::bind(&Listener::call, boost::ref(listener1), LLSD("timeout")));
// Look ma, no timeout!
mainloop.post(17);
check_listener("no timeout 3", listener1, LLSD(0));
// Now let the updated actionAfter() timer expire.
filter.forceTimeout();
// Notice the timeout.
mainloop.post(17);
check_listener("timeout", listener1, LLSD("timeout"));
// Timing out cancels the timer. Verify that.
listener1.reset(0);
filter.forceTimeout();
mainloop.post(17);
check_listener("no timeout 4", listener1, LLSD(0));
// Reset the timer and then cancel() it.
filter.actionAfter(20,
boost::bind(&Listener::call, boost::ref(listener1), LLSD("timeout")));
// neither expired nor satisified
mainloop.post(17);
check_listener("no timeout 5", listener1, LLSD(0));
// cancel
filter.cancel();
// timeout!
filter.forceTimeout();
mainloop.post(17);
check_listener("no timeout 6", listener1, LLSD(0));
}
template<> template<>
void filter_object::test<3>()
{
set_test_name("LLEventTimeout::eventAfter()");
LLEventPump& driver(pumps.obtain("driver"));
TestEventTimeout filter(driver);
listener0.reset(0);
LLTempBoundListener temp1(
listener0.listenTo(filter));
filter.eventAfter(20, LLSD("timeout"));
// Okay, (fake) timer is ticking. 'filter' can only sense the timer
// when we pump mainloop. Do that right now to take the logic path
// before either the anticipated event arrives or the timer expires.
mainloop.post(17);
check_listener("no timeout 1", listener0, LLSD(0));
// Expected event arrives...
driver.post(1);
check_listener("event passed thru", listener0, LLSD(1));
// Should have canceled the timer. Verify that by asserting that the
// time has expired, then pumping mainloop again.
filter.forceTimeout();
mainloop.post(17);
check_listener("no timeout 2", listener0, LLSD(1));
// Set timer again.
filter.eventAfter(20, LLSD("timeout"));
// Now let the timer expire.
filter.forceTimeout();
// Notice the timeout.
mainloop.post(17);
check_listener("timeout", listener0, LLSD("timeout"));
// Timing out cancels the timer. Verify that.
listener0.reset(0);
filter.forceTimeout();
mainloop.post(17);
check_listener("no timeout 3", listener0, LLSD(0));
}
template<> template<>
void filter_object::test<4>()
{
set_test_name("LLEventTimeout::errorAfter()");
WrapLL_ERRS capture;
LLEventPump& driver(pumps.obtain("driver"));
TestEventTimeout filter(driver);
listener0.reset(0);
LLTempBoundListener temp1(
listener0.listenTo(filter));
filter.errorAfter(20, "timeout");
// Okay, (fake) timer is ticking. 'filter' can only sense the timer
// when we pump mainloop. Do that right now to take the logic path
// before either the anticipated event arrives or the timer expires.
mainloop.post(17);
check_listener("no timeout 1", listener0, LLSD(0));
// Expected event arrives...
driver.post(1);
check_listener("event passed thru", listener0, LLSD(1));
// Should have canceled the timer. Verify that by asserting that the
// time has expired, then pumping mainloop again.
filter.forceTimeout();
mainloop.post(17);
check_listener("no timeout 2", listener0, LLSD(1));
// Set timer again.
filter.errorAfter(20, "timeout");
// Now let the timer expire.
filter.forceTimeout();
// Notice the timeout.
std::string threw;
try
{
mainloop.post(17);
}
catch (const WrapLL_ERRS::FatalException& e)
{
threw = e.what();
}
ensure_contains("errorAfter() timeout exception", threw, "timeout");
// Timing out cancels the timer. Verify that.
listener0.reset(0);
filter.forceTimeout();
mainloop.post(17);
check_listener("no timeout 3", listener0, LLSD(0));
}
} // namespace tut
/*****************************************************************************
* Link dependencies
*****************************************************************************/
#include "llsdutil.cpp"

View File

@ -0,0 +1,56 @@
/**
* @file wrapllerrs.h
* @author Nat Goodspeed
* @date 2009-03-11
* @brief Define a class useful for unit tests that engage llerrs (LL_ERRS) functionality
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
* Copyright (c) 2009, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_WRAPLLERRS_H)
#define LL_WRAPLLERRS_H
#include "llerrorcontrol.h"
struct WrapLL_ERRS
{
WrapLL_ERRS():
// Resetting Settings discards the default Recorder that writes to
// stderr. Otherwise, expected llerrs (LL_ERRS) messages clutter the
// console output of successful tests, potentially confusing things.
mPriorErrorSettings(LLError::saveAndResetSettings()),
// Save shutdown function called by LL_ERRS
mPriorFatal(LLError::getFatalFunction())
{
// Make LL_ERRS call our own operator() method
LLError::setFatalFunction(boost::bind(&WrapLL_ERRS::operator(), this, _1));
}
~WrapLL_ERRS()
{
LLError::setFatalFunction(mPriorFatal);
LLError::restoreSettings(mPriorErrorSettings);
}
struct FatalException: public std::runtime_error
{
FatalException(const std::string& what): std::runtime_error(what) {}
};
void operator()(const std::string& message)
{
// Save message for later in case consumer wants to sense the result directly
error = message;
// Also throw an appropriate exception since calling code is likely to
// assume that control won't continue beyond LL_ERRS.
throw FatalException(message);
}
std::string error;
LLError::Settings* mPriorErrorSettings;
LLError::FatalFunction mPriorFatal;
};
#endif /* ! defined(LL_WRAPLLERRS_H) */

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

@ -39,14 +39,14 @@
* @param str The string to parse.
* @return Returns the first U64 value found in the string or 0 on failure.
*/
U64 str_to_U64(const std::string& str);
LL_COMMON_API U64 str_to_U64(const std::string& str);
/**
* @brief Given a U64 value, return a printable representation.
* @param value The U64 to turn into a printable character array.
* @return Returns the result string.
*/
std::string U64_to_str(U64 value);
LL_COMMON_API std::string U64_to_str(U64 value);
/**
* @brief Given a U64 value, return a printable representation.
@ -65,16 +65,16 @@ std::string U64_to_str(U64 value);
* @param result_size The size of the buffer allocated. Use U64_BUF.
* @return Returns the result pointer.
*/
char* U64_to_str(U64 value, char* result, S32 result_size);
LL_COMMON_API char* U64_to_str(U64 value, char* result, S32 result_size);
/**
* @brief Convert a U64 to the closest F64 value.
*/
F64 U64_to_F64(const U64 value);
LL_COMMON_API F64 U64_to_F64(const U64 value);
/**
* @brief Helper function to wrap strtoull() which is not available on windows.
*/
U64 llstrtou64(const char* str, char** end, S32 base);
LL_COMMON_API U64 llstrtou64(const char* str, char** end, S32 base);
#endif

View File

@ -43,7 +43,7 @@
#include "llsdutil.h"
#include "lltransactiontypes.h"
#include "lltransactionflags.h"
#include "llsdutil.h"
#include "llsdutil_math.h"
#include "message.h"
#include "u64.h"

View File

@ -62,6 +62,7 @@ set(llmath_HEADER_FILES
llv4vector3.h
llvolume.h
llvolumemgr.h
llsdutil_math.h
m3math.h
m4math.h
raytrace.h

View File

@ -30,6 +30,8 @@
* $/LicenseInfo$
*/
#include "linden_common.h"
// self include
#include "llbbox.h"

View File

@ -34,7 +34,7 @@
#include "linden_common.h"
#include "llsdutil.h"
#include "llsdutil_math.h"
#include "v3math.h"
#include "v4math.h"

View File

@ -0,0 +1,70 @@
/**
* @file llsdutil_math.h
* @author Brad
* @date 2009-05-19
* @brief Utility classes, functions, etc, for using structured data with math classes.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
* Copyright (c) 2009-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLSDUTIL_MATH_H
#define LL_LLSDUTIL_MATH_H
class LL_COMMON_API LLSD;
// vector3
class LLVector3;
LLSD ll_sd_from_vector3(const LLVector3& vec);
LLVector3 ll_vector3_from_sd(const LLSD& sd, S32 start_index = 0);
// vector4
class LLVector4;
LLSD ll_sd_from_vector4(const LLVector4& vec);
LLVector4 ll_vector4_from_sd(const LLSD& sd, S32 start_index = 0);
// vector3d (double)
class LLVector3d;
LLSD ll_sd_from_vector3d(const LLVector3d& vec);
LLVector3d ll_vector3d_from_sd(const LLSD& sd, S32 start_index = 0);
// vector2
class LLVector2;
LLSD ll_sd_from_vector2(const LLVector2& vec);
LLVector2 ll_vector2_from_sd(const LLSD& sd);
// Quaternion
class LLQuaternion;
LLSD ll_sd_from_quaternion(const LLQuaternion& quat);
LLQuaternion ll_quaternion_from_sd(const LLSD& sd);
// color4
class LLColor4;
LLSD ll_sd_from_color4(const LLColor4& c);
LLColor4 ll_color4_from_sd(const LLSD& sd);
#endif // LL_LLSDUTIL_MATH_H

View File

@ -22,6 +22,7 @@ include_directories(
set(llmessage_SOURCE_FILES
llares.cpp
llareslistener.cpp
llassetstorage.cpp
llblowfishcipher.cpp
llbuffer.cpp
@ -104,6 +105,7 @@ set(llmessage_HEADER_FILES
CMakeLists.txt
llares.h
llareslistener.h
llassetstorage.h
llblowfishcipher.h
llbuffer.h
@ -221,10 +223,11 @@ IF (NOT LINUX AND VIEWER)
# llhttpclientadapter.cpp
lltrustedmessageservice.cpp
lltemplatemessagedispatcher.cpp
# Commented out - see rationale at bottom of newview's build file + poppy 2009-06-05
# Don't make llmessage depend on llsdmessage_test because ADD_COMM_BUILD_TEST depends on llmessage!
# ADD_COMM_BUILD_TEST(llsdmessage "" "${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llsdmessage_peer.py")
# llareslistener.cpp
)
LL_ADD_PROJECT_UNIT_TESTS(llmessage "${llmessage_TEST_SOURCE_FILES}")
# Commented out - see rationale at bottom of newview's build file + poppy 2009-06-05
# Don't make llmessage depend on llsdmessage_test because ADD_COMM_BUILD_TEST depends on llmessage!
# ADD_COMM_BUILD_TEST(llsdmessage "" "${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llsdmessage_peer.py")
ENDIF (NOT LINUX AND VIEWER)

View File

@ -33,6 +33,7 @@
*/
#include "linden_common.h"
#include "llares.h"
#include <ares_dns.h>
#include <ares_version.h>
@ -42,9 +43,10 @@
#include "apr_poll.h"
#include "llapr.h"
#include "llares.h"
#include "llareslistener.h"
#if defined(LL_WINDOWS)
#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
# define ns_c_in 1
# define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */
# define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */
@ -102,7 +104,9 @@ void LLAres::QueryResponder::queryError(int code)
}
LLAres::LLAres() :
chan_(NULL), mInitSuccess(false)
chan_(NULL),
mInitSuccess(false),
mListener(new LLAresListener("LLAres", this))
{
if (ares_init(&chan_) != ARES_SUCCESS)
{

Some files were not shown because too many files have changed in this diff Show More