Merged in viewer-2.0.0-3 changes up through r129050. Boost got clobbered so I'll need to rebuild that, plus a couple other minor clenaups.
commit
a7efd0d8dd
|
|
@ -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
|
||||
|
|
@ -65,6 +65,7 @@ add_custom_target(viewer)
|
|||
if (VIEWER)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llcrashlogger)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llui)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}viewer_components)
|
||||
|
||||
if (LINUX)
|
||||
add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
# -*- cmake -*-
|
||||
|
||||
set(LLLOGIN_INCLUDE_DIRS
|
||||
${LIBS_OPEN_DIR}/viewer_components/login
|
||||
)
|
||||
|
||||
set(LLLOGIN_LIBRARIES lllogin)
|
||||
|
|
@ -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,6 +14,7 @@ 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})
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -435,7 +435,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 '
|
||||
|
|
@ -453,9 +452,7 @@ class DarwinSetup(UnixSetup):
|
|||
targets = ' '.join(['-target ' + repr(t) for t in targets])
|
||||
else:
|
||||
targets = ''
|
||||
# cmd = ('xcodebuild -parallelizeTargets ' # parallelizeTargets is suspected of non-deterministic build failures. + poppy 2009-06-05
|
||||
cmd = ('xcodebuild '
|
||||
'-configuration %s %s %s' %
|
||||
cmd = ('xcodebuild -configuration %s %s %s' %
|
||||
(self.build_type, ' '.join(opts), targets))
|
||||
for d in self.build_dirs():
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -105,6 +116,7 @@ set(llcommon_HEADER_FILES
|
|||
llchat.h
|
||||
llclickaction.h
|
||||
llcommon.h
|
||||
llcoros.h
|
||||
llcrc.h
|
||||
llcriticaldamp.h
|
||||
llcursortypes.h
|
||||
|
|
@ -126,6 +138,9 @@ set(llcommon_HEADER_FILES
|
|||
llerrorlegacy.h
|
||||
llerrorthread.h
|
||||
llevent.h
|
||||
lleventcoro.h
|
||||
lleventdispatcher.h
|
||||
lleventfilter.h
|
||||
llevents.h
|
||||
lleventemitter.h
|
||||
llextendedstatus.h
|
||||
|
|
@ -140,6 +155,7 @@ set(llcommon_HEADER_FILES
|
|||
llhttpstatuscodes.h
|
||||
llindexedqueue.h
|
||||
llinstancetracker.h
|
||||
llinstancetracker.h
|
||||
llkeythrottle.h
|
||||
lllazy.h
|
||||
lllinkedqueue.h
|
||||
|
|
@ -219,17 +235,49 @@ 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})
|
||||
endif(SHARED_LIB_STAGING_DIR)
|
||||
|
||||
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_FILE}
|
||||
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/${LLCOMMON_FILE}
|
||||
COMMENT "Copying llcommon to the staging folder."
|
||||
)
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public:
|
|||
};
|
||||
#endif
|
||||
|
||||
class LLApp
|
||||
class LL_COMMON_API LLApp
|
||||
{
|
||||
friend class LLErrorThread;
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,203 +1,203 @@
|
|||
/**
|
||||
* @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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
#include "lltimer.h"
|
||||
#include "llfile.h"
|
||||
|
||||
class LLCommon
|
||||
class LL_COMMON_API LLCommon
|
||||
{
|
||||
public:
|
||||
static void initClass();
|
||||
|
|
|
|||
|
|
@ -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 "";
|
||||
}
|
||||
|
|
@ -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) */
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
// llinfos << "File crc: " << crc.getCRC() << llendl;
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
class LLCRC
|
||||
class LL_COMMON_API LLCRC
|
||||
{
|
||||
protected:
|
||||
U32 mCurrent;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
#include "llframetimer.h"
|
||||
|
||||
class LLCriticalDamp
|
||||
class LL_COMMON_API LLCriticalDamp
|
||||
{
|
||||
public:
|
||||
LLCriticalDamp();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"};
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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 ;
|
||||
|
|
|
|||
|
|
@ -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,13 +68,13 @@ 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 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
|
||||
|
||||
|
|
@ -84,21 +84,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):
|
||||
|
|
@ -116,15 +116,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:
|
||||
|
|
@ -138,17 +138,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
|
||||
|
||||
|
||||
|
|
@ -157,11 +157,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();
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
#include "llthread.h"
|
||||
|
||||
class LLErrorThread : public LLThread
|
||||
class LL_COMMON_API LLErrorThread : public LLThread
|
||||
{
|
||||
public:
|
||||
LLErrorThread();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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) */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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) */
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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) */
|
||||
|
|
@ -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
|
||||
|
|
@ -256,6 +259,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 +508,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
|
|
@ -1,352 +1,352 @@
|
|||
/**
|
||||
* @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() { return mCollapsed; }
|
||||
|
||||
U64 getCountAverage() { return mCountAverage; }
|
||||
U64 getCallAverage() { return mCallAverage; }
|
||||
|
||||
U64 getHistoricalCount(S32 history_index = 0);
|
||||
U64 getHistoricalCalls(S32 history_index = 0);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
static DeclareTimer FTM_ARRANGE;
|
||||
static DeclareTimer FTM_ATTACHMENT_UPDATE;
|
||||
static DeclareTimer FTM_AUDIO_UPDATE;
|
||||
static DeclareTimer FTM_AUTO_SELECT;
|
||||
static DeclareTimer FTM_AVATAR_UPDATE;
|
||||
static DeclareTimer FTM_CLEANUP;
|
||||
static DeclareTimer FTM_CLIENT_COPY;
|
||||
static DeclareTimer FTM_CREATE_OBJECT;
|
||||
static DeclareTimer FTM_CULL;
|
||||
static DeclareTimer FTM_CULL_REBOUND;
|
||||
static DeclareTimer FTM_FILTER;
|
||||
static DeclareTimer FTM_FLEXIBLE_UPDATE;
|
||||
static DeclareTimer FTM_FRAME;
|
||||
static DeclareTimer FTM_FRUSTUM_CULL;
|
||||
static DeclareTimer FTM_GEN_FLEX;
|
||||
static DeclareTimer FTM_GEN_TRIANGLES;
|
||||
static DeclareTimer FTM_GEN_VOLUME;
|
||||
static DeclareTimer FTM_GEO_SKY;
|
||||
static DeclareTimer FTM_GEO_UPDATE;
|
||||
static DeclareTimer FTM_HUD_EFFECTS;
|
||||
static DeclareTimer FTM_HUD_UPDATE;
|
||||
static DeclareTimer FTM_IDLE;
|
||||
static DeclareTimer FTM_IDLE_CB;
|
||||
static DeclareTimer FTM_IDLE_NETWORK;
|
||||
static DeclareTimer FTM_IMAGE_CREATE;
|
||||
static DeclareTimer FTM_IMAGE_MARK_DIRTY;
|
||||
static DeclareTimer FTM_IMAGE_UPDATE;
|
||||
static DeclareTimer FTM_INVENTORY;
|
||||
static DeclareTimer FTM_JOINT_UPDATE;
|
||||
static DeclareTimer FTM_KEYHANDLER;
|
||||
static DeclareTimer FTM_LOAD_AVATAR;
|
||||
static DeclareTimer FTM_LOD_UPDATE;
|
||||
static DeclareTimer FTM_MESSAGES;
|
||||
static DeclareTimer FTM_MOUSEHANDLER;
|
||||
static DeclareTimer FTM_NETWORK;
|
||||
static DeclareTimer FTM_OBJECTLIST_UPDATE;
|
||||
static DeclareTimer FTM_OCCLUSION_READBACK;
|
||||
static DeclareTimer FTM_OCTREE_BALANCE;
|
||||
static DeclareTimer FTM_PICK;
|
||||
static DeclareTimer FTM_PIPELINE;
|
||||
static DeclareTimer FTM_POOLRENDER;
|
||||
static DeclareTimer FTM_POOLS;
|
||||
static DeclareTimer FTM_PROCESS_IMAGES;
|
||||
static DeclareTimer FTM_PROCESS_MESSAGES;
|
||||
static DeclareTimer FTM_PROCESS_OBJECTS;
|
||||
static DeclareTimer FTM_PUMP;
|
||||
static DeclareTimer FTM_REBUILD_GRASS_VB;
|
||||
static DeclareTimer FTM_REBUILD_PARTICLE_VB;
|
||||
static DeclareTimer FTM_REBUILD_TERRAIN_VB;
|
||||
static DeclareTimer FTM_REBUILD_VBO;
|
||||
static DeclareTimer FTM_REBUILD_VOLUME_VB;
|
||||
static DeclareTimer FTM_REFRESH;
|
||||
static DeclareTimer FTM_REGION_UPDATE;
|
||||
static DeclareTimer FTM_RENDER;
|
||||
static DeclareTimer FTM_RENDER_ALPHA;
|
||||
static DeclareTimer FTM_RENDER_BLOOM;
|
||||
static DeclareTimer FTM_RENDER_BLOOM_FBO;
|
||||
static DeclareTimer FTM_RENDER_BUMP;
|
||||
static DeclareTimer FTM_RENDER_CHARACTERS;
|
||||
static DeclareTimer FTM_RENDER_FAKE_VBO_UPDATE;
|
||||
static DeclareTimer FTM_RENDER_FONTS;
|
||||
static DeclareTimer FTM_RENDER_FULLBRIGHT;
|
||||
static DeclareTimer FTM_RENDER_GEOMETRY;
|
||||
static DeclareTimer FTM_RENDER_GLOW;
|
||||
static DeclareTimer FTM_RENDER_GRASS;
|
||||
static DeclareTimer FTM_RENDER_INVISIBLE;
|
||||
static DeclareTimer FTM_RENDER_OCCLUSION;
|
||||
static DeclareTimer FTM_RENDER_SHINY;
|
||||
static DeclareTimer FTM_RENDER_SIMPLE;
|
||||
static DeclareTimer FTM_RENDER_TERRAIN;
|
||||
static DeclareTimer FTM_RENDER_TREES;
|
||||
static DeclareTimer FTM_RENDER_UI;
|
||||
static DeclareTimer FTM_RENDER_WATER;
|
||||
static DeclareTimer FTM_RENDER_WL_SKY;
|
||||
static DeclareTimer FTM_RESET_DRAWORDER;
|
||||
static DeclareTimer FTM_SHADOW_ALPHA;
|
||||
static DeclareTimer FTM_SHADOW_AVATAR;
|
||||
static DeclareTimer FTM_SHADOW_RENDER;
|
||||
static DeclareTimer FTM_SHADOW_SIMPLE;
|
||||
static DeclareTimer FTM_SHADOW_TERRAIN;
|
||||
static DeclareTimer FTM_SHADOW_TREE;
|
||||
static DeclareTimer FTM_SIMULATE_PARTICLES;
|
||||
static DeclareTimer FTM_SLEEP;
|
||||
static DeclareTimer FTM_SORT;
|
||||
static DeclareTimer FTM_STATESORT;
|
||||
static DeclareTimer FTM_STATESORT_DRAWABLE;
|
||||
static DeclareTimer FTM_STATESORT_POSTSORT;
|
||||
static DeclareTimer FTM_SWAP;
|
||||
static DeclareTimer FTM_TEMP1;
|
||||
static DeclareTimer FTM_TEMP2;
|
||||
static DeclareTimer FTM_TEMP3;
|
||||
static DeclareTimer FTM_TEMP4;
|
||||
static DeclareTimer FTM_TEMP5;
|
||||
static DeclareTimer FTM_TEMP6;
|
||||
static DeclareTimer FTM_TEMP7;
|
||||
static DeclareTimer FTM_TEMP8;
|
||||
static DeclareTimer FTM_UPDATE_ANIMATION;
|
||||
static DeclareTimer FTM_UPDATE_AVATAR;
|
||||
static DeclareTimer FTM_UPDATE_CLOUDS;
|
||||
static DeclareTimer FTM_UPDATE_GRASS;
|
||||
static DeclareTimer FTM_UPDATE_MOVE;
|
||||
static DeclareTimer FTM_UPDATE_PARTICLES;
|
||||
static DeclareTimer FTM_UPDATE_PRIMITIVES;
|
||||
static DeclareTimer FTM_UPDATE_SKY;
|
||||
static DeclareTimer FTM_UPDATE_TERRAIN;
|
||||
static DeclareTimer FTM_UPDATE_TEXTURES;
|
||||
static DeclareTimer FTM_UPDATE_TREE;
|
||||
static DeclareTimer FTM_UPDATE_WATER;
|
||||
static DeclareTimer FTM_UPDATE_WLPARAM;
|
||||
static DeclareTimer FTM_VFILE_WAIT;
|
||||
static DeclareTimer FTM_WORLD_UPDATE;
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
~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);
|
||||
|
||||
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() { return mCollapsed; }
|
||||
|
||||
U64 getCountAverage() { return mCountAverage; }
|
||||
U64 getCallAverage() { return mCallAverage; }
|
||||
|
||||
U64 getHistoricalCount(S32 history_index = 0);
|
||||
U64 getHistoricalCalls(S32 history_index = 0);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
static DeclareTimer FTM_ARRANGE;
|
||||
static DeclareTimer FTM_ATTACHMENT_UPDATE;
|
||||
static DeclareTimer FTM_AUDIO_UPDATE;
|
||||
static DeclareTimer FTM_AUTO_SELECT;
|
||||
static DeclareTimer FTM_AVATAR_UPDATE;
|
||||
static DeclareTimer FTM_CLEANUP;
|
||||
static DeclareTimer FTM_CLIENT_COPY;
|
||||
static DeclareTimer FTM_CREATE_OBJECT;
|
||||
static DeclareTimer FTM_CULL;
|
||||
static DeclareTimer FTM_CULL_REBOUND;
|
||||
static DeclareTimer FTM_FILTER;
|
||||
static DeclareTimer FTM_FLEXIBLE_UPDATE;
|
||||
static DeclareTimer FTM_FRAME;
|
||||
static DeclareTimer FTM_FRUSTUM_CULL;
|
||||
static DeclareTimer FTM_GEN_FLEX;
|
||||
static DeclareTimer FTM_GEN_TRIANGLES;
|
||||
static DeclareTimer FTM_GEN_VOLUME;
|
||||
static DeclareTimer FTM_GEO_SKY;
|
||||
static DeclareTimer FTM_GEO_UPDATE;
|
||||
static DeclareTimer FTM_HUD_EFFECTS;
|
||||
static DeclareTimer FTM_HUD_UPDATE;
|
||||
static DeclareTimer FTM_IDLE;
|
||||
static DeclareTimer FTM_IDLE_CB;
|
||||
static DeclareTimer FTM_IDLE_NETWORK;
|
||||
static DeclareTimer FTM_IMAGE_CREATE;
|
||||
static DeclareTimer FTM_IMAGE_MARK_DIRTY;
|
||||
static DeclareTimer FTM_IMAGE_UPDATE;
|
||||
static DeclareTimer FTM_INVENTORY;
|
||||
static DeclareTimer FTM_JOINT_UPDATE;
|
||||
static DeclareTimer FTM_KEYHANDLER;
|
||||
static DeclareTimer FTM_LOAD_AVATAR;
|
||||
static DeclareTimer FTM_LOD_UPDATE;
|
||||
static DeclareTimer FTM_MESSAGES;
|
||||
static DeclareTimer FTM_MOUSEHANDLER;
|
||||
static DeclareTimer FTM_NETWORK;
|
||||
static DeclareTimer FTM_OBJECTLIST_UPDATE;
|
||||
static DeclareTimer FTM_OCCLUSION_READBACK;
|
||||
static DeclareTimer FTM_OCTREE_BALANCE;
|
||||
static DeclareTimer FTM_PICK;
|
||||
static DeclareTimer FTM_PIPELINE;
|
||||
static DeclareTimer FTM_POOLRENDER;
|
||||
static DeclareTimer FTM_POOLS;
|
||||
static DeclareTimer FTM_PROCESS_IMAGES;
|
||||
static DeclareTimer FTM_PROCESS_MESSAGES;
|
||||
static DeclareTimer FTM_PROCESS_OBJECTS;
|
||||
static DeclareTimer FTM_PUMP;
|
||||
static DeclareTimer FTM_REBUILD_GRASS_VB;
|
||||
static DeclareTimer FTM_REBUILD_PARTICLE_VB;
|
||||
static DeclareTimer FTM_REBUILD_TERRAIN_VB;
|
||||
static DeclareTimer FTM_REBUILD_VBO;
|
||||
static DeclareTimer FTM_REBUILD_VOLUME_VB;
|
||||
static DeclareTimer FTM_REFRESH;
|
||||
static DeclareTimer FTM_REGION_UPDATE;
|
||||
static DeclareTimer FTM_RENDER;
|
||||
static DeclareTimer FTM_RENDER_ALPHA;
|
||||
static DeclareTimer FTM_RENDER_BLOOM;
|
||||
static DeclareTimer FTM_RENDER_BLOOM_FBO;
|
||||
static DeclareTimer FTM_RENDER_BUMP;
|
||||
static DeclareTimer FTM_RENDER_CHARACTERS;
|
||||
static DeclareTimer FTM_RENDER_FAKE_VBO_UPDATE;
|
||||
static DeclareTimer FTM_RENDER_FONTS;
|
||||
static DeclareTimer FTM_RENDER_FULLBRIGHT;
|
||||
static DeclareTimer FTM_RENDER_GEOMETRY;
|
||||
static DeclareTimer FTM_RENDER_GLOW;
|
||||
static DeclareTimer FTM_RENDER_GRASS;
|
||||
static DeclareTimer FTM_RENDER_INVISIBLE;
|
||||
static DeclareTimer FTM_RENDER_OCCLUSION;
|
||||
static DeclareTimer FTM_RENDER_SHINY;
|
||||
static DeclareTimer FTM_RENDER_SIMPLE;
|
||||
static DeclareTimer FTM_RENDER_TERRAIN;
|
||||
static DeclareTimer FTM_RENDER_TREES;
|
||||
static DeclareTimer FTM_RENDER_UI;
|
||||
static DeclareTimer FTM_RENDER_WATER;
|
||||
static DeclareTimer FTM_RENDER_WL_SKY;
|
||||
static DeclareTimer FTM_RESET_DRAWORDER;
|
||||
static DeclareTimer FTM_SHADOW_ALPHA;
|
||||
static DeclareTimer FTM_SHADOW_AVATAR;
|
||||
static DeclareTimer FTM_SHADOW_RENDER;
|
||||
static DeclareTimer FTM_SHADOW_SIMPLE;
|
||||
static DeclareTimer FTM_SHADOW_TERRAIN;
|
||||
static DeclareTimer FTM_SHADOW_TREE;
|
||||
static DeclareTimer FTM_SIMULATE_PARTICLES;
|
||||
static DeclareTimer FTM_SLEEP;
|
||||
static DeclareTimer FTM_SORT;
|
||||
static DeclareTimer FTM_STATESORT;
|
||||
static DeclareTimer FTM_STATESORT_DRAWABLE;
|
||||
static DeclareTimer FTM_STATESORT_POSTSORT;
|
||||
static DeclareTimer FTM_SWAP;
|
||||
static DeclareTimer FTM_TEMP1;
|
||||
static DeclareTimer FTM_TEMP2;
|
||||
static DeclareTimer FTM_TEMP3;
|
||||
static DeclareTimer FTM_TEMP4;
|
||||
static DeclareTimer FTM_TEMP5;
|
||||
static DeclareTimer FTM_TEMP6;
|
||||
static DeclareTimer FTM_TEMP7;
|
||||
static DeclareTimer FTM_TEMP8;
|
||||
static DeclareTimer FTM_UPDATE_ANIMATION;
|
||||
static DeclareTimer FTM_UPDATE_AVATAR;
|
||||
static DeclareTimer FTM_UPDATE_CLOUDS;
|
||||
static DeclareTimer FTM_UPDATE_GRASS;
|
||||
static DeclareTimer FTM_UPDATE_MOVE;
|
||||
static DeclareTimer FTM_UPDATE_PARTICLES;
|
||||
static DeclareTimer FTM_UPDATE_PRIMITIVES;
|
||||
static DeclareTimer FTM_UPDATE_SKY;
|
||||
static DeclareTimer FTM_UPDATE_TERRAIN;
|
||||
static DeclareTimer FTM_UPDATE_TEXTURES;
|
||||
static DeclareTimer FTM_UPDATE_TREE;
|
||||
static DeclareTimer FTM_UPDATE_WATER;
|
||||
static DeclareTimer FTM_UPDATE_WLPARAM;
|
||||
static DeclareTimer FTM_VFILE_WAIT;
|
||||
static DeclareTimer FTM_WORLD_UPDATE;
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
~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);
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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_*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class LLLogImpl;
|
|||
class LLApp;
|
||||
class LLSD;
|
||||
|
||||
class LLLog
|
||||
class LL_COMMON_API LLLog
|
||||
{
|
||||
public:
|
||||
LLLog(LLApp* app);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
class LLMetricsImpl;
|
||||
class LLSD;
|
||||
|
||||
class LLMetrics
|
||||
class LL_COMMON_API LLMetrics
|
||||
{
|
||||
public:
|
||||
LLMetrics();
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
#include "stdtypes.h"
|
||||
|
||||
class LLMortician
|
||||
class LL_COMMON_API LLMortician
|
||||
{
|
||||
public:
|
||||
LLMortician() { mIsDead = FALSE; }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@
|
|||
// see llthread.h for LLThreadSafeRefCount
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class LLRefCount
|
||||
class LL_COMMON_API LLRefCount
|
||||
{
|
||||
protected:
|
||||
private:
|
||||
LLRefCount(const LLRefCount&); // not implemented
|
||||
private:
|
||||
LLRefCount&operator=(const LLRefCount&); // not implemented
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ public:
|
|||
};
|
||||
|
||||
template <typename HASH_KEY_TYPE, int TABLE_SIZE>
|
||||
class LLSimpleHash
|
||||
class LL_COMMON_API LLSimpleHash
|
||||
{
|
||||
public:
|
||||
LLSimpleHash()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class LLApp;
|
|||
* See: http://www.ietf.org/rfc/rfc3986.txt
|
||||
*
|
||||
*/
|
||||
class LLURI
|
||||
class LL_COMMON_API LLURI
|
||||
{
|
||||
public:
|
||||
LLURI();
|
||||
|
|
|
|||
|
|
@ -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() { }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
class LLReflective;
|
||||
class LLMetaProperty;
|
||||
class LLMetaMethod;
|
||||
class LLMetaClass
|
||||
class LL_COMMON_API LLMetaClass
|
||||
{
|
||||
public:
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
#define LL_REFLECTIVE_H
|
||||
|
||||
class LLMetaClass;
|
||||
class LLReflective
|
||||
class LL_COMMON_API LLReflective
|
||||
{
|
||||
public:
|
||||
LLReflective();
|
||||
|
|
|
|||
|
|
@ -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) */
|
||||
|
|
|
|||
|
|
@ -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) */
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
|
@ -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) */
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ set(llmath_HEADER_FILES
|
|||
llv4vector3.h
|
||||
llvolume.h
|
||||
llvolumemgr.h
|
||||
llsdutil_math.h
|
||||
m3math.h
|
||||
m4math.h
|
||||
raytrace.h
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llsdutil.h"
|
||||
#include "llsdutil_math.h"
|
||||
|
||||
#include "v3math.h"
|
||||
#include "v4math.h"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,7 +36,13 @@
|
|||
#define LL_LLARES_H
|
||||
|
||||
#ifdef LL_WINDOWS
|
||||
// ares.h is broken on windows in that it depends on types defined in ws2tcpip.h
|
||||
// we need to include them first to work around it, but the headers issue warnings
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4996)
|
||||
# include <winsock2.h>
|
||||
# include <ws2tcpip.h>
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#ifdef LL_STANDALONE
|
||||
|
|
@ -49,7 +55,10 @@
|
|||
#include "llrefcount.h"
|
||||
#include "lluri.h"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
class LLQueryResponder;
|
||||
class LLAresListener;
|
||||
|
||||
/**
|
||||
* @brief Supported DNS RR types.
|
||||
|
|
@ -444,6 +453,9 @@ public:
|
|||
protected:
|
||||
ares_channel chan_;
|
||||
bool mInitSuccess;
|
||||
// boost::scoped_ptr would actually fit the requirement better, but it
|
||||
// can't handle incomplete types as boost::shared_ptr can.
|
||||
boost::shared_ptr<LLAresListener> mListener;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* @file llareslistener.cpp
|
||||
* @author Nat Goodspeed
|
||||
* @date 2009-03-18
|
||||
* @brief Implementation for llareslistener.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewergpl$
|
||||
* Copyright (c) 2009, Linden Research, Inc.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// Precompiled header
|
||||
#include "linden_common.h"
|
||||
// associated header
|
||||
#include "llareslistener.h"
|
||||
// STL headers
|
||||
// std headers
|
||||
// external library headers
|
||||
// other Linden headers
|
||||
#include "llares.h"
|
||||
#include "llerror.h"
|
||||
#include "llevents.h"
|
||||
#include "llsdutil.h"
|
||||
|
||||
LLAresListener::LLAresListener(const std::string& pumpname, LLAres* llares):
|
||||
LLDispatchListener(pumpname, "op"),
|
||||
mAres(llares)
|
||||
{
|
||||
// add() every method we want to be able to invoke via this event API.
|
||||
// Optional third parameter validates expected LLSD request structure.
|
||||
add("rewriteURI", &LLAresListener::rewriteURI,
|
||||
LLSD().insert("uri", LLSD()).insert("reply", LLSD()));
|
||||
}
|
||||
|
||||
/// This UriRewriteResponder subclass packages returned URIs as an LLSD
|
||||
/// array to send back to the requester.
|
||||
class UriRewriteResponder: public LLAres::UriRewriteResponder
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Specify the request, containing the event pump name on which to send
|
||||
* the reply.
|
||||
*/
|
||||
UriRewriteResponder(const LLSD& request):
|
||||
mReqID(request),
|
||||
mPumpName(request["reply"])
|
||||
{}
|
||||
|
||||
/// Called by base class with results. This is called in both the
|
||||
/// success and error cases. On error, the calling logic passes the
|
||||
/// original URI.
|
||||
virtual void rewriteResult(const std::vector<std::string>& uris)
|
||||
{
|
||||
LLSD result;
|
||||
for (std::vector<std::string>::const_iterator ui(uris.begin()), uend(uris.end());
|
||||
ui != uend; ++ui)
|
||||
{
|
||||
result.append(*ui);
|
||||
}
|
||||
// This call knows enough to avoid trying to insert a map key into an
|
||||
// LLSD array. It's there so that if, for any reason, we ever decide
|
||||
// to change the response from array to map, it will Just Start Working.
|
||||
mReqID.stamp(result);
|
||||
LLEventPumps::instance().obtain(mPumpName).post(result);
|
||||
}
|
||||
|
||||
private:
|
||||
LLReqID mReqID;
|
||||
const std::string mPumpName;
|
||||
};
|
||||
|
||||
void LLAresListener::rewriteURI(const LLSD& data)
|
||||
{
|
||||
mAres->rewriteURI(data["uri"], new UriRewriteResponder(data));
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* @file llareslistener.h
|
||||
* @author Nat Goodspeed
|
||||
* @date 2009-03-18
|
||||
* @brief LLEventPump API for LLAres. This header doesn't actually define the
|
||||
* API; the API is defined by the pump name on which this class
|
||||
* listens, and by the expected content of LLSD it receives.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewergpl$
|
||||
* Copyright (c) 2009, Linden Research, Inc.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#if ! defined(LL_LLARESLISTENER_H)
|
||||
#define LL_LLARESLISTENER_H
|
||||
|
||||
#include "lleventdispatcher.h"
|
||||
|
||||
class LLAres;
|
||||
class LLSD;
|
||||
|
||||
/// Listen on an LLEventPump with specified name for LLAres request events.
|
||||
class LLAresListener: public LLDispatchListener
|
||||
{
|
||||
public:
|
||||
/// Specify the pump name on which to listen, and bind the LLAres instance
|
||||
/// to use (e.g. gAres)
|
||||
LLAresListener(const std::string& pumpname, LLAres* llares);
|
||||
|
||||
private:
|
||||
/// command["op"] == "rewriteURI"
|
||||
void rewriteURI(const LLSD& data);
|
||||
|
||||
LLAres* mAres;
|
||||
};
|
||||
|
||||
#endif /* ! defined(LL_LLARESLISTENER_H) */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue