diff --git a/doc/contributions.txt b/doc/contributions.txt
index 6c39a77dd..258e139bc 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -4,6 +4,10 @@ along with the issue identifier corresponding to the patches we've
received from them. To see more about these contributions, visit the
browsable version: http://wiki.secondlife.com/wiki/Source_contributions
+Entries are related to URLs as follows:
+IMP-xxx: http://redmine.kokuaviewer.org/issues/xxx
+Everything else ([VWR|SNOW|CT|SVC|WEB]-xxx): https://jira.secondlife.com/browse/KEY-xxx
+
Able Whitman
VWR-650
VWR-1460
@@ -58,12 +62,18 @@ Aimee Trescothick
Alejandro Rosenthal
VWR-1184
Aleric Inglewood
+ VWR-10579 (IMP-552)
VWR-10759
VWR-10837
VWR-12984
+ VWR-13040 (IMP-575)
VWR-13996
VWR-14426
VWR-14914
+ VWR-24247
+ VWR-24312
+ VWR-24320
+ VWR-24333
SNOW-47
SNOW-84
SNOW-86
@@ -72,18 +82,37 @@ Aleric Inglewood
SNOW-129
SNOW-196
SNOW-203
+ SNOW-240
SNOW-408
- SNOW-415
+ SNOW-415 (IMP-576)
+ SNOW-477 (IMP-577)
SNOW-479
SNOW-626
- SNOW-713
- SNOW-744
- SNOW-751
+ SNOW-713 (IMP-692)
+ SNOW-744 (IMP-578)
SNOW-752
SNOW-753
+ SNOW-766 (IMP-553)
SNOW-772
SNOW-793
+ SNOW-796 (IMP-581)
+ SNOW-800 (IMP-556)
SNOW-806
+ IMP-429
+ IMP-561
+ IMP-565
+ IMP-566
+ IMP-567
+ IMP-573
+ IMP-590
+ IMP-660
+ IMP-661
+ IMP-662
+ IMP-663
+ IMP-664
+ IMP-670
+ IMP-701
+ IMP-734
Alissa Sabre
VWR-81
VWR-83
@@ -105,7 +134,7 @@ Alissa Sabre
VWR-1351
VWR-1353
VWR-1410
- VWR-1843
+ VWR-1843
VWR-2116
VWR-2826
VWR-3290
@@ -113,17 +142,17 @@ Alissa Sabre
VWR-3857
VWR-4010
VWR-5575
- VWR-5929
- VWR-6384
- VWR-6385
+ VWR-5929
+ VWR-6384
+ VWR-6385
VWR-6386
- VWR-6430
+ VWR-6430
VWR-6858
- VWR-6668
- VWR-7086
- VWR-7087
- VWR-7153
- VWR-7168
+ VWR-6668
+ VWR-7086
+ VWR-7087
+ VWR-7153
+ VWR-7168
VWR-9190
VWR-10728
VWR-12620
@@ -181,6 +210,7 @@ Boroondas Gupte
SNOW-201
SNOW-396
SNOW-589
+ SNOW-623 (IMP-554)
SNOW-624
VWR-233
WEB-262
@@ -549,7 +579,7 @@ Pf Shan
CT-321
princess niven
VWR-5733
- CT-85
+ CT-85
CT-320
CT-352
Renault Clio
@@ -590,6 +620,7 @@ Robin Cornelius
VWR-11128
VWR-12758
VWR-12686
+ VWR-12838
Ryozu Kojima
VWR-53
VWR-287
@@ -788,4 +819,3 @@ Zi Ree
Zipherius Turas
VWR-76
VWR-77
-
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 65dfab0dc..4b2f9dc4b 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -208,10 +208,18 @@ if (LINUX)
# this stops us requiring a really recent glibc at runtime
add_definitions(-fno-stack-protector)
endif (NOT STANDALONE)
- set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2} -march=pentium4 -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
- set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2} -march=pentium4 -mfpmath=sse -msse2 "${GCC_EXTRA_OPTIMIZATIONS})
- set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -march=pentium4 -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
- set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 ${CMAKE_C_FLAGS_RELWITHDEBINFO} -march=pentium4 -mfpmath=sse -msse2 "${GCC_EXTRA_OPTIMIZATIONS})
+ if (${ARCH} STREQUAL "x86_64")
+ add_definitions(-DLINUX64=1 -pipe)
+ set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
+ set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
+ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
+ set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
+ else (${ARCH} STREQUAL "x86_64")
+ set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2} -march=pentium4 -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
+ set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2} -march=pentium4 -mfpmath=sse -msse2 "${GCC_EXTRA_OPTIMIZATIONS})
+ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -march=pentium4 -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
+ set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -march=pentium4 -mfpmath=sse -msse2 "${GCC_EXTRA_OPTIMIZATIONS})
+ endif (${ARCH} STREQUAL "x86_64")
endif (VIEWER)
set(CMAKE_CXX_FLAGS_DEBUG "-fno-inline ${CMAKE_CXX_FLAGS_DEBUG}")
@@ -219,6 +227,8 @@ if (LINUX)
set(CMAKE_C_FLAGS_RELEASE "-O3 ${CMAKE_C_FLAGS_RELEASE}")
set(CMAKE_CXX_FLAGS_RELEASESSE2 "-O3 ${CMAKE_CXX_FLAGS_RELEASESSE2}")
set(CMAKE_C_FLAGS_RELEASESSE2 "-O3 ${CMAKE_C_FLAGS_RELEASESSE2}")
+ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
+ set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 ${CMAKE_C_FLAGS_RELWITHDEBINFO}")
endif (LINUX)
diff --git a/indra/cmake/APR.cmake b/indra/cmake/APR.cmake
index 5cd150d58..d1f089891 100644
--- a/indra/cmake/APR.cmake
+++ b/indra/cmake/APR.cmake
@@ -14,16 +14,18 @@ else (STANDALONE)
use_prebuilt_binary(apr_suite)
if (WINDOWS)
set(APR_LIBRARIES
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/apr-1.lib
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/apr-1.lib
+ debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.lib
+ optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.lib
)
set(APRICONV_LIBRARIES
debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapriconv-1.lib
optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapriconv-1.lib
)
+ # Doesn't need to link with iconv.dll
+ set(APRICONV_LIBRARIES "")
set(APRUTIL_LIBRARIES
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/aprutil-1.lib
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/aprutil-1.lib
+ debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.lib ${APRICONV_LIBRARIES}
+ optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.lib ${APRICONV_LIBRARIES}
)
elseif (DARWIN)
set(APR_LIBRARIES
@@ -41,9 +43,8 @@ else (STANDALONE)
set(APRICONV_LIBRARIES iconv)
endif (WINDOWS)
set(APR_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/apr-1)
- set(APRUTIL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/apr-1)
if (LINUX AND VIEWER)
- list(APPEND APRUTIL_LIBRARIES ${DB_LIBRARIES} uuid)
+ list(APPEND APRUTIL_LIBRARIES ${DB_LIBRARIES})
endif (LINUX AND VIEWER)
endif (STANDALONE)
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 6b9e342f4..b7ec75f54 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -35,7 +35,6 @@ set(cmake_SOURCE_FILES
FindNDOF.cmake
FindOpenJPEG.cmake
FindXmlRpcEpi.cmake
- FindMyZLIB.cmake
FMOD.cmake
FreeType.cmake
GStreamer010Plugin.cmake
diff --git a/indra/cmake/FindMyZLIB.cmake b/indra/cmake/FindMyZLIB.cmake
deleted file mode 100644
index 6d630f1ba..000000000
--- a/indra/cmake/FindMyZLIB.cmake
+++ /dev/null
@@ -1,46 +0,0 @@
-# -*- cmake -*-
-
-# - Find zlib
-# Find the ZLIB includes and library
-# This module defines
-# ZLIB_INCLUDE_DIRS, where to find zlib.h, etc.
-# ZLIB_LIBRARIES, the libraries needed to use zlib.
-# ZLIB_FOUND, If false, do not try to use zlib.
-#
-# This FindZLIB is about 43 times as fast the one provided with cmake (2.8.x),
-# because it doesn't look up the version of zlib, resulting in a dramatic
-# speed up for configure (from 4 minutes 22 seconds to 6 seconds).
-#
-# Note: Since this file is only used for standalone, the windows
-# specific parts were left out.
-
-FIND_PATH(ZLIB_INCLUDE_DIR zlib.h
- NO_SYSTEM_ENVIRONMENT_PATH
- )
-
-FIND_LIBRARY(ZLIB_LIBRARY z)
-
-if (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
- SET(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR})
- SET(ZLIB_LIBRARIES ${ZLIB_LIBRARY})
- SET(ZLIB_FOUND "YES")
-else (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
- SET(ZLIB_FOUND "NO")
-endif (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
-
-if (ZLIB_FOUND)
- if (NOT ZLIB_FIND_QUIETLY)
- message(STATUS "Found ZLIB: ${ZLIB_LIBRARIES}")
- SET(ZLIB_FIND_QUIETLY TRUE)
- endif (NOT ZLIB_FIND_QUIETLY)
-else (ZLIB_FOUND)
- if (ZLIB_FIND_REQUIRED)
- message(FATAL_ERROR "Could not find ZLIB library")
- endif (ZLIB_FIND_REQUIRED)
-endif (ZLIB_FOUND)
-
-mark_as_advanced(
- ZLIB_LIBRARY
- ZLIB_INCLUDE_DIR
- )
-
diff --git a/indra/cmake/GooglePerfTools.cmake b/indra/cmake/GooglePerfTools.cmake
index a5f957a20..0b483e5cf 100644
--- a/indra/cmake/GooglePerfTools.cmake
+++ b/indra/cmake/GooglePerfTools.cmake
@@ -25,9 +25,11 @@ else (STANDALONE)
endif (LINUX)
endif (STANDALONE)
-#if (GOOGLE_PERFTOOLS_FOUND)
-# set(USE_GOOGLE_PERFTOOLS ON CACHE BOOL "Build with Google PerfTools support.")
-#endif (GOOGLE_PERFTOOLS_FOUND)
+if (GOOGLE_PERFTOOLS_FOUND)
+ set(USE_GOOGLE_PERFTOOLS ON CACHE BOOL "Build with Google PerfTools support.")
+else (GOOGLE_PERFTOOLS_FOUND)
+ set(USE_GOOGLE_PERFTOOLS OFF)
+endif (GOOGLE_PERFTOOLS_FOUND)
# XXX Disable temporarily, until we have compilation issues on 64-bit
# Etch sorted.
@@ -41,7 +43,7 @@ else (USE_GOOGLE_PERFTOOLS)
set(TCMALLOC_FLAG -ULL_USE_TCMALLOC)
endif (USE_GOOGLE_PERFTOOLS)
-if (NOT(DISABLE_TCMALLOC OR USE_GOOGLE_PERFTOOLS))
+if (NOT(DISABLE_TCMALLOC OR NOT USE_GOOGLE_PERFTOOLS))
message(STATUS "Building with Google TCMalloc")
set(TCMALLOC_FLAG -DLL_USE_TCMALLOC=1_)
include_directories(${GOOGLE_PERFTOOLS_INCLUDE_DIR})
diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake
index 410766e4f..2862ba7f0 100644
--- a/indra/cmake/LLCommon.cmake
+++ b/indra/cmake/LLCommon.cmake
@@ -7,7 +7,6 @@ include(ZLIB)
set(LLCOMMON_INCLUDE_DIRS
${LIBS_OPEN_DIR}/llcommon
- ${APRUTIL_INCLUDE_DIR}
${APR_INCLUDE_DIR}
${Boost_INCLUDE_DIRS}
)
diff --git a/indra/cmake/Prebuilt.cmake b/indra/cmake/Prebuilt.cmake
index 6dd9c47bd..a91519278 100644
--- a/indra/cmake/Prebuilt.cmake
+++ b/indra/cmake/Prebuilt.cmake
@@ -1,11 +1,44 @@
# -*- cmake -*-
+include(Python)
+include(FindSCP)
+
macro (use_prebuilt_binary _binary)
- if(NOT STANDALONE)
- get_property(PREBUILT_PACKAGES TARGET prepare PROPERTY PREBUILT)
- list(FIND PREBUILT_PACKAGES ${_binary} _index)
- if(_index LESS 0)
- set_property(TARGET prepare APPEND PROPERTY PREBUILT ${_binary})
- endif(_index LESS 0)
- endif(NOT STANDALONE)
+ if (NOT STANDALONE)
+ if(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed)
+ if(INSTALL_PROPRIETARY)
+ include(FindSCP)
+ if(DEBUG_PREBUILT)
+ message("cd ${SCRIPTS_DIR} && ${PYTHON_EXECUTABLE} install.py --install-dir=${CMAKE_SOURCE_DIR}/.. --scp=${SCP_EXECUTABLE} ${_binary}")
+ endif(DEBUG_PREBUILT)
+ execute_process(COMMAND ${PYTHON_EXECUTABLE}
+ install.py
+ --install-dir=${CMAKE_SOURCE_DIR}/..
+ --scp=${SCP_EXECUTABLE}
+ ${_binary}
+ WORKING_DIRECTORY ${SCRIPTS_DIR}
+ RESULT_VARIABLE ${_binary}_installed
+ )
+ else(INSTALL_PROPRIETARY)
+ if(DEBUG_PREBUILT)
+ message("cd ${SCRIPTS_DIR} && ${PYTHON_EXECUTABLE} install.py --install-dir=${CMAKE_SOURCE_DIR}/.. ${_binary}")
+ endif(DEBUG_PREBUILT)
+ execute_process(COMMAND ${PYTHON_EXECUTABLE}
+ install.py
+ --install-dir=${CMAKE_SOURCE_DIR}/..
+ ${_binary}
+ WORKING_DIRECTORY ${SCRIPTS_DIR}
+ RESULT_VARIABLE ${_binary}_installed
+ )
+ endif(INSTALL_PROPRIETARY)
+ 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_prebuilt_binary _binary)
diff --git a/indra/cmake/UI.cmake b/indra/cmake/UI.cmake
index 6067602d5..64fa85ff2 100644
--- a/indra/cmake/UI.cmake
+++ b/indra/cmake/UI.cmake
@@ -42,6 +42,7 @@ else (STANDALONE)
gdk_pixbuf-2.0
Xinerama
glib-2.0
+ gio-2.0
gmodule-2.0
gobject-2.0
gthread-2.0
diff --git a/indra/cmake/ViewerMiscLibs.cmake b/indra/cmake/ViewerMiscLibs.cmake
index 746de0fe9..38d044473 100644
--- a/indra/cmake/ViewerMiscLibs.cmake
+++ b/indra/cmake/ViewerMiscLibs.cmake
@@ -2,10 +2,25 @@
include(Prebuilt)
if (NOT STANDALONE)
+ use_prebuilt_binary(libuuid)
use_prebuilt_binary(vivox)
- if (LINUX)
- #use_prebuilt_binary(libuuid)
+ if(LINUX)
+ if (${ARCH} STREQUAL "x86_64")
+ use_prebuilt_binary(32bitcompatibilitylibs)
+ endif (${ARCH} STREQUAL "x86_64")
use_prebuilt_binary(fontconfig)
- endif (LINUX)
+ endif(LINUX)
+else (NOT STANDALONE)
+ # Download there even when using standalone.
+ set(STANDALONE OFF)
+ use_prebuilt_binary(vivox)
+ if(LINUX AND ${ARCH} STREQUAL "x86_64")
+ use_prebuilt_binary(32bitcompatibilitylibs)
+ endif(LINUX AND ${ARCH} STREQUAL "x86_64")
+ set(STANDALONE ON)
endif(NOT STANDALONE)
+if (WINDOWS)
+ use_prebuilt_binary(dbghelp)
+endif (WINDOWS)
+
diff --git a/indra/cmake/WebKitLibPlugin.cmake b/indra/cmake/WebKitLibPlugin.cmake
index 44f5619e1..a4befa495 100644
--- a/indra/cmake/WebKitLibPlugin.cmake
+++ b/indra/cmake/WebKitLibPlugin.cmake
@@ -3,7 +3,29 @@ include(Linking)
include(Prebuilt)
if (STANDALONE)
- find_package(LLQtWebkit REQUIRED)
+ # The minimal version, 4.4.3, is rather arbitrary: it's the version in Debian/Lenny.
+ find_package(Qt4 4.4.3 COMPONENTS QtCore QtGui QtNetwork QtOpenGL QtWebKit REQUIRED)
+ include(${QT_USE_FILE})
+ set(QTDIR $ENV{QTDIR})
+ if (QTDIR AND NOT "${QT_BINARY_DIR}" STREQUAL "${QTDIR}/bin")
+ message(FATAL_ERROR "\"${QT_BINARY_DIR}\" is unequal \"${QTDIR}/bin\"; "
+ "Qt is found by looking for qmake in your PATH. "
+ "Please set your PATH such that 'qmake' is found in \$QTDIR/bin, "
+ "or unset QTDIR if the found Qt is correct.")
+ endif (QTDIR AND NOT "${QT_BINARY_DIR}" STREQUAL "${QTDIR}/bin")
+ find_package(LLQtWebkit REQUIRED QUIET)
+ # Add the plugins.
+ set(QT_PLUGIN_LIBRARIES)
+ foreach(qlibname qgif qjpeg)
+ find_library(QT_PLUGIN_${qlibname} ${qlibname} PATHS ${QT_PLUGINS_DIR}/imageformats NO_DEFAULT_PATH)
+ if (QT_PLUGIN_${qlibname})
+ list(APPEND QT_PLUGIN_LIBRARIES ${QT_PLUGIN_${qlibname}})
+ else (QT_PLUGIN_${qtlibname})
+ message(FATAL_ERROR "Could not find the Qt plugin ${qlibname} in \"${QT_PLUGINS_DIR}/imageformats\"!")
+ endif (QT_PLUGIN_${qlibname})
+ endforeach(qlibname)
+ # qjpeg depends on libjpeg
+ list(APPEND QT_PLUGIN_LIBRARIES jpeg)
set(WEBKITLIBPLUGIN OFF CACHE BOOL
"WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.")
else (STANDALONE)
@@ -32,25 +54,26 @@ if (WINDOWS)
elseif (DARWIN)
set(WEBKIT_PLUGIN_LIBRARIES
optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib
- debug ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib
+ debug ${ARCH_PREBUILT_DIRS_DEBUG}/libllqtwebkit.dylib
)
elseif (LINUX)
- if (STANDALONE)
- set(WEBKIT_PLUGIN_LIBRARIES ${LLQTWEBKIT_LIBRARY})
- else (STANDALONE)
+ if (STANDALONE)
+ set(WEBKIT_PLUGIN_LIBRARIES ${LLQTWEBKIT_LIBRARY} ${QT_LIBRARIES} ${QT_PLUGIN_LIBRARIES})
+ else (STANDALONE)
set(WEBKIT_PLUGIN_LIBRARIES
- llqtwebkit
- qgif
- qjpeg
- QtWebKit
- QtOpenGL
- QtNetwork
- QtGui
- QtCore
- fontconfig
- X11
- Xrender
- GL
- )
- endif (STANDALONE)
+ llqtwebkit
+ qgif
+ qjpeg
+ QtWebKit
+ QtOpenGL
+ QtNetwork
+ QtGui
+ QtCore
+ jpeg
+ fontconfig
+ X11
+ Xrender
+ GL
+ )
+ endif (STANDALONE)
endif (WINDOWS)
diff --git a/indra/cmake/ZLIB.cmake b/indra/cmake/ZLIB.cmake
index c233b3eec..48e5130ad 100644
--- a/indra/cmake/ZLIB.cmake
+++ b/indra/cmake/ZLIB.cmake
@@ -6,7 +6,7 @@ set(ZLIB_FIND_REQUIRED ON)
include(Prebuilt)
if (STANDALONE)
- include(FindMyZLIB)
+ include(FindZLIB)
else (STANDALONE)
use_prebuilt_binary(zlib)
if (WINDOWS)
diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py
index bfac97981..585b47d4a 100644
--- a/indra/lib/python/indra/util/llmanifest.py
+++ b/indra/lib/python/indra/util/llmanifest.py
@@ -119,6 +119,7 @@ ARGUMENTS=[
Example use: %(name)s --arch=i686
On Linux this would try to use Linux_i686Manifest.""",
default=""),
+ dict(name='artwork', description='Artwork directory.', default=DEFAULT_SRCTREE),
dict(name='build', description='Build directory.', default=DEFAULT_SRCTREE),
dict(name='buildtype', description="""The build type used. ('Debug', 'Release', 'ReleaseSSE2' or 'RelWithDebInfo')
Default is Release """,
@@ -126,6 +127,9 @@ ARGUMENTS=[
dict(name='branding_id', description="""Identifier for the branding set to
use. Currently, 'secondlife' or 'snowglobe')""",
default='secondlife'),
+ dict(name='channel',
+ description="""The channel to use for updates, packaging, settings name, etc.""",
+ default=get_channel),
dict(name='configuration',
description="""The build configuration used. Only used on OS X for
now, but it could be used for other platforms as well.""",
@@ -136,16 +140,13 @@ ARGUMENTS=[
though it's not strictly a grid, 'firstlook' is also an acceptable
value for this parameter.""",
default=""),
- dict(name='channel',
- description="""The channel to use for updates, packaging, settings name, etc.""",
- default=get_channel),
- dict(name='login_channel',
- description="""The channel to use for login handshake/updates only.""",
- default=None),
dict(name='installer_name',
description=""" The name of the file that the installer should be
packaged up into. Only used on Linux at the moment.""",
default=None),
+ dict(name='login_channel',
+ description="""The channel to use for login handshake/updates only.""",
+ default=None),
dict(name='login_url',
description="""The url that the login screen displays in the client.""",
default=None),
@@ -156,7 +157,9 @@ ARGUMENTS=[
dict(name='source',
description='Source directory.',
default=DEFAULT_SRCTREE),
- dict(name='artwork', description='Artwork directory.', default=DEFAULT_SRCTREE),
+ dict(name='standalone',
+ description='Set to ON if this is a standalone build.',
+ default="OFF"),
dict(name='touch',
description="""File to touch when action is finished. Touch file will
contain the name of the final package in a form suitable
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index ca26d492a..7f352269b 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -13,6 +13,7 @@ include_directories(
)
set(llcommon_SOURCE_FILES
+ aiaprpool.cpp
imageids.cpp
indra_constants.cpp
llapp.cpp
@@ -78,6 +79,8 @@ set(llcommon_SOURCE_FILES
set(llcommon_HEADER_FILES
CMakeLists.txt
+ aiaprpool.h
+ aithreadsafe.h
bitpack.h
ctype_workaround.h
doublelinkedlist.h
@@ -155,6 +158,7 @@ set(llcommon_HEADER_FILES
llqueuedthread.h
llrand.h
llrun.h
+ llscopedvolatileaprpool.h
llsd.h
llsdserialize.h
llsdserialize_xml.h
@@ -201,7 +205,7 @@ set_source_files_properties(${llcommon_HEADER_FILES}
list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES})
-add_library (llcommon ${llcommon_SOURCE_FILES})
+add_library (llcommon SHARED ${llcommon_SOURCE_FILES})
add_dependencies(llcommon prepare)
target_link_libraries(
llcommon
diff --git a/indra/llcommon/aiaprpool.cpp b/indra/llcommon/aiaprpool.cpp
new file mode 100644
index 000000000..d3748e983
--- /dev/null
+++ b/indra/llcommon/aiaprpool.cpp
@@ -0,0 +1,198 @@
+/**
+ * @file aiaprpool.cpp
+ *
+ * Copyright (c) 2010, Aleric Inglewood.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution.
+ *
+ * CHANGELOG
+ * and additional copyright holders.
+ *
+ * 04/04/2010
+ * - Initial version, written by Aleric Inglewood @ SL
+ *
+ * 10/11/2010
+ * - Changed filename, class names and license to a more
+ * company-neutral format.
+ * - Added APR_HAS_THREADS #if's to allow creation and destruction
+ * of subpools by threads other than the parent pool owner.
+ */
+
+#include "linden_common.h"
+
+#include "llerror.h"
+#include "aiaprpool.h"
+#include "llthread.h"
+
+// Create a subpool from parent.
+void AIAPRPool::create(AIAPRPool& parent)
+{
+ llassert(!mPool); // Must be non-initialized.
+ mParent = &parent;
+ if (!mParent) // Using the default parameter?
+ {
+ // By default use the root pool of the current thread.
+ mParent = &AIThreadLocalData::tldata().mRootPool;
+ }
+ llassert(mParent->mPool); // Parent must be initialized.
+#if APR_HAS_THREADS
+ // As per the documentation of APR (ie http://apr.apache.org/docs/apr/1.4/apr__pools_8h.html):
+ //
+ // Note that most operations on pools are not thread-safe: a single pool should only be
+ // accessed by a single thread at any given time. The one exception to this rule is creating
+ // a subpool of a given pool: one or more threads can safely create subpools at the same
+ // time that another thread accesses the parent pool.
+ //
+ // In other words, it's safe for any thread to create a (sub)pool, independent of who
+ // owns the parent pool.
+ mOwner = apr_os_thread_current();
+#else
+ mOwner = mParent->mOwner;
+ llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
+#endif
+ apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, mParent->mPool);
+ llassert_always(apr_pool_create_status == APR_SUCCESS);
+ llassert(mPool); // Initialized.
+ apr_pool_cleanup_register(mPool, this, &s_plain_cleanup, &apr_pool_cleanup_null);
+}
+
+// Destroy the (sub)pool, if any.
+void AIAPRPool::destroy(void)
+{
+ // Only do anything if we are not already (being) destroyed.
+ if (mPool)
+ {
+#if !APR_HAS_THREADS
+ // If we are a root pool, then every thread may destruct us: in that case
+ // we have to assume that no other thread will use this pool concurrently,
+ // of course. Otherwise, if we are a subpool, only the thread that owns
+ // the parent may destruct us, since that is the pool that is still alive,
+ // possibly being used by others and being altered here.
+ llassert(!mParent || apr_os_thread_equal(mParent->mOwner, apr_os_thread_current()));
+#endif
+ apr_pool_t* pool = mPool;
+ mPool = NULL; // Mark that we are BEING destructed.
+ apr_pool_cleanup_kill(pool, this, &s_plain_cleanup);
+ apr_pool_destroy(pool);
+ }
+}
+
+bool AIAPRPool::parent_is_being_destructed(void)
+{
+ return mParent && (!mParent->mPool || mParent->parent_is_being_destructed());
+}
+
+AIAPRInitialization::AIAPRInitialization(void)
+{
+ static bool apr_initialized = false;
+
+ if (!apr_initialized)
+ {
+ apr_initialize();
+ }
+
+ apr_initialized = true;
+}
+
+bool AIAPRRootPool::sCountInitialized = false;
+apr_uint32_t volatile AIAPRRootPool::sCount;
+
+extern apr_thread_mutex_t* gLogMutexp;
+extern apr_thread_mutex_t* gCallStacksLogMutexp;
+
+AIAPRRootPool::AIAPRRootPool(void) : AIAPRInitialization(), AIAPRPool(0)
+{
+ // sCountInitialized don't need locking because when we get here there is still only a single thread.
+ if (!sCountInitialized)
+ {
+ // Initialize the logging mutex
+ apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, mPool);
+ apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, mPool);
+
+ apr_status_t status = apr_atomic_init(mPool);
+ llassert_always(status == APR_SUCCESS);
+ apr_atomic_set32(&sCount, 1); // Set to 1 to account for the global root pool.
+ sCountInitialized = true;
+
+ // Initialize thread-local APR pool support.
+ // Because this recursively calls AIAPRRootPool::AIAPRRootPool(void)
+ // it must be done last, so that sCount is already initialized.
+ AIThreadLocalData::init();
+ }
+ apr_atomic_inc32(&sCount);
+}
+
+AIAPRRootPool::~AIAPRRootPool()
+{
+ if (!apr_atomic_dec32(&sCount))
+ {
+ // The last pool was destructed. Cleanup remainder of APR.
+ LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL;
+
+ if (gLogMutexp)
+ {
+ // Clean up the logging mutex
+
+ // All other threads NEED to be done before we clean up APR, so this is okay.
+ apr_thread_mutex_destroy(gLogMutexp);
+ gLogMutexp = NULL;
+ }
+ if (gCallStacksLogMutexp)
+ {
+ // Clean up the logging mutex
+
+ // All other threads NEED to be done before we clean up APR, so this is okay.
+ apr_thread_mutex_destroy(gCallStacksLogMutexp);
+ gCallStacksLogMutexp = NULL;
+ }
+
+ // Must destroy ALL, and therefore this last AIAPRRootPool, before terminating APR.
+ static_cast(this)->destroy();
+
+ apr_terminate();
+ }
+}
+
+//static
+AIAPRRootPool& AIAPRRootPool::get(void)
+{
+ static AIAPRRootPool global_APRpool(0); // This is what used to be gAPRPoolp.
+ return global_APRpool;
+}
+
+void AIVolatileAPRPool::clearVolatileAPRPool()
+{
+ llassert_always(mNumActiveRef > 0);
+ if (--mNumActiveRef == 0)
+ {
+ if (isOld())
+ {
+ destroy();
+ mNumTotalRef = 0 ;
+ }
+ else
+ {
+ // This does not actually free the memory,
+ // it just allows the pool to re-use this memory for the next allocation.
+ clear();
+ }
+ }
+
+ // Paranoia check if the pool is jammed.
+ llassert(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ;
+}
diff --git a/indra/llcommon/aiaprpool.h b/indra/llcommon/aiaprpool.h
new file mode 100644
index 000000000..72e9ddbd4
--- /dev/null
+++ b/indra/llcommon/aiaprpool.h
@@ -0,0 +1,238 @@
+/**
+ * @file aiaprpool.h
+ * @brief Implementation of AIAPRPool.
+ *
+ * Copyright (c) 2010, Aleric Inglewood.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution.
+ *
+ * CHANGELOG
+ * and additional copyright holders.
+ *
+ * 04/04/2010
+ * - Initial version, written by Aleric Inglewood @ SL
+ *
+ * 10/11/2010
+ * - Changed filename, class names and license to a more
+ * company-neutral format.
+ * - Added APR_HAS_THREADS #if's to allow creation and destruction
+ * of subpools by threads other than the parent pool owner.
+ */
+
+#ifndef AIAPRPOOL_H
+#define AIAPRPOOL_H
+
+#ifdef LL_WINDOWS
+#include // Needed before including apr_portable.h
+#endif
+
+#include "apr_portable.h"
+#include "apr_pools.h"
+#include "llerror.h"
+
+extern void ll_init_apr();
+
+/**
+ * @brief A wrapper around the APR memory pool API.
+ *
+ * Usage of this class should be restricted to passing it to libapr-1 function calls that need it.
+ *
+ */
+class LL_COMMON_API AIAPRPool
+{
+protected:
+ apr_pool_t* mPool; //!< Pointer to the underlaying pool. NULL if not initialized.
+ AIAPRPool* mParent; //!< Pointer to the parent pool, if any. Only valid when mPool is non-zero.
+ apr_os_thread_t mOwner; //!< The thread that owns this memory pool. Only valid when mPool is non-zero.
+
+public:
+ //! Construct an uninitialized (destructed) pool.
+ AIAPRPool(void) : mPool(NULL) { }
+
+ //! Construct a subpool from an existing pool.
+ // This is not a copy-constructor, this class doesn't have one!
+ AIAPRPool(AIAPRPool& parent) : mPool(NULL) { create(parent); }
+
+ //! Destruct the memory pool (free all of it's subpools and allocated memory).
+ ~AIAPRPool() { destroy(); }
+
+protected:
+ // Create a pool that is allocated from the Operating System. Only used by AIAPRRootPool.
+ AIAPRPool(int) : mPool(NULL), mParent(NULL), mOwner(apr_os_thread_current())
+ {
+ apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, NULL);
+ llassert_always(apr_pool_create_status == APR_SUCCESS);
+ llassert(mPool);
+ apr_pool_cleanup_register(mPool, this, &s_plain_cleanup, &apr_pool_cleanup_null);
+ }
+
+public:
+ //! Create a subpool from parent. May only be called for an uninitialized/destroyed pool.
+ // The default parameter causes the root pool of the current thread to be used.
+ void create(AIAPRPool& parent = *static_cast(NULL));
+
+ //! Destroy the (sub)pool, if any.
+ void destroy(void);
+
+ // Use some safebool idiom (http://www.artima.com/cppsource/safebool.html) rather than operator bool.
+ typedef apr_pool_t* const AIAPRPool::* const bool_type;
+ //! Return true if the pool is initialized.
+ operator bool_type() const { return mPool ? &AIAPRPool::mPool : 0; }
+
+ // Painful, but we have to either provide access to this, or wrap
+ // every APR function call that needs a apr_pool_t* to be passed.
+ // NEVER destroy a pool that is returned by this function!
+ apr_pool_t* operator()(void) const
+ {
+ llassert(mPool);
+ llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
+ return mPool;
+ }
+
+ // Free all memory without destructing the pool.
+ void clear(void)
+ {
+ llassert(mPool);
+ llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
+ apr_pool_clear(mPool);
+ }
+
+// These methods would make this class 'complete' (as wrapper around the libapr
+// pool functions), but we don't use memory pools in the viewer (only when
+// we are forced to pass one to a libapr call), so don't define them in order
+// not to encourage people to use them.
+#if 0
+ void* palloc(size_t size)
+ {
+ llassert(mPool);
+ llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
+ return apr_palloc(mPool, size);
+ }
+ void* pcalloc(size_t size)
+ {
+ llassert(mPool);
+ llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
+ return apr_pcalloc(mPool, size);
+ }
+#endif
+
+private:
+ bool parent_is_being_destructed(void);
+ static apr_status_t s_plain_cleanup(void* userdata) { return static_cast(userdata)->plain_cleanup(); }
+
+ apr_status_t plain_cleanup(void)
+ {
+ if (mPool && // We are not being destructed,
+ parent_is_being_destructed()) // but our parent is.
+ // This means the pool is being destructed recursively by libapr
+ // because one of it's parents is being destructed.
+ {
+ mPool = NULL; // Stop destroy() from destructing the pool again.
+ }
+ return APR_SUCCESS;
+ }
+};
+
+class AIAPRInitialization
+{
+public:
+ AIAPRInitialization(void);
+};
+
+/**
+ * @brief Root memory pool (allocates memory from the operating system).
+ *
+ * This class should only be used by AIThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase
+ * (and LLMutexRootPool when APR_HAS_THREADS isn't defined).
+ */
+class LL_COMMON_API AIAPRRootPool : public AIAPRInitialization, public AIAPRPool
+{
+private:
+ friend class AIThreadLocalData;
+ friend class AIThreadSafeSimpleDCRootPool_pbase;
+#if !APR_HAS_THREADS
+ friend class LLMutexRootPool;
+#endif
+ //! Construct a root memory pool.
+ // Should only be used by AIThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase.
+ AIAPRRootPool(void);
+ ~AIAPRRootPool();
+
+private:
+ // Keep track of how many root pools exist and when the last one is destructed.
+ static bool sCountInitialized;
+ static apr_uint32_t volatile sCount;
+
+public:
+ // Return a global root pool that is independent of AIThreadLocalData.
+ // Normally you should not use this. Only use for early initialization
+ // (before main) and deinitialization (after main).
+ static AIAPRRootPool& get(void);
+
+#if APR_POOL_DEBUG
+ void grab_ownership(void)
+ {
+ // You need a patched libapr to use this.
+ // See http://web.archiveorange.com/archive/v/5XO9y2zoxUOMt6Gmi1OI
+ apr_pool_owner_set(mPool);
+ }
+#endif
+
+private:
+ // Used for constructing the Special Global Root Pool (returned by AIAPRRootPool::get).
+ // It is the same as the default constructor but omits to increment sCount. As a result,
+ // we must be sure that at least one other AIAPRRootPool is created before termination
+ // of the application (which is the case: we create one AIAPRRootPool per thread).
+ AIAPRRootPool(int) : AIAPRInitialization(), AIAPRPool(0) { }
+};
+
+//! Volatile memory pool
+//
+// 'Volatile' APR memory pool which normally only clears memory,
+// and does not destroy the pool (the same pool is reused) for
+// greater efficiency. However, as a safe guard the apr pool
+// is destructed every FULL_VOLATILE_APR_POOL uses to allow
+// the system memory to be allocated more efficiently and not
+// get scattered through RAM.
+//
+class LL_COMMON_API AIVolatileAPRPool : protected AIAPRPool
+{
+public:
+ AIVolatileAPRPool(void) : mNumActiveRef(0), mNumTotalRef(0) { }
+
+ apr_pool_t* getVolatileAPRPool(void)
+ {
+ if (!mPool) create();
+ ++mNumActiveRef;
+ ++mNumTotalRef;
+ return AIAPRPool::operator()();
+ }
+ void clearVolatileAPRPool(void);
+
+ bool isOld(void) const { return mNumTotalRef > FULL_VOLATILE_APR_POOL; }
+ bool isUnused() const { return mNumActiveRef == 0; }
+
+private:
+ S32 mNumActiveRef; // Number of active uses of the pool.
+ S32 mNumTotalRef; // Number of total uses of the pool since last creation.
+
+ // Maximum number of references to AIVolatileAPRPool until the pool is recreated.
+ static S32 const FULL_VOLATILE_APR_POOL = 1024;
+};
+
+#endif // AIAPRPOOL_H
diff --git a/indra/llcommon/aithreadsafe.h b/indra/llcommon/aithreadsafe.h
new file mode 100644
index 000000000..70cd2a3db
--- /dev/null
+++ b/indra/llcommon/aithreadsafe.h
@@ -0,0 +1,482 @@
+/**
+ * @file aithreadsafe.h
+ * @brief Implementation of AIThreadSafe, AIReadAccessConst, AIReadAccess and AIWriteAccess.
+ *
+ * Copyright (c) 2010, Aleric Inglewood.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution.
+ *
+ * CHANGELOG
+ * and additional copyright holders.
+ *
+ * 31/03/2010
+ * Initial version, written by Aleric Inglewood @ SL
+ */
+
+#ifndef AITHREADSAFE_H
+#define AITHREADSAFE_H
+
+#include
+
+#include "llthread.h"
+#include "llerror.h"
+
+template struct AIReadAccessConst;
+template struct AIReadAccess;
+template struct AIWriteAccess;
+template struct AIAccess;
+
+template
+class AIThreadSafeBits
+{
+private:
+ // AIThreadSafe is a wrapper around an instance of T.
+ // Because T might not have a default constructor, it is constructed
+ // 'in place', with placement new, in the memory reserved here.
+ //
+ // Make sure that the memory that T will be placed in is properly
+ // aligned by using an array of long's.
+ long mMemory[(sizeof(T) + sizeof(long) - 1) / sizeof(long)];
+
+public:
+ // The wrapped objects are constructed in-place with placement new *outside*
+ // of this object (by AITHREADSAFE macro(s) or derived classes).
+ // However, we are responsible for the destruction of the wrapped object.
+ ~AIThreadSafeBits() { ptr()->~T(); }
+
+ // Only for use by AITHREADSAFE, see below.
+ void* memory() const { return const_cast(&mMemory[0]); }
+
+protected:
+ // Accessors.
+ T const* ptr() const { return reinterpret_cast(mMemory); }
+ T* ptr() { return reinterpret_cast(mMemory); }
+};
+
+/**
+ * @brief A wrapper class for objects that need to be accessed by more than one thread, allowing concurrent readers.
+ *
+ * Use AITHREADSAFE to define instances of any type, and use AIReadAccessConst,
+ * AIReadAccess and AIWriteAccess to get access to the instance.
+ *
+ * For example,
+ *
+ *
+ * class Foo { public: Foo(int, int); };
+ *
+ * AITHREADSAFE(Foo, foo, (2, 3));
+ *
+ * AIReadAccess foo_r(foo);
+ * // Use foo_r-> for read access.
+ *
+ * AIWriteAccess foo_w(foo);
+ * // Use foo_w-> for write access.
+ *
+ *
+ * If foo is constant, you have to use AIReadAccessConst.
+ *
+ * It is possible to pass access objects to a function that
+ * downgrades the access, for example:
+ *
+ *
+ * void readfunc(AIReadAccess const& access);
+ *
+ * AIWriteAccess foo_w(foo);
+ * readfunc(foo_w); // readfunc will perform read access to foo_w.
+ *
+ *
+ * If AIReadAccess is non-const, you can upgrade the access by creating
+ * an AIWriteAccess object from it. For example:
+ *
+ *
+ * AIWriteAccess foo_w(foo_r);
+ *
+ *
+ * This API is Robust(tm). If you try anything that could result in problems,
+ * it simply won't compile. The only mistake you can still easily make is
+ * to obtain write access to an object when it is not needed, or to unlock
+ * an object in between accesses while the state of the object should be
+ * preserved. For example:
+ *
+ *
+ * // This resets foo to point to the first file and then returns that.
+ * std::string filename = AIWriteAccess(foo)->get_first_filename();
+ *
+ * // WRONG! The state between calling get_first_filename and get_next_filename should be preserved!
+ *
+ * AIWriteAccess foo_w(foo); // Wrong. The code below only needs read-access.
+ * while (!filename.empty())
+ * {
+ * something(filename);
+ * filename = foo_w->next_filename();
+ * }
+ *
+ *
+ * Correct would be
+ *
+ *
+ * AIReadAccess foo_r(foo);
+ * std::string filename = AIWriteAccess(foo_r)->get_first_filename();
+ * while (!filename.empty())
+ * {
+ * something(filename);
+ * filename = foo_r->next_filename();
+ * }
+ *
+ *
+ */
+template
+class AIThreadSafe : public AIThreadSafeBits
+{
+protected:
+ // Only these may access the object (through ptr()).
+ friend struct AIReadAccessConst;
+ friend struct AIReadAccess;
+ friend struct AIWriteAccess;
+
+ // Locking control.
+ AIRWLock mRWLock;
+
+ // For use by AIThreadSafeDC
+ AIThreadSafe(void) { }
+ AIThreadSafe(AIAPRPool& parent) : mRWLock(parent) { }
+
+public:
+ // Only for use by AITHREADSAFE, see below.
+ AIThreadSafe(T* object) { llassert(object == AIThreadSafeBits::ptr()); }
+};
+
+/**
+ * @brief Instantiate an static, global or local object of a given type wrapped in AIThreadSafe, using an arbitrary constructor.
+ *
+ * For example, instead of doing
+ *
+ *
+ * Foo foo(x, y);
+ * static Bar bar;
+ *
+ *
+ * One can instantiate a thread-safe instance with
+ *
+ *
+ * AITHREADSAFE(Foo, foo, (x, y));
+ * static AITHREADSAFE(Bar, bar, );
+ *
+ *
+ * Note: This macro does not allow to allocate such object on the heap.
+ * If that is needed, have a look at AIThreadSafeDC.
+ */
+#define AITHREADSAFE(type, var, paramlist) AIThreadSafe var(new (var.memory()) type paramlist)
+
+/**
+ * @brief A wrapper class for objects that need to be accessed by more than one thread.
+ *
+ * This class is the same as an AIThreadSafe wrapper, except that it can only
+ * be used for default constructed objects.
+ *
+ * For example, instead of
+ *
+ *
+ * Foo foo;
+ *
+ *
+ * One would use
+ *
+ *
+ * AIThreadSafeDC foo;
+ *
+ *
+ * The advantage over AITHREADSAFE is that this object can be allocated with
+ * new on the heap. For example:
+ *
+ *
+ * AIThreadSafeDC* ptr = new AIThreadSafeDC;
+ *
+ *
+ * which is not possible with AITHREADSAFE.
+ */
+template
+class AIThreadSafeDC : public AIThreadSafe
+{
+public:
+ // Construct a wrapper around a default constructed object.
+ AIThreadSafeDC(void) { new (AIThreadSafe::ptr()) T; }
+};
+
+/**
+ * @brief Read lock object and provide read access.
+ */
+template
+struct AIReadAccessConst
+{
+ //! Internal enum for the lock-type of the AI*Access object.
+ enum state_type
+ {
+ readlocked, //!< A AIReadAccessConst or AIReadAccess.
+ read2writelocked, //!< A AIWriteAccess constructed from a AIReadAccess.
+ writelocked, //!< A AIWriteAccess constructed from a AIThreadSafe.
+ write2writelocked //!< A AIWriteAccess constructed from (the AIReadAccess base class of) a AIWriteAccess.
+ };
+
+ //! Construct a AIReadAccessConst from a constant AIThreadSafe.
+ AIReadAccessConst(AIThreadSafe const& wrapper)
+ : mWrapper(const_cast&>(wrapper)),
+ mState(readlocked)
+ {
+ mWrapper.mRWLock.rdlock();
+ }
+
+ //! Destruct the AI*Access object.
+ // These should never be dynamically allocated, so there is no need to make this virtual.
+ ~AIReadAccessConst()
+ {
+ if (mState == readlocked)
+ mWrapper.mRWLock.rdunlock();
+ else if (mState == writelocked)
+ mWrapper.mRWLock.wrunlock();
+ else if (mState == read2writelocked)
+ mWrapper.mRWLock.wr2rdlock();
+ }
+
+ //! Access the underlaying object for read access.
+ T const* operator->() const { return mWrapper.ptr(); }
+
+ //! Access the underlaying object for read access.
+ T const& operator*() const { return *mWrapper.ptr(); }
+
+protected:
+ //! Constructor used by AIReadAccess.
+ AIReadAccessConst(AIThreadSafe& wrapper, state_type state)
+ : mWrapper(wrapper), mState(state) { }
+
+ AIThreadSafe& mWrapper; //!< Reference to the object that we provide access to.
+ state_type const mState; //!< The lock state that mWrapper is in.
+
+private:
+ // Disallow copy constructing directly.
+ AIReadAccessConst(AIReadAccessConst const&);
+};
+
+/**
+ * @brief Read lock object and provide read access, with possible promotion to write access.
+ */
+template
+struct AIReadAccess : public AIReadAccessConst
+{
+ typedef typename AIReadAccessConst::state_type state_type;
+ using AIReadAccessConst::readlocked;
+
+ //! Construct a AIReadAccess from a non-constant AIThreadSafe.
+ AIReadAccess(AIThreadSafe& wrapper) : AIReadAccessConst(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(); }
+
+protected:
+ //! Constructor used by AIWriteAccess.
+ AIReadAccess(AIThreadSafe& wrapper, state_type state) : AIReadAccessConst(wrapper, state) { }
+
+ friend class AIWriteAccess;
+};
+
+/**
+ * @brief Write lock object and provide read/write access.
+ */
+template
+struct AIWriteAccess : public AIReadAccess
+{
+ using AIReadAccessConst::readlocked;
+ using AIReadAccessConst::read2writelocked;
+ using AIReadAccessConst::writelocked;
+ using AIReadAccessConst::write2writelocked;
+
+ //! Construct a AIWriteAccess from a non-constant AIThreadSafe.
+ AIWriteAccess(AIThreadSafe& wrapper) : AIReadAccess(wrapper, writelocked) { this->mWrapper.mRWLock.wrlock();}
+
+ //! Promote read access to write access.
+ explicit AIWriteAccess(AIReadAccess& access)
+ : AIReadAccess(access.mWrapper, (access.mState == readlocked) ? read2writelocked : write2writelocked)
+ {
+ if (this->mState == read2writelocked)
+ {
+ this->mWrapper.mRWLock.rd2wrlock();
+ }
+ }
+
+ //! Access the underlaying object for (read and) write access.
+ T* operator->() const { return this->mWrapper.ptr(); }
+
+ //! Access the underlaying object for (read and) write access.
+ T& operator*() const { return *this->mWrapper.ptr(); }
+};
+
+/**
+ * @brief A wrapper class for objects that need to be accessed by more than one thread.
+ *
+ * Use AITHREADSAFESIMPLE to define instances of any type, and use AIAccess
+ * to get access to the instance.
+ *
+ * For example,
+ *
+ *
+ * class Foo { public: Foo(int, int); };
+ *
+ * AITHREADSAFESIMPLE(Foo, foo, (2, 3));
+ *
+ * AIAccess foo_w(foo);
+ * // Use foo_w-> for read and write access.
+ *
+ * See also AIThreadSafe
+ */
+template
+class AIThreadSafeSimple : public AIThreadSafeBits
+{
+protected:
+ // Only this one may access the object (through ptr()).
+ friend struct AIAccess;
+
+ // Locking control.
+ LLMutex mMutex;
+
+ // For use by AIThreadSafeSimpleDC
+ AIThreadSafeSimple(void) { }
+ AIThreadSafeSimple(AIAPRPool& parent) : mMutex(parent) { }
+
+public:
+ // Only for use by AITHREADSAFESIMPLE, see below.
+ AIThreadSafeSimple(T* object) { llassert(object == AIThreadSafeBits::ptr()); }
+};
+
+/**
+ * @brief Instantiate an static, global or local object of a given type wrapped in AIThreadSafeSimple, using an arbitrary constructor.
+ *
+ * For example, instead of doing
+ *
+ *
+ * Foo foo(x, y);
+ * static Bar bar;
+ *
+ *
+ * One can instantiate a thread-safe instance with
+ *
+ *
+ * AITHREADSAFESIMPLE(Foo, foo, (x, y));
+ * static AITHREADSAFESIMPLE(Bar, bar, );
+ *
+ *
+ * Note: This macro does not allow to allocate such object on the heap.
+ * If that is needed, have a look at AIThreadSafeSimpleDC.
+ */
+#define AITHREADSAFESIMPLE(type, var, paramlist) AIThreadSafeSimple var(new (var.memory()) type paramlist)
+
+/**
+ * @brief A wrapper class for objects that need to be accessed by more than one thread.
+ *
+ * This class is the same as an AIThreadSafeSimple wrapper, except that it can only
+ * be used for default constructed objects.
+ *
+ * For example, instead of
+ *
+ *
+ * Foo foo;
+ *
+ *
+ * One would use
+ *
+ *
+ * AIThreadSafeSimpleDC foo;
+ *
+ *
+ * The advantage over AITHREADSAFESIMPLE is that this object can be allocated with
+ * new on the heap. For example:
+ *
+ *
+ * AIThreadSafeSimpleDC* ptr = new AIThreadSafeSimpleDC;
+ *
+ *
+ * which is not possible with AITHREADSAFESIMPLE.
+ */
+template
+class AIThreadSafeSimpleDC : public AIThreadSafeSimple
+{
+public:
+ // Construct a wrapper around a default constructed object.
+ AIThreadSafeSimpleDC(void) { new (AIThreadSafeSimple::ptr()) T; }
+
+protected:
+ // For use by AIThreadSafeSimpleDCRootPool
+ AIThreadSafeSimpleDC(AIAPRPool& parent) : AIThreadSafeSimple(parent) { new (AIThreadSafeSimple::ptr()) T; }
+};
+
+// Helper class for AIThreadSafeSimpleDCRootPool to assure initialization of
+// the root pool before constructing AIThreadSafeSimpleDC.
+class AIThreadSafeSimpleDCRootPool_pbase
+{
+protected:
+ AIAPRRootPool mRootPool;
+
+private:
+ template friend class AIThreadSafeSimpleDCRootPool;
+ AIThreadSafeSimpleDCRootPool_pbase(void) { }
+};
+
+/**
+ * @brief A wrapper class for objects that need to be accessed by more than one thread.
+ *
+ * The same as AIThreadSafeSimpleDC except that this class creates its own AIAPRRootPool
+ * for the internally used mutexes and condition, instead of using the current threads
+ * root pool. The advantage of this is that it can be used for objects that need to
+ * be accessed from the destructors of global objects (after main). The disadvantage
+ * is that it's less efficient to use your own root pool, therefore it's use should be
+ * restricted to those cases where it is absolutely necessary.
+ */
+template
+class AIThreadSafeSimpleDCRootPool : private AIThreadSafeSimpleDCRootPool_pbase, public AIThreadSafeSimpleDC
+{
+public:
+ // Construct a wrapper around a default constructed object, using memory allocated
+ // from the operating system for the internal APR objects (mutexes and conditional),
+ // as opposed to allocated from the current threads root pool.
+ AIThreadSafeSimpleDCRootPool(void) :
+ AIThreadSafeSimpleDCRootPool_pbase(),
+ AIThreadSafeSimpleDC(mRootPool) { }
+};
+
+/**
+ * @brief Write lock object and provide read/write access.
+ */
+template
+struct AIAccess
+{
+ //! Construct a AIAccess from a non-constant AIThreadSafeSimple.
+ AIAccess(AIThreadSafeSimple& wrapper) : mWrapper(wrapper) { this->mWrapper.mMutex.lock(); }
+
+ //! Access the underlaying object for (read and) write access.
+ T* operator->() const { return this->mWrapper.ptr(); }
+
+ //! Access the underlaying object for (read and) write access.
+ T& operator*() const { return *this->mWrapper.ptr(); }
+
+ ~AIAccess() { this->mWrapper.mMutex.unlock(); }
+
+protected:
+ AIThreadSafeSimple& mWrapper; //!< Reference to the object that we provide access to.
+
+private:
+ // Disallow copy constructing directly.
+ AIAccess(AIAccess const&);
+};
+
+#endif
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index fb2fdd814..3bb833a94 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -95,7 +95,6 @@ LLAppChildCallback LLApp::sDefaultChildCallback = NULL;
LLApp::LLApp() : mThreadErrorp(NULL)
{
commonCtor();
- startErrorThread();
}
void LLApp::commonCtor()
@@ -123,13 +122,8 @@ void LLApp::commonCtor()
mOptions.append(sd);
}
- // Make sure we clean up APR when we exit
- // Don't need to do this if we're cleaning up APR in the destructor
- //atexit(ll_cleanup_apr);
-
// Set the application to this instance.
sApplication = this;
-
}
LLApp::LLApp(LLErrorThread *error_thread) :
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index 77cb17c1a..d5cf6ea93 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -256,9 +256,12 @@ protected:
*/
void stepFrame();
-private:
+ /**
+ * @ brief This method is called once as soon as logging is initialized.
+ */
void startErrorThread();
-
+
+private:
void setupErrorHandling(); // Do platform-specific error-handling setup (signals, structured exceptions)
static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred.
static void runSyncErrorHandler(); // run IMMEDIATELY when we get an error, ran in the context of the faulting thread.
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index 7210bd2b1..9595707cb 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -34,219 +34,7 @@
#include "linden_common.h"
#include "llapr.h"
-
-apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool
-apr_thread_mutex_t *gLogMutexp = NULL;
-apr_thread_mutex_t *gCallStacksLogMutexp = NULL;
-
-const S32 FULL_VOLATILE_APR_POOL = 1024 ; //number of references to LLVolatileAPRPool
-
-void ll_init_apr()
-{
- if (!gAPRPoolp)
- {
- // Initialize APR and create the global pool
- apr_initialize();
- apr_pool_create(&gAPRPoolp, NULL);
-
- // Initialize the logging mutex
- apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp);
- apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp);
-
- // Initialize thread-local APR pool support.
- LLVolatileAPRPool::initLocalAPRFilePool();
- }
-}
-
-
-void ll_cleanup_apr()
-{
- LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL;
-
- if (gLogMutexp)
- {
- // Clean up the logging mutex
-
- // All other threads NEED to be done before we clean up APR, so this is okay.
- apr_thread_mutex_destroy(gLogMutexp);
- gLogMutexp = NULL;
- }
- if (gCallStacksLogMutexp)
- {
- // Clean up the logging mutex
-
- // All other threads NEED to be done before we clean up APR, so this is okay.
- apr_thread_mutex_destroy(gCallStacksLogMutexp);
- gCallStacksLogMutexp = NULL;
- }
- if (gAPRPoolp)
- {
- apr_pool_destroy(gAPRPoolp);
- gAPRPoolp = NULL;
- }
- apr_terminate();
-}
-
-//
-//
-//LLAPRPool
-//
-LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag)
- : mParent(parent),
- mReleasePoolFlag(releasePoolFlag),
- mMaxSize(size),
- mPool(NULL)
-{
- createAPRPool() ;
-}
-
-LLAPRPool::~LLAPRPool()
-{
- releaseAPRPool() ;
-}
-
-void LLAPRPool::createAPRPool()
-{
- if(mPool)
- {
- return ;
- }
-
- mStatus = apr_pool_create(&mPool, mParent);
- ll_apr_warn_status(mStatus) ;
-
- if(mMaxSize > 0) //size is the number of blocks (which is usually 4K), NOT bytes.
- {
- apr_allocator_t *allocator = apr_pool_allocator_get(mPool);
- if (allocator)
- {
- apr_allocator_max_free_set(allocator, mMaxSize) ;
- }
- }
-}
-
-void LLAPRPool::releaseAPRPool()
-{
- if(!mPool)
- {
- return ;
- }
-
- if(!mParent || mReleasePoolFlag)
- {
- apr_pool_destroy(mPool) ;
- mPool = NULL ;
- }
-}
-
-apr_pool_t* LLAPRPool::getAPRPool()
-{
- if(!mPool)
- {
- createAPRPool() ;
- }
-
- return mPool ;
-}
-LLVolatileAPRPool::LLVolatileAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag)
- : LLAPRPool(parent, size, releasePoolFlag)
-{
- mNumActiveRef = 0 ;
- mNumTotalRef = 0 ;
-}
-
-apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool()
-{
- mNumTotalRef++ ;
- mNumActiveRef++ ;
- return getAPRPool() ;
-}
-
-void LLVolatileAPRPool::clearVolatileAPRPool()
-{
- if(mNumActiveRef > 0)
- {
- mNumActiveRef--;
- if(mNumActiveRef < 1)
- {
- if(isFull())
- {
- mNumTotalRef = 0 ;
-
- //destroy the apr_pool.
- releaseAPRPool() ;
- }
- else
- {
- //This does not actually free the memory,
- //it just allows the pool to re-use this memory for the next allocation.
- apr_pool_clear(mPool) ;
- }
- }
- }
- else
- {
- llassert_always(mNumActiveRef > 0) ;
- }
-
- //paranoia check if the pool is jammed.
- //will remove the check before going to release.
- llassert_always(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ;
-}
-
-BOOL LLVolatileAPRPool::isFull()
-{
- return mNumTotalRef > FULL_VOLATILE_APR_POOL ;
-}
-
-#ifdef SHOW_ASSERT
-// This allows the use of llassert(is_main_thread()) to assure the current thread is the main thread.
-static void* gIsMainThread;
-bool is_main_thread() { return gIsMainThread == LLVolatileAPRPool::getLocalAPRFilePool(); }
-#endif
-
-// The thread private handle to access the LocalAPRFilePool.
-apr_threadkey_t* LLVolatileAPRPool::sLocalAPRFilePoolKey;
-
-// This should be called exactly once, before the first call to createLocalAPRFilePool.
-// static
-void LLVolatileAPRPool::initLocalAPRFilePool()
-{
- apr_status_t status = apr_threadkey_private_create(&sLocalAPRFilePoolKey, &destroyLocalAPRFilePool, gAPRPoolp);
- ll_apr_assert_status(status); // Or out of memory, or system-imposed limit on the
- // total number of keys per process {PTHREAD_KEYS_MAX}
- // has been exceeded.
- // Create the thread-local pool for the main thread (this function is called by the main thread).
- createLocalAPRFilePool();
-#ifdef SHOW_ASSERT
- gIsMainThread = getLocalAPRFilePool();
-#endif
-}
-
-// This should be called once for every thread, before it uses getLocalAPRFilePool.
-// static
-void LLVolatileAPRPool::createLocalAPRFilePool()
-{
- void* thread_local_data = new LLVolatileAPRPool;
- apr_status_t status = apr_threadkey_private_set(thread_local_data, sLocalAPRFilePoolKey);
- llassert_always(status == APR_SUCCESS);
-}
-
-// This is called once for every thread when the thread is destructed.
-// static
-void LLVolatileAPRPool::destroyLocalAPRFilePool(void* thread_local_data)
-{
- delete reinterpret_cast(thread_local_data);
-}
-
-// static
-LLVolatileAPRPool* LLVolatileAPRPool::getLocalAPRFilePool()
-{
- void* thread_local_data;
- apr_status_t status = apr_threadkey_private_get(&thread_local_data, sLocalAPRFilePoolKey);
- llassert_always(status == APR_SUCCESS);
- return reinterpret_cast(thread_local_data);
-}
+#include "llscopedvolatileaprpool.h"
//---------------------------------------------------------------------
//
@@ -309,13 +97,15 @@ void ll_apr_assert_status(apr_status_t status)
//
LLAPRFile::LLAPRFile()
: mFile(NULL),
- mCurrentFilePoolp(NULL)
+ mVolatileFilePoolp(NULL),
+ mRegularFilePoolp(NULL)
{
}
LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type)
: mFile(NULL),
- mCurrentFilePoolp(NULL)
+ mVolatileFilePoolp(NULL),
+ mRegularFilePoolp(NULL)
{
open(filename, flags, access_type);
}
@@ -334,10 +124,16 @@ apr_status_t LLAPRFile::close()
mFile = NULL ;
}
- if(mCurrentFilePoolp)
+ if (mVolatileFilePoolp)
{
- mCurrentFilePoolp->clearVolatileAPRPool() ;
- mCurrentFilePoolp = NULL ;
+ mVolatileFilePoolp->clearVolatileAPRPool() ;
+ mVolatileFilePoolp = NULL ;
+ }
+
+ if (mRegularFilePoolp)
+ {
+ delete mRegularFilePoolp;
+ mRegularFilePoolp = NULL;
}
return ret ;
@@ -346,25 +142,28 @@ apr_status_t LLAPRFile::close()
apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, access_t access_type, S32* sizep)
{
llassert_always(!mFile);
- llassert_always(!mCurrentFilePoolp);
+ llassert_always(!mVolatileFilePoolp && !mRegularFilePoolp);
- // Access the pool and increment it's reference count.
- // The reference count of LLVolatileAPRPool objects will be decremented
- // again in LLAPRFile::close by calling mCurrentFilePoolp->clearVolatileAPRPool().
- apr_pool_t* pool;
- if (access_type == local)
+ apr_status_t status;
{
- // Use a "volatile" thread-local pool.
- mCurrentFilePoolp = LLVolatileAPRPool::getLocalAPRFilePool();
- pool = mCurrentFilePoolp->getVolatileAPRPool();
+ apr_pool_t* apr_file_open_pool;
+ if (access_type == local)
+ {
+ // Use a "volatile" thread-local pool.
+ mVolatileFilePoolp = &AIThreadLocalData::tldata().mVolatileAPRPool;
+ // Access the pool and increment it's reference count.
+ // The reference count of AIVolatileAPRPool objects will be decremented
+ // again in LLAPRFile::close by calling mVolatileFilePoolp->clearVolatileAPRPool().
+ apr_file_open_pool = mVolatileFilePoolp->getVolatileAPRPool();
+ }
+ else
+ {
+ mRegularFilePoolp = new AIAPRPool(AIThreadLocalData::tldata().mRootPool);
+ apr_file_open_pool = (*mRegularFilePoolp)();
+ }
+ status = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, apr_file_open_pool);
}
- else
- {
- llassert(is_main_thread());
- pool = gAPRPoolp;
- }
- apr_status_t s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, pool);
- if (s != APR_SUCCESS || !mFile)
+ if (status != APR_SUCCESS || !mFile)
{
mFile = NULL ;
close() ;
@@ -372,7 +171,7 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc
{
*sizep = 0;
}
- return s;
+ return status;
}
if (sizep)
@@ -389,7 +188,7 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc
*sizep = file_size;
}
- return s;
+ return status;
}
// File I/O
@@ -449,17 +248,6 @@ S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset)
//static components of LLAPRFile
//
-// Used in the static functions below.
-class LLScopedVolatileAPRFilePool {
-private:
- LLVolatileAPRPool* mPool;
- apr_pool_t* apr_pool;
-public:
- LLScopedVolatileAPRFilePool() : mPool(LLVolatileAPRPool::getLocalAPRFilePool()), apr_pool(mPool->getVolatileAPRPool()) { }
- ~LLScopedVolatileAPRFilePool() { mPool->clearVolatileAPRPool(); }
- operator apr_pool_t*() const { return apr_pool; }
-};
-
//static
S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset)
{
@@ -496,7 +284,7 @@ S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset)
S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes)
{
apr_file_t* file_handle;
- LLScopedVolatileAPRFilePool pool;
+ LLScopedVolatileAPRPool pool;
apr_status_t s = apr_file_open(&file_handle, filename.c_str(), APR_READ|APR_BINARY, APR_OS_DEFAULT, pool);
if (s != APR_SUCCESS || !file_handle)
{
@@ -548,7 +336,7 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n
}
apr_file_t* file_handle;
- LLScopedVolatileAPRFilePool pool;
+ LLScopedVolatileAPRPool pool;
apr_status_t s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool);
if (s != APR_SUCCESS || !file_handle)
{
@@ -593,7 +381,7 @@ bool LLAPRFile::remove(const std::string& filename)
{
apr_status_t s;
- LLScopedVolatileAPRFilePool pool;
+ LLScopedVolatileAPRPool pool;
s = apr_file_remove(filename.c_str(), pool);
if (s != APR_SUCCESS)
@@ -613,7 +401,7 @@ bool LLAPRFile::rename(const std::string& filename, const std::string& newname)
{
apr_status_t s;
- LLScopedVolatileAPRFilePool pool;
+ LLScopedVolatileAPRPool pool;
s = apr_file_rename(filename.c_str(), newname.c_str(), pool);
if (s != APR_SUCCESS)
@@ -631,7 +419,7 @@ bool LLAPRFile::isExist(const std::string& filename, apr_int32_t flags)
apr_file_t* file_handle;
apr_status_t s;
- LLScopedVolatileAPRFilePool pool;
+ LLScopedVolatileAPRPool pool;
s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool);
if (s != APR_SUCCESS || !file_handle)
@@ -652,7 +440,7 @@ S32 LLAPRFile::size(const std::string& filename)
apr_finfo_t info;
apr_status_t s;
- LLScopedVolatileAPRFilePool pool;
+ LLScopedVolatileAPRPool pool;
s = apr_file_open(&file_handle, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool);
if (s != APR_SUCCESS || !file_handle)
@@ -681,7 +469,7 @@ bool LLAPRFile::makeDir(const std::string& dirname)
{
apr_status_t s;
- LLScopedVolatileAPRFilePool pool;
+ LLScopedVolatileAPRPool pool;
s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool);
if (s != APR_SUCCESS)
@@ -698,7 +486,7 @@ bool LLAPRFile::removeDir(const std::string& dirname)
{
apr_status_t s;
- LLScopedVolatileAPRFilePool pool;
+ LLScopedVolatileAPRPool pool;
s = apr_file_remove(dirname.c_str(), pool);
if (s != APR_SUCCESS)
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index 2aed51511..ded15f531 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -48,73 +48,8 @@
#include "apr_atomic.h"
#include "llstring.h"
-extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
-
-/**
- * @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 : protected 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 ;}
-
- static void initLocalAPRFilePool();
- static void createLocalAPRFilePool();
- static void destroyLocalAPRFilePool(void* thread_local_data);
- static LLVolatileAPRPool* getLocalAPRFilePool();
-
-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.
-
- static apr_threadkey_t* sLocalAPRFilePoolKey;
-} ;
+class AIAPRPool;
+class AIVolatileAPRPool;
/**
* @class LLScopedLock
@@ -205,7 +140,8 @@ class LL_COMMON_API LLAPRFile : boost::noncopyable
// make this non copyable since a copy closes the file
private:
apr_file_t* mFile ;
- LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool.
+ AIVolatileAPRPool* mVolatileFilePoolp; // (Thread local) APR pool currently in use.
+ AIAPRPool* mRegularFilePoolp; // ...or a regular pool.
public:
enum access_t {
@@ -260,6 +196,4 @@ 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
diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 2cbb71855..298dd4695 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -34,18 +34,10 @@
#include "llcommon.h"
#include "llthread.h"
-//static
-BOOL LLCommon::sAprInitialized = FALSE;
-
//static
void LLCommon::initClass()
{
LLMemory::initClass();
- if (!sAprInitialized)
- {
- ll_init_apr();
- sAprInitialized = TRUE;
- }
LLTimer::initClass();
LLThreadSafeRefCount::initThreadSafeRefCount();
// LLWorkerThread::initClass();
@@ -59,10 +51,5 @@ void LLCommon::cleanupClass()
// LLWorkerThread::cleanupClass();
LLThreadSafeRefCount::cleanupThreadSafeRefCount();
LLTimer::cleanupClass();
- if (sAprInitialized)
- {
- ll_cleanup_apr();
- sAprInitialized = FALSE;
- }
LLMemory::cleanupClass();
}
diff --git a/indra/llcommon/llcommon.h b/indra/llcommon/llcommon.h
index 851d4ac2d..300ebe2b2 100644
--- a/indra/llcommon/llcommon.h
+++ b/indra/llcommon/llcommon.h
@@ -43,8 +43,6 @@ class LL_COMMON_API LLCommon
public:
static void initClass();
static void cleanupClass();
-private:
- static BOOL sAprInitialized;
};
#endif
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index e549979f0..4cdfe097d 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -55,6 +55,7 @@
#include "llsdserialize.h"
#include "llstl.h"
#include "lltimer.h"
+#include "aithreadsafe.h"
extern apr_thread_mutex_t* gCallStacksLogMutexp;
@@ -357,12 +358,15 @@ namespace
void addCallSite(LLError::CallSite&);
void invalidateCallSites();
- static Globals& get();
+ static AIThreadSafeSimple& get();
// return the one instance of the globals
private:
CallSiteVector callSites;
+ friend class AIThreadSafeSimpleDC; // Calls constructor.
+ friend class AIThreadSafeSimple; // Calls destructor.
+
Globals()
: messageStreamInUse(false)
{ }
@@ -386,7 +390,7 @@ namespace
callSites.clear();
}
- Globals& Globals::get()
+ AIThreadSafeSimple& Globals::get()
{
/* This pattern, of returning a reference to a static function
variable, is to ensure that this global is constructed before
@@ -394,8 +398,8 @@ namespace
is.
See C++ FAQ Lite, sections 10.12 through 10.14
*/
- static Globals* globals = new Globals;
- return *globals;
+ static AIThreadSafeSimpleDCRootPool* ts_globals_ptr = new AIThreadSafeSimpleDCRootPool;
+ return *ts_globals_ptr;
}
}
@@ -424,13 +428,16 @@ namespace LLError
int shouldLogCallCounter;
- static Settings& get();
+ static AIThreadSafeSimple& get();
static void reset();
- static Settings* saveAndReset();
- static void restore(Settings*);
+ static AIThreadSafeSimple* saveAndReset();
+ static void restore(AIThreadSafeSimple*);
private:
+ friend class AIThreadSafeBits; // Calls destructor.
+ friend class AIThreadSafeSimpleDC; // Calls constructor.
+
Settings()
: printLocation(false),
defaultLevel(LLError::LEVEL_DEBUG),
@@ -446,53 +453,42 @@ namespace LLError
for_each(recorders.begin(), recorders.end(),
DeletePointer());
}
-
- static Settings*& getPtr();
+
+ static AIThreadSafeSimple* sSettings;
};
+
+ // Pointer to current AIThreadSafeSimple object if any (NULL otherwise).
+ AIThreadSafeSimple* Settings::sSettings;
- Settings& Settings::get()
+ AIThreadSafeSimple& Settings::get()
{
- Settings* p = getPtr();
- if (!p)
+ if (!sSettings)
{
reset();
- p = getPtr();
}
- return *p;
+ return *sSettings;
}
void Settings::reset()
{
- Globals::get().invalidateCallSites();
-
- Settings*& p = getPtr();
- delete p;
- p = new Settings();
+ AIAccess(Globals::get())->invalidateCallSites();
+ delete sSettings;
+ sSettings = new AIThreadSafeSimpleDC;
}
- Settings* Settings::saveAndReset()
+ AIThreadSafeSimple* Settings::saveAndReset()
{
- Globals::get().invalidateCallSites();
-
- Settings*& p = getPtr();
- Settings* originalSettings = p;
- p = new Settings();
+ AIAccess(Globals::get())->invalidateCallSites();
+ AIThreadSafeSimple* originalSettings = sSettings;
+ sSettings = new AIThreadSafeSimpleDC;
return originalSettings;
}
- void Settings::restore(Settings* originalSettings)
+ void Settings::restore(AIThreadSafeSimple* originalSettings)
{
- Globals::get().invalidateCallSites();
-
- Settings*& p = getPtr();
- delete p;
- p = originalSettings;
- }
-
- Settings*& Settings::getPtr()
- {
- static Settings* currentSettings = NULL;
- return currentSettings;
+ AIAccess(Globals::get())->invalidateCallSites();
+ delete sSettings;
+ sSettings = originalSettings;
}
}
@@ -596,68 +592,64 @@ namespace LLError
commonInit(dir);
}
+ void setPrintLocation(AIAccess const& settings_w, bool print)
+ {
+ settings_w->printLocation = print;
+ }
+
void setPrintLocation(bool print)
{
- Settings& s = Settings::get();
- s.printLocation = print;
+ setPrintLocation(AIAccess(Settings::get()), print);
}
void setFatalFunction(const FatalFunction& f)
{
- Settings& s = Settings::get();
- s.crashFunction = f;
+ AIAccess(Settings::get())->crashFunction = f;
}
FatalFunction getFatalFunction()
{
- Settings& s = Settings::get();
- return s.crashFunction;
+ return AIAccess(Settings::get())->crashFunction;
}
void setTimeFunction(TimeFunction f)
{
- Settings& s = Settings::get();
- s.timeFunction = f;
+ AIAccess(Settings::get())->timeFunction = f;
+ }
+
+ void setDefaultLevel(AIAccess const& settings_w, ELevel level)
+ {
+ AIAccess(Globals::get())->invalidateCallSites();
+ settings_w->defaultLevel = level;
}
void setDefaultLevel(ELevel level)
{
- Globals& g = Globals::get();
- Settings& s = Settings::get();
- g.invalidateCallSites();
- s.defaultLevel = level;
+ setDefaultLevel(AIAccess(Settings::get()), level);
}
void setFunctionLevel(const std::string& function_name, ELevel level)
{
- Globals& g = Globals::get();
- Settings& s = Settings::get();
- g.invalidateCallSites();
- s.functionLevelMap[function_name] = level;
+ AIAccess(Globals::get())->invalidateCallSites();
+ AIAccess(Settings::get())->functionLevelMap[function_name] = level;
}
void setClassLevel(const std::string& class_name, ELevel level)
{
- Globals& g = Globals::get();
- Settings& s = Settings::get();
- g.invalidateCallSites();
- s.classLevelMap[class_name] = level;
+ AIAccess(Globals::get())->invalidateCallSites();
+ AIAccess(Settings::get())->classLevelMap[class_name] = level;
}
void setFileLevel(const std::string& file_name, ELevel level)
{
- Globals& g = Globals::get();
- Settings& s = Settings::get();
- g.invalidateCallSites();
- s.fileLevelMap[file_name] = level;
+ AIAccess(Globals::get())->invalidateCallSites();
+ AIAccess(Settings::get())->fileLevelMap[file_name] = level;
}
void setTagLevel(const std::string& tag_name, ELevel level)
{
- Globals& g = Globals::get();
- Settings& s = Settings::get();
- g.invalidateCallSites();
- s.tagLevelMap[tag_name] = level;
+ AIAccess(Globals::get())->invalidateCallSites();
+ AIAccess(Settings::get())->tagLevelMap[tag_name] = level;
}
}
@@ -701,18 +693,16 @@ namespace LLError
{
void configure(const LLSD& config)
{
- Globals& g = Globals::get();
- Settings& s = Settings::get();
+ AIAccess settings_w(Settings::get());
+ AIAccess(Globals::get())->invalidateCallSites();
+ settings_w->functionLevelMap.clear();
+ settings_w->classLevelMap.clear();
+ settings_w->fileLevelMap.clear();
+ settings_w->tagLevelMap.clear();
+ settings_w->uniqueLogMessages.clear();
- g.invalidateCallSites();
- s.functionLevelMap.clear();
- s.classLevelMap.clear();
- s.fileLevelMap.clear();
- s.tagLevelMap.clear();
- s.uniqueLogMessages.clear();
-
- setPrintLocation(config["print-location"]);
- setDefaultLevel(decodeLevel(config["default-level"]));
+ setPrintLocation(settings_w, config["print-location"]);
+ setDefaultLevel(settings_w, decodeLevel(config["default-level"]));
LLSD sets = config["settings"];
LLSD::array_const_iterator a, end;
@@ -722,10 +712,10 @@ namespace LLError
ELevel level = decodeLevel(entry["level"]);
- setLevels(s.functionLevelMap, entry["functions"], level);
- setLevels(s.classLevelMap, entry["classes"], level);
- setLevels(s.fileLevelMap, entry["files"], level);
- setLevels(s.tagLevelMap, entry["tags"], level);
+ setLevels(settings_w->functionLevelMap, entry["functions"], level);
+ setLevels(settings_w->classLevelMap, entry["classes"], level);
+ setLevels(settings_w->fileLevelMap, entry["files"], level);
+ setLevels(settings_w->tagLevelMap, entry["tags"], level);
}
}
}
@@ -742,26 +732,34 @@ namespace LLError
- void addRecorder(Recorder* recorder)
+ void addRecorder(AIAccess const& settings_w, Recorder* recorder)
{
if (recorder == NULL)
{
return;
}
- Settings& s = Settings::get();
- s.recorders.push_back(recorder);
+ settings_w->recorders.push_back(recorder);
+ }
+
+ void addRecorder(Recorder* recorder)
+ {
+ addRecorder(AIAccess(Settings::get()), recorder);
+ }
+
+ void removeRecorder(AIAccess const& settings_w, Recorder* recorder)
+ {
+ if (recorder == NULL)
+ {
+ return;
+ }
+ settings_w->recorders.erase(
+ std::remove(settings_w->recorders.begin(), settings_w->recorders.end(), recorder),
+ settings_w->recorders.end());
}
void removeRecorder(Recorder* recorder)
{
- if (recorder == NULL)
- {
- return;
- }
- Settings& s = Settings::get();
- s.recorders.erase(
- std::remove(s.recorders.begin(), s.recorders.end(), recorder),
- s.recorders.end());
+ removeRecorder(AIAccess(Settings::get()), recorder);
}
}
@@ -769,12 +767,12 @@ namespace LLError
{
void logToFile(const std::string& file_name)
{
- LLError::Settings& s = LLError::Settings::get();
+ AIAccess settings_w(Settings::get());
- removeRecorder(s.fileRecorder);
- delete s.fileRecorder;
- s.fileRecorder = NULL;
- s.fileRecorderFileName.clear();
+ removeRecorder(settings_w, settings_w->fileRecorder);
+ delete settings_w->fileRecorder;
+ settings_w->fileRecorder = NULL;
+ settings_w->fileRecorderFileName.clear();
if (file_name.empty())
{
@@ -788,54 +786,51 @@ namespace LLError
return;
}
- s.fileRecorderFileName = file_name;
- s.fileRecorder = f;
- addRecorder(f);
+ settings_w->fileRecorderFileName = file_name;
+ settings_w->fileRecorder = f;
+ addRecorder(settings_w, f);
}
void logToFixedBuffer(LLLineBuffer* fixedBuffer)
{
- LLError::Settings& s = LLError::Settings::get();
+ AIAccess settings_w(Settings::get());
- removeRecorder(s.fixedBufferRecorder);
- delete s.fixedBufferRecorder;
- s.fixedBufferRecorder = NULL;
+ removeRecorder(settings_w, settings_w->fixedBufferRecorder);
+ delete settings_w->fixedBufferRecorder;
+ settings_w->fixedBufferRecorder = NULL;
if (!fixedBuffer)
{
return;
}
- s.fixedBufferRecorder = new RecordToFixedBuffer(fixedBuffer);
- addRecorder(s.fixedBufferRecorder);
+ settings_w->fixedBufferRecorder = new RecordToFixedBuffer(fixedBuffer);
+ addRecorder(settings_w, settings_w->fixedBufferRecorder);
}
std::string logFileName()
{
- LLError::Settings& s = LLError::Settings::get();
- return s.fileRecorderFileName;
+ return AIAccess(Settings::get())->fileRecorderFileName;
}
}
namespace
{
- void writeToRecorders(LLError::ELevel level, const std::string& message)
+ void writeToRecorders(AIAccess const& settings_w, LLError::ELevel level, const std::string& message)
{
- LLError::Settings& s = LLError::Settings::get();
-
std::string messageWithTime;
-
- for (Recorders::const_iterator i = s.recorders.begin();
- i != s.recorders.end();
+
+ for (Recorders::const_iterator i = settings_w->recorders.begin();
+ i != settings_w->recorders.end();
++i)
{
LLError::Recorder* r = *i;
- if (r->wantsTime() && s.timeFunction != NULL)
+ if (r->wantsTime() && settings_w->timeFunction != NULL)
{
if (messageWithTime.empty())
{
- messageWithTime = s.timeFunction() + " " + message;
+ messageWithTime = settings_w->timeFunction() + " " + message;
}
r->recordMessage(level, messageWithTime);
@@ -877,6 +872,9 @@ You get:
*/
+apr_thread_mutex_t* gLogMutexp;
+apr_thread_mutex_t* gCallStacksLogMutexp;
+
namespace {
bool checkLevelMap(const LevelMap& map, const std::string& key,
LLError::ELevel& level)
@@ -952,10 +950,9 @@ namespace LLError
return false;
}
- Globals& g = Globals::get();
- Settings& s = Settings::get();
+ AIAccess settings_w(Settings::get());
- s.shouldLogCallCounter += 1;
+ settings_w->shouldLogCallCounter += 1;
std::string class_name = className(site.mClassInfo);
std::string function_name = functionName(site.mFunction);
@@ -964,20 +961,20 @@ namespace LLError
function_name = class_name + "::" + function_name;
}
- ELevel compareLevel = s.defaultLevel;
+ ELevel compareLevel = settings_w->defaultLevel;
// The most specific match found will be used as the log level,
// since the computation short circuits.
// So, in increasing order of importance:
// Default < Broad Tag < File < Class < Function < Narrow Tag
- ((site.mNarrowTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mNarrowTag, compareLevel) : false)
- || checkLevelMap(s.functionLevelMap, function_name, compareLevel)
- || checkLevelMap(s.classLevelMap, class_name, compareLevel)
- || checkLevelMap(s.fileLevelMap, abbreviateFile(site.mFile), compareLevel)
- || ((site.mBroadTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mBroadTag, compareLevel) : false);
+ ((site.mNarrowTag != NULL) ? checkLevelMap(settings_w->tagLevelMap, site.mNarrowTag, compareLevel) : false)
+ || checkLevelMap(settings_w->functionLevelMap, function_name, compareLevel)
+ || checkLevelMap(settings_w->classLevelMap, class_name, compareLevel)
+ || checkLevelMap(settings_w->fileLevelMap, abbreviateFile(site.mFile), compareLevel)
+ || ((site.mBroadTag != NULL) ? checkLevelMap(settings_w->tagLevelMap, site.mBroadTag, compareLevel) : false);
site.mCached = true;
- g.addCallSite(site);
+ AIAccess(Globals::get())->addCallSite(site);
return site.mShouldLog = site.mLevel >= compareLevel;
}
@@ -987,16 +984,16 @@ namespace LLError
LogLock lock;
if (lock.ok())
{
- Globals& g = Globals::get();
+ AIAccess globals(Globals::get());
- if (!g.messageStreamInUse)
+ if (!globals->messageStreamInUse)
{
- g.messageStreamInUse = true;
- return &g.messageStream;
+ globals->messageStreamInUse = true;
+ return &globals->messageStream; // Returns pointer to member of unlocked object, apparently "protected" by having set globals->messageStreamInUse.
}
}
- return new std::ostringstream;
+ return new std::ostringstream; // Holy memory leak.
}
void Log::flush(std::ostringstream* out, char* message)
@@ -1017,12 +1014,12 @@ namespace LLError
message[127] = '\0' ;
}
- Globals& g = Globals::get();
- if (out == &g.messageStream)
+ AIAccess globals(Globals::get());
+ if (out == &globals->messageStream)
{
- g.messageStream.clear();
- g.messageStream.str("");
- g.messageStreamInUse = false;
+ globals->messageStream.clear();
+ globals->messageStream.str("");
+ globals->messageStreamInUse = false;
}
else
{
@@ -1039,28 +1036,31 @@ namespace LLError
return;
}
- Globals& g = Globals::get();
- Settings& s = Settings::get();
-
std::string message = out->str();
- if (out == &g.messageStream)
+
{
- g.messageStream.clear();
- g.messageStream.str("");
- g.messageStreamInUse = false;
- }
- else
- {
- delete out;
+ AIAccess globals(Globals::get());
+ if (out == &globals->messageStream)
+ {
+ globals->messageStream.clear();
+ globals->messageStream.str("");
+ globals->messageStreamInUse = false;
+ }
+ else
+ {
+ delete out;
+ }
}
+ AIAccess settings_w(Settings::get());
+
if (site.mLevel == LEVEL_ERROR)
{
std::ostringstream fatalMessage;
fatalMessage << abbreviateFile(site.mFile)
<< "(" << site.mLine << ") : error";
- writeToRecorders(site.mLevel, fatalMessage.str());
+ writeToRecorders(settings_w, site.mLevel, fatalMessage.str());
}
@@ -1075,7 +1075,7 @@ namespace LLError
default: prefix << "XXX: "; break;
};
- if (s.printLocation)
+ if (settings_w->printLocation)
{
prefix << abbreviateFile(site.mFile)
<< "(" << site.mLine << ") : ";
@@ -1093,8 +1093,8 @@ namespace LLError
if (site.mPrintOnce)
{
- std::map::iterator messageIter = s.uniqueLogMessages.find(message);
- if (messageIter != s.uniqueLogMessages.end())
+ std::map::iterator messageIter = settings_w->uniqueLogMessages.find(message);
+ if (messageIter != settings_w->uniqueLogMessages.end())
{
messageIter->second++;
unsigned int num_messages = messageIter->second;
@@ -1110,14 +1110,14 @@ namespace LLError
else
{
prefix << "ONCE: ";
- s.uniqueLogMessages[message] = 1;
+ settings_w->uniqueLogMessages[message] = 1;
}
}
if (site.mPrintOnce)
{
- std::map::iterator messageIter = s.uniqueLogMessages.find(message);
- if (messageIter != s.uniqueLogMessages.end())
+ std::map::iterator messageIter = settings_w->uniqueLogMessages.find(message);
+ if (messageIter != settings_w->uniqueLogMessages.end())
{
messageIter->second++;
unsigned int num_messages = messageIter->second;
@@ -1133,18 +1133,18 @@ namespace LLError
else
{
prefix << "ONCE: ";
- s.uniqueLogMessages[message] = 1;
+ settings_w->uniqueLogMessages[message] = 1;
}
}
prefix << message;
message = prefix.str();
- writeToRecorders(site.mLevel, message);
+ writeToRecorders(settings_w, site.mLevel, message);
- if (site.mLevel == LEVEL_ERROR && s.crashFunction)
+ if (site.mLevel == LEVEL_ERROR && settings_w->crashFunction)
{
- s.crashFunction(message);
+ settings_w->crashFunction(message);
}
}
}
@@ -1154,14 +1154,16 @@ namespace LLError
namespace LLError
{
- Settings* saveAndResetSettings()
+ class ThreadSafeSettings { };
+
+ ThreadSafeSettings* saveAndResetSettings()
{
- return Settings::saveAndReset();
+ return reinterpret_cast(Settings::saveAndReset());
}
- void restoreSettings(Settings* s)
+ void restoreSettings(ThreadSafeSettings* s)
{
- return Settings::restore(s);
+ Settings::restore(reinterpret_cast*>(s));
}
std::string removePrefix(std::string& s, const std::string& p)
@@ -1207,8 +1209,7 @@ namespace LLError
int shouldLogCallCount()
{
- Settings& s = Settings::get();
- return s.shouldLogCallCounter;
+ return AIAccess(Settings::get())->shouldLogCallCounter;
}
#if LL_WINDOWS
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index 2a7c500db..c6eb39cae 100644
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -167,9 +167,9 @@ namespace LLError
Utilities for use by the unit tests of LLError itself.
*/
- class Settings;
- LL_COMMON_API Settings* saveAndResetSettings();
- LL_COMMON_API void restoreSettings(Settings *);
+ class ThreadSafeSettings;
+ LL_COMMON_API ThreadSafeSettings* saveAndResetSettings();
+ LL_COMMON_API void restoreSettings(ThreadSafeSettings *);
LL_COMMON_API std::string abbreviateFile(const std::string& filePath);
LL_COMMON_API int shouldLogCallCount();
diff --git a/indra/llcommon/llfixedbuffer.cpp b/indra/llcommon/llfixedbuffer.cpp
index 1f6a06c24..08be3e259 100644
--- a/indra/llcommon/llfixedbuffer.cpp
+++ b/indra/llcommon/llfixedbuffer.cpp
@@ -36,8 +36,7 @@
LLFixedBuffer::LLFixedBuffer(const U32 max_lines)
: LLLineBuffer(),
- mMaxLines(max_lines),
- mMutex(NULL)
+ mMaxLines(max_lines)
{
mTimer.reset();
}
diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h
index 39a745f25..df49757a6 100644
--- a/indra/llcommon/llpreprocessor.h
+++ b/indra/llcommon/llpreprocessor.h
@@ -107,17 +107,7 @@
#endif
-// 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
-
-// Deal with the differeneces on Windows
+// Deal with the differences on Windows
#if defined(LL_WINDOWS)
#define BOOST_REGEX_NO_LIB 1
#define CURL_STATICLIB 1
@@ -169,7 +159,6 @@
#define LL_DLLIMPORT
#endif // LL_WINDOWS
-/*
#ifdef llcommon_EXPORTS
// Compiling llcommon (shared)
#define LL_COMMON_API LL_DLLEXPORT
@@ -177,9 +166,5 @@
// Using llcommon (shared)
#define LL_COMMON_API LL_DLLIMPORT
#endif // llcommon_EXPORTS
-*/
-
-//I hate DLLs -SG
-#define LL_COMMON_API
#endif // not LL_LINDEN_PREPROCESSOR_H
diff --git a/indra/llcommon/llscopedvolatileaprpool.h b/indra/llcommon/llscopedvolatileaprpool.h
new file mode 100644
index 000000000..724dc7f05
--- /dev/null
+++ b/indra/llcommon/llscopedvolatileaprpool.h
@@ -0,0 +1,58 @@
+/**
+ * @file llscopedvolatileaprpool.h
+ * @brief Implementation of LLScopedVolatileAPRPool
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://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_LLSCOPEDVOLATILEAPRPOOL_H
+#define LL_LLSCOPEDVOLATILEAPRPOOL_H
+
+#include "llthread.h"
+
+//! Scoped volatile memory pool.
+//
+// As the AIVolatileAPRPool should never keep allocations very
+// long, it's most common use is for allocations with a lifetime
+// equal to it's scope.
+//
+// This is a convenience class that makes just a little easier to type.
+//
+class LLScopedVolatileAPRPool
+{
+private:
+ AIVolatileAPRPool& mPool;
+ apr_pool_t* mScopedAPRpool;
+public:
+ LLScopedVolatileAPRPool() : mPool(AIThreadLocalData::tldata().mVolatileAPRPool), mScopedAPRpool(mPool.getVolatileAPRPool()) { }
+ ~LLScopedVolatileAPRPool() { mPool.clearVolatileAPRPool(); }
+ // Only use this to pass the pointer to a libapr-1 function that requires it.
+ operator apr_pool_t*() const { return mScopedAPRpool; }
+};
+
+#endif
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 6b1115a54..171747921 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -36,6 +36,7 @@
#include
#include
#include
+#include
- fmod
-
- copyright
- FMOD Sound System, copyright (C) Firelight Technologies Pty, Ltd., 1994-2006.
- description
- Audio engine and mp3 stream decoder .
- license
- fmod
- packages
-
- darwin
-
- md5sum
- c7e317bec481b7efa2a0319e163dcc65
- url
- scp:install-packages.lindenlab.com:/local/www/install-packages/doc/fmod-3.75-darwin-20080818.tar.bz2
-
- linux
-
- md5sum
- abd2b4ba4ac993f19d82804af387eb7c
- url
- scp:install-packages.lindenlab.com:/local/www/install-packages/doc/fmod-3.75-linux-20080818.tar.bz2
-
- windows
-
- md5sum
- 1a55dec2907821f5f785648a660126c3
- url
- scp:install-packages.lindenlab.com:/local/www/install-packages/doc/fmod-3.75-windows-20080611.tar.bz2
-
-
- fontconfiglicense
@@ -1015,35 +968,6 @@ anguage Infrstructure (CLI) international standard
- mysql
-
- license
- gpl
- packages
-
- darwin
-
- md5sum
- df27f2db244ea2762759a06cd75ada4e
- url
- scp:install-packages.lindenlab.com:/local/www/install-packages/doc/mysql-darwin-20080812.tar.bz2
-
- linux
-
- md5sum
- cc86b4cc858655e23704d1168325d7b9
- url
- scp:install-packages.lindenlab.com:/local/www/install-packages/doc/mysqlclient-linux-20090320.tar.bz2
-
- windows
-
- md5sum
- 98bac06680dca907e783d8dd4aa9edde
- url
- scp:install-packages.lindenlab.com:/local/www/install-packages/doc/mysql-windows-20080804.tar.bz2
-
-
- ndofdevcopyright
@@ -1219,58 +1143,6 @@ anguage Infrstructure (CLI) international standard
- quicktime
-
- copyright
- Copyright (C) 1990-2007 by Apple Computer, Inc., all rights reserved.
- description
- Separate download. Used to play in-world video clips on a prim.
- license
- quicktime
- packages
-
- windows
-
- md5sum
- be45825cc14ede53790ac93c58307dcb
- url
- scp:install-packages.lindenlab.com:/local/www/install-packages/doc/quicktime-sdk-windows-7.3-20091110.tar.bz2
-
-
-
- smartheap
-
- copyright
- Copyright (C) 1991-2000 Compuware Corporation. All Rights Reserved.
- description
- Memory Management Library
- license
- smartheap
- packages
-
- darwin
-
- md5sum
- f54131b5f228e805c64c2e4e6c96579a
- url
- scp:install-packages.lindenlab.com:/local/www/install-packages/doc/smartheap-6.0.2-darwin-20080610.tar.bz2
-
- linux
-
- md5sum
- 499208522bf7d7843e1d014d64214e06
- url
- scp:install-packages.lindenlab.com:/local/www/install-packages/doc/smartheap-6.0.2-linux-20080610.tar.bz2
-
- windows
-
- md5sum
- 78fd47017f21d11eae43bca3e38a3e1e
- url
- scp:install-packages.lindenlab.com:/local/www/install-packages/doc/smartheap-6.0.2-windows-20080611.tar.bz2
-
-
- tutcopyright
@@ -1331,6 +1203,13 @@ anguage Infrstructure (CLI) international standard
urlhttp://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6270-linux-20090309.tar.bz2
+ linux64
+
+ md5sum
+ 01573510dce7f380f44e561ef2f3dd9f
+ url
+ http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6270-linux-20090309.tar.bz2
+ windowsmd5sum
@@ -1340,6 +1219,29 @@ anguage Infrstructure (CLI) international standard
+ 32bitcompatibilitylibs
+
+ copyright
+ Copyrights: Libidn: Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ Simon Josefsson. License GPL v3.0.
+ Freealut, libuuid, openal-soft: see copyright and license of the
+ according main packages.
+
+ description
+ 32bit libraries needed for using voice
+ license
+ gpl
+ packages
+
+ linux64
+
+ md5sum
+ cbaafc55fb8b14283541791e82f13462
+ url
+ http://imprudenceviewer.org/download/libs/linux64-32bitcompatibilitylibs-20100903.tar.bz2
+
+
+ xmlrpc-epicopyright
diff --git a/scripts/install.py b/scripts/install.py
index 85818bc9a..e53f664b4 100755
--- a/scripts/install.py
+++ b/scripts/install.py
@@ -535,24 +535,24 @@ windows/i686/vs/2003 -- specify a windows visual studio 2003 package"""
platform,
cache_dir))
to_install = []
+ to_uninstall = []
#print "self._installed",self._installed
for ifile in ifiles:
if ifile.pkgname not in self._installed:
to_install.append(ifile)
elif ifile.url not in self._installed[ifile.pkgname].urls():
+ to_uninstall.append(ifile.pkgname)
to_install.append(ifile)
elif ifile.md5sum != \
self._installed[ifile.pkgname].get_md5sum(ifile.url):
- # *TODO: We may want to uninstall the old version too
- # when we detect it is installed, but the md5 sum is
- # different.
+ to_uninstall.append(ifile.pkgname)
to_install.append(ifile)
else:
#print "Installation up to date:",
# ifile.pkgname,ifile.platform_path
pass
#print "to_install",to_install
- return to_install
+ return [to_install, to_uninstall]
def _install(self, to_install, install_dir):
for ifile in to_install:
@@ -565,17 +565,43 @@ windows/i686/vs/2003 -- specify a windows visual studio 2003 package"""
tar.extractall(path=install_dir)
except AttributeError:
_extractall(tar, path=install_dir)
+ symlinks = []
+ if _get_platform() == 'linux' or _get_platform() == 'linux64':
+ first = 1
+ for tfile in tar.getnames():
+ if tfile.find('.so.') > 0:
+ LINK = re.sub(r'\.so\.[0-9.]*$', '.so', tfile)
+ link_name = install_dir + "/" + LINK
+ if not os.path.exists(link_name):
+ if first == 1:
+ first = 0
+ print "Adding missing symlink(s) for package %s:" % ifile.filename
+ target = os.path.basename(tfile)
+ soname = os.popen("readelf -d \"%(install_dir)s/%(tfile)s\" %(stderr_redirect)s"
+ " | grep SONAME | sed -e 's/.*\[//;s/\].*//'" %
+ {"install_dir": install_dir, "tfile": tfile, "stderr_redirect": ("2>/dev/null" if self._dryrun else "")}).read()
+ soname = soname.strip()
+ if soname: # not empty
+ tmpfname = os.path.dirname(LINK) + "/" + soname
+ if os.path.exists(install_dir + "/" + tmpfname):
+ target = soname
+ else:
+ print "WARNING: SONAME %s doesn't exist!" % tmpfname
+ if not self._dryrun:
+ os.symlink(target, link_name)
+ symlinks += [LINK]
+ print " %s --> %s" % (LINK, target)
if ifile.pkgname in self._installed:
self._installed[ifile.pkgname].add_files(
ifile.url,
- tar.getnames())
+ tar.getnames() + symlinks)
self._installed[ifile.pkgname].set_md5sum(
ifile.url,
ifile.md5sum)
else:
# *HACK: this understands the installed package syntax.
definition = { ifile.url :
- {'files': tar.getnames(),
+ {'files': tar.getnames() + symlinks,
'md5sum' : ifile.md5sum } }
self._installed[ifile.pkgname] = InstalledPackage(definition)
self._installed_changed = True
@@ -595,12 +621,17 @@ windows/i686/vs/2003 -- specify a windows visual studio 2003 package"""
cache_dir = os.path.realpath(cache_dir)
_mkdir(install_dir)
_mkdir(cache_dir)
- to_install = self._build_ifiles(platform, cache_dir)
+ to_install_uninstall = self._build_ifiles(platform, cache_dir)
+ to_install = to_install_uninstall[0]
+ to_uninstall = to_install_uninstall[1]
# Filter for files which we actually requested to install.
to_install = [ifl for ifl in to_install if ifl.pkgname in installables]
+ to_uninstall = [ifl for ifl in to_uninstall if ifl in installables]
for ifile in to_install:
ifile.fetch_local()
+ if to_uninstall:
+ self.uninstall(to_uninstall, install_dir)
self._install(to_install, install_dir)
def do_install(self, installables, platform, install_dir, cache_dir=None,
@@ -787,7 +818,7 @@ def _get_platform():
# TODO -- someday when install.py accepts a platform of the form
# os/arch/compiler/compiler_version then we can replace the
# 'linux64' platform with 'linux/x86_64/gcc/4.1'
- this_platform = 'linux'
+ this_platform = 'linux64'
return this_platform
def _getuser():