This commit is contained in:
Shyotl
2011-05-07 23:48:28 -05:00
178 changed files with 2242 additions and 1938 deletions

View File

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

View File

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

View File

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

View File

@@ -35,7 +35,6 @@ set(cmake_SOURCE_FILES
FindNDOF.cmake
FindOpenJPEG.cmake
FindXmlRpcEpi.cmake
FindMyZLIB.cmake
FMOD.cmake
FreeType.cmake
GStreamer010Plugin.cmake

View File

@@ -1,46 +0,0 @@
# -*- cmake -*-
# - Find zlib
# Find the ZLIB includes and library
# This module defines
# ZLIB_INCLUDE_DIRS, where to find zlib.h, etc.
# ZLIB_LIBRARIES, the libraries needed to use zlib.
# ZLIB_FOUND, If false, do not try to use zlib.
#
# This FindZLIB is about 43 times as fast the one provided with cmake (2.8.x),
# because it doesn't look up the version of zlib, resulting in a dramatic
# speed up for configure (from 4 minutes 22 seconds to 6 seconds).
#
# Note: Since this file is only used for standalone, the windows
# specific parts were left out.
FIND_PATH(ZLIB_INCLUDE_DIR zlib.h
NO_SYSTEM_ENVIRONMENT_PATH
)
FIND_LIBRARY(ZLIB_LIBRARY z)
if (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
SET(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR})
SET(ZLIB_LIBRARIES ${ZLIB_LIBRARY})
SET(ZLIB_FOUND "YES")
else (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
SET(ZLIB_FOUND "NO")
endif (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
if (ZLIB_FOUND)
if (NOT ZLIB_FIND_QUIETLY)
message(STATUS "Found ZLIB: ${ZLIB_LIBRARIES}")
SET(ZLIB_FIND_QUIETLY TRUE)
endif (NOT ZLIB_FIND_QUIETLY)
else (ZLIB_FOUND)
if (ZLIB_FIND_REQUIRED)
message(FATAL_ERROR "Could not find ZLIB library")
endif (ZLIB_FIND_REQUIRED)
endif (ZLIB_FOUND)
mark_as_advanced(
ZLIB_LIBRARY
ZLIB_INCLUDE_DIR
)

View File

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

View File

@@ -7,7 +7,6 @@ include(ZLIB)
set(LLCOMMON_INCLUDE_DIRS
${LIBS_OPEN_DIR}/llcommon
${APRUTIL_INCLUDE_DIR}
${APR_INCLUDE_DIR}
${Boost_INCLUDE_DIRS}
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 <http://www.gnu.org/licenses/>.
*
* 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<AIAPRRootPool*>(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)) ;
}

238
indra/llcommon/aiaprpool.h Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>.
*
* 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 <ws2tcpip.h> // 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<AIAPRPool*>(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<AIAPRPool*>(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

View File

@@ -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 <http://www.gnu.org/licenses/>.
*
* 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 <new>
#include "llthread.h"
#include "llerror.h"
template<typename T> struct AIReadAccessConst;
template<typename T> struct AIReadAccess;
template<typename T> struct AIWriteAccess;
template<typename T> struct AIAccess;
template<typename T>
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<long*>(&mMemory[0]); }
protected:
// Accessors.
T const* ptr() const { return reinterpret_cast<T const*>(mMemory); }
T* ptr() { return reinterpret_cast<T*>(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,
*
* <code>
* class Foo { public: Foo(int, int); };
*
* AITHREADSAFE(Foo, foo, (2, 3));
*
* AIReadAccess<Foo> foo_r(foo);
* // Use foo_r-> for read access.
*
* AIWriteAccess<Foo> foo_w(foo);
* // Use foo_w-> for write access.
* </code>
*
* If <code>foo</code> is constant, you have to use <code>AIReadAccessConst<Foo></code>.
*
* It is possible to pass access objects to a function that
* downgrades the access, for example:
*
* <code>
* void readfunc(AIReadAccess const& access);
*
* AIWriteAccess<Foo> foo_w(foo);
* readfunc(foo_w); // readfunc will perform read access to foo_w.
* </code>
*
* If <code>AIReadAccess</code> is non-const, you can upgrade the access by creating
* an <code>AIWriteAccess</code> object from it. For example:
*
* <code>
* AIWriteAccess<Foo> foo_w(foo_r);
* </code>
*
* 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:
*
* <code>
* // This resets foo to point to the first file and then returns that.
* std::string filename = AIWriteAccess<Foo>(foo)->get_first_filename();
*
* // WRONG! The state between calling get_first_filename and get_next_filename should be preserved!
*
* AIWriteAccess<Foo> foo_w(foo); // Wrong. The code below only needs read-access.
* while (!filename.empty())
* {
* something(filename);
* filename = foo_w->next_filename();
* }
* </code>
*
* Correct would be
*
* <code>
* AIReadAccess<Foo> foo_r(foo);
* std::string filename = AIWriteAccess<Foo>(foo_r)->get_first_filename();
* while (!filename.empty())
* {
* something(filename);
* filename = foo_r->next_filename();
* }
* </code>
*
*/
template<typename T>
class AIThreadSafe : public AIThreadSafeBits<T>
{
protected:
// Only these may access the object (through ptr()).
friend struct AIReadAccessConst<T>;
friend struct AIReadAccess<T>;
friend struct AIWriteAccess<T>;
// 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<T>::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
*
* <code>
* Foo foo(x, y);
* static Bar bar;
* </code>
*
* One can instantiate a thread-safe instance with
*
* <code>
* AITHREADSAFE(Foo, foo, (x, y));
* static AITHREADSAFE(Bar, bar, );
* </code>
*
* 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<type> 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
*
* <code>
* Foo foo;
* </code>
*
* One would use
*
* <code>
* AIThreadSafeDC<Foo> foo;
* </code>
*
* The advantage over AITHREADSAFE is that this object can be allocated with
* new on the heap. For example:
*
* <code>
* AIThreadSafeDC<Foo>* ptr = new AIThreadSafeDC<Foo>;
* </code>
*
* which is not possible with AITHREADSAFE.
*/
template<typename T>
class AIThreadSafeDC : public AIThreadSafe<T>
{
public:
// Construct a wrapper around a default constructed object.
AIThreadSafeDC(void) { new (AIThreadSafe<T>::ptr()) T; }
};
/**
* @brief Read lock object and provide read access.
*/
template<typename T>
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<T> const& wrapper)
: mWrapper(const_cast<AIThreadSafe<T>&>(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<T>& wrapper, state_type state)
: mWrapper(wrapper), mState(state) { }
AIThreadSafe<T>& 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<typename T>
struct AIReadAccess : public AIReadAccessConst<T>
{
typedef typename AIReadAccessConst<T>::state_type state_type;
using AIReadAccessConst<T>::readlocked;
//! Construct a AIReadAccess from a non-constant AIThreadSafe.
AIReadAccess(AIThreadSafe<T>& wrapper) : AIReadAccessConst<T>(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(); }
protected:
//! Constructor used by AIWriteAccess.
AIReadAccess(AIThreadSafe<T>& wrapper, state_type state) : AIReadAccessConst<T>(wrapper, state) { }
friend class AIWriteAccess<T>;
};
/**
* @brief Write lock object and provide read/write access.
*/
template<typename T>
struct AIWriteAccess : public AIReadAccess<T>
{
using AIReadAccessConst<T>::readlocked;
using AIReadAccessConst<T>::read2writelocked;
using AIReadAccessConst<T>::writelocked;
using AIReadAccessConst<T>::write2writelocked;
//! Construct a AIWriteAccess from a non-constant AIThreadSafe.
AIWriteAccess(AIThreadSafe<T>& wrapper) : AIReadAccess<T>(wrapper, writelocked) { this->mWrapper.mRWLock.wrlock();}
//! Promote read access to write access.
explicit AIWriteAccess(AIReadAccess<T>& access)
: AIReadAccess<T>(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,
*
* <code>
* class Foo { public: Foo(int, int); };
*
* AITHREADSAFESIMPLE(Foo, foo, (2, 3));
*
* AIAccess<Foo> foo_w(foo);
* // Use foo_w-> for read and write access.
*
* See also AIThreadSafe
*/
template<typename T>
class AIThreadSafeSimple : public AIThreadSafeBits<T>
{
protected:
// Only this one may access the object (through ptr()).
friend struct AIAccess<T>;
// 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<T>::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
*
* <code>
* Foo foo(x, y);
* static Bar bar;
* </code>
*
* One can instantiate a thread-safe instance with
*
* <code>
* AITHREADSAFESIMPLE(Foo, foo, (x, y));
* static AITHREADSAFESIMPLE(Bar, bar, );
* </code>
*
* 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<type> 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
*
* <code>
* Foo foo;
* </code>
*
* One would use
*
* <code>
* AIThreadSafeSimpleDC<Foo> foo;
* </code>
*
* The advantage over AITHREADSAFESIMPLE is that this object can be allocated with
* new on the heap. For example:
*
* <code>
* AIThreadSafeSimpleDC<Foo>* ptr = new AIThreadSafeSimpleDC<Foo>;
* </code>
*
* which is not possible with AITHREADSAFESIMPLE.
*/
template<typename T>
class AIThreadSafeSimpleDC : public AIThreadSafeSimple<T>
{
public:
// Construct a wrapper around a default constructed object.
AIThreadSafeSimpleDC(void) { new (AIThreadSafeSimple<T>::ptr()) T; }
protected:
// For use by AIThreadSafeSimpleDCRootPool
AIThreadSafeSimpleDC(AIAPRPool& parent) : AIThreadSafeSimple<T>(parent) { new (AIThreadSafeSimple<T>::ptr()) T; }
};
// Helper class for AIThreadSafeSimpleDCRootPool to assure initialization of
// the root pool before constructing AIThreadSafeSimpleDC.
class AIThreadSafeSimpleDCRootPool_pbase
{
protected:
AIAPRRootPool mRootPool;
private:
template<typename T> 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<typename T>
class AIThreadSafeSimpleDCRootPool : private AIThreadSafeSimpleDCRootPool_pbase, public AIThreadSafeSimpleDC<T>
{
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<T>(mRootPool) { }
};
/**
* @brief Write lock object and provide read/write access.
*/
template<typename T>
struct AIAccess
{
//! Construct a AIAccess from a non-constant AIThreadSafeSimple.
AIAccess(AIThreadSafeSimple<T>& 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<T>& mWrapper; //!< Reference to the object that we provide access to.
private:
// Disallow copy constructing directly.
AIAccess(AIAccess const&);
};
#endif

View File

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

View File

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

View File

@@ -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<LLVolatileAPRPool*>(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<LLVolatileAPRPool*>(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)

View File

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

View File

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

View File

@@ -43,8 +43,6 @@ class LL_COMMON_API LLCommon
public:
static void initClass();
static void cleanupClass();
private:
static BOOL sAprInitialized;
};
#endif

View File

@@ -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<Globals>& get();
// return the one instance of the globals
private:
CallSiteVector callSites;
friend class AIThreadSafeSimpleDC<Globals>; // Calls constructor.
friend class AIThreadSafeSimple<Globals>; // Calls destructor.
Globals()
: messageStreamInUse(false)
{ }
@@ -386,7 +390,7 @@ namespace
callSites.clear();
}
Globals& Globals::get()
AIThreadSafeSimple<Globals>& 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<Globals>* ts_globals_ptr = new AIThreadSafeSimpleDCRootPool<Globals>;
return *ts_globals_ptr;
}
}
@@ -424,13 +428,16 @@ namespace LLError
int shouldLogCallCounter;
static Settings& get();
static AIThreadSafeSimple<Settings>& get();
static void reset();
static Settings* saveAndReset();
static void restore(Settings*);
static AIThreadSafeSimple<Settings>* saveAndReset();
static void restore(AIThreadSafeSimple<Settings>*);
private:
friend class AIThreadSafeBits<Settings>; // Calls destructor.
friend class AIThreadSafeSimpleDC<Settings>; // 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<Settings>* sSettings;
};
// Pointer to current AIThreadSafeSimple<Settings> object if any (NULL otherwise).
AIThreadSafeSimple<Settings>* Settings::sSettings;
Settings& Settings::get()
AIThreadSafeSimple<Settings>& 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>(Globals::get())->invalidateCallSites();
delete sSettings;
sSettings = new AIThreadSafeSimpleDC<Settings>;
}
Settings* Settings::saveAndReset()
AIThreadSafeSimple<Settings>* Settings::saveAndReset()
{
Globals::get().invalidateCallSites();
Settings*& p = getPtr();
Settings* originalSettings = p;
p = new Settings();
AIAccess<Globals>(Globals::get())->invalidateCallSites();
AIThreadSafeSimple<Settings>* originalSettings = sSettings;
sSettings = new AIThreadSafeSimpleDC<Settings>;
return originalSettings;
}
void Settings::restore(Settings* originalSettings)
void Settings::restore(AIThreadSafeSimple<Settings>* originalSettings)
{
Globals::get().invalidateCallSites();
Settings*& p = getPtr();
delete p;
p = originalSettings;
}
Settings*& Settings::getPtr()
{
static Settings* currentSettings = NULL;
return currentSettings;
AIAccess<Globals>(Globals::get())->invalidateCallSites();
delete sSettings;
sSettings = originalSettings;
}
}
@@ -596,68 +592,64 @@ namespace LLError
commonInit(dir);
}
void setPrintLocation(AIAccess<Settings> const& settings_w, bool print)
{
settings_w->printLocation = print;
}
void setPrintLocation(bool print)
{
Settings& s = Settings::get();
s.printLocation = print;
setPrintLocation(AIAccess<Settings>(Settings::get()), print);
}
void setFatalFunction(const FatalFunction& f)
{
Settings& s = Settings::get();
s.crashFunction = f;
AIAccess<Settings>(Settings::get())->crashFunction = f;
}
FatalFunction getFatalFunction()
{
Settings& s = Settings::get();
return s.crashFunction;
return AIAccess<Settings>(Settings::get())->crashFunction;
}
void setTimeFunction(TimeFunction f)
{
Settings& s = Settings::get();
s.timeFunction = f;
AIAccess<Settings>(Settings::get())->timeFunction = f;
}
void setDefaultLevel(AIAccess<Settings> const& settings_w, ELevel level)
{
AIAccess<Globals>(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>(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>(Globals::get())->invalidateCallSites();
AIAccess<Settings>(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>(Globals::get())->invalidateCallSites();
AIAccess<Settings>(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>(Globals::get())->invalidateCallSites();
AIAccess<Settings>(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>(Globals::get())->invalidateCallSites();
AIAccess<Settings>(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> settings_w(Settings::get());
AIAccess<Globals>(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<Settings> 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>(Settings::get()), recorder);
}
void removeRecorder(AIAccess<Settings> 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>(Settings::get()), recorder);
}
}
@@ -769,12 +767,12 @@ namespace LLError
{
void logToFile(const std::string& file_name)
{
LLError::Settings& s = LLError::Settings::get();
AIAccess<Settings> 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> 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>(Settings::get())->fileRecorderFileName;
}
}
namespace
{
void writeToRecorders(LLError::ELevel level, const std::string& message)
void writeToRecorders(AIAccess<LLError::Settings> 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> 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>(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(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(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(Globals::get());
if (out == &globals->messageStream)
{
globals->messageStream.clear();
globals->messageStream.str("");
globals->messageStreamInUse = false;
}
else
{
delete out;
}
}
AIAccess<Settings> 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<std::string, unsigned int>::iterator messageIter = s.uniqueLogMessages.find(message);
if (messageIter != s.uniqueLogMessages.end())
std::map<std::string, unsigned int>::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<std::string, unsigned int>::iterator messageIter = s.uniqueLogMessages.find(message);
if (messageIter != s.uniqueLogMessages.end())
std::map<std::string, unsigned int>::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<ThreadSafeSettings*>(Settings::saveAndReset());
}
void restoreSettings(Settings* s)
void restoreSettings(ThreadSafeSettings* s)
{
return Settings::restore(s);
Settings::restore(reinterpret_cast<AIThreadSafeSimple<Settings>*>(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>(Settings::get())->shouldLogCallCounter;
}
#if LL_WINDOWS

View File

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

View File

@@ -36,8 +36,7 @@
LLFixedBuffer::LLFixedBuffer(const U32 max_lines)
: LLLineBuffer(),
mMaxLines(max_lines),
mMutex(NULL)
mMaxLines(max_lines)
{
mTimer.reset();
}

View File

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

View File

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

View File

@@ -36,6 +36,7 @@
#include <string>
#include <cstdio>
#include <algorithm>
#include <map>
#if LL_LINUX || LL_SOLARIS
#include <wctype.h>
@@ -212,7 +213,7 @@ public:
/////////////////////////////////////////////////////////////////////////////////////////
// Static Utility functions that operate on std::strings
static std::basic_string<T> null;
static std::basic_string<T> const null;
typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t;
static S32 format(std::basic_string<T>& s, const format_map_t& fmt_map);
@@ -303,7 +304,7 @@ public:
};
template<class T> std::basic_string<T> LLStringUtilBase<T>::null;
template<class T> std::basic_string<T> const LLStringUtilBase<T>::null;
typedef LLStringUtilBase<char> LLStringUtil;
typedef LLStringUtilBase<llwchar> LLWStringUtil;

View File

@@ -72,8 +72,8 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
// Set thread state to running
threadp->mStatus = RUNNING;
// Create a thread local APRFile pool.
LLVolatileAPRPool::createLocalAPRFilePool();
// Create a thread local data.
AIThreadLocalData::create(threadp);
// Run the user supplied function
threadp->run();
@@ -87,24 +87,14 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
}
LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
LLThread::LLThread(std::string const& name) :
mPaused(FALSE),
mName(name),
mAPRThreadp(NULL),
mStatus(STOPPED)
mStatus(STOPPED),
mThreadLocalData(NULL)
{
// Thread creation probably CAN be paranoid about APR being initialized, if necessary
if (poolp)
{
mIsLocalPool = FALSE;
mAPRPoolp = poolp;
}
else
{
mIsLocalPool = TRUE;
apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
}
mRunCondition = new LLCondition(mAPRPoolp);
mRunCondition = new LLCondition;
}
@@ -147,24 +137,18 @@ void LLThread::shutdown()
if (!isStopped())
{
// This thread just wouldn't stop, even though we gave it time
llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl;
llwarns << "LLThread::shutdown() exiting thread before clean exit!" << llendl;
return;
}
mAPRThreadp = NULL;
}
delete mRunCondition;
if (mIsLocalPool)
{
apr_pool_destroy(mAPRPoolp);
}
}
void LLThread::start()
{
apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);
apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, tldata().mRootPool());
// We won't bother joining
apr_thread_detach(mAPRThreadp);
@@ -265,38 +249,72 @@ void LLThread::wakeLocked()
}
}
#ifdef SHOW_ASSERT
// This allows the use of llassert(is_main_thread()) to assure the current thread is the main thread.
static apr_os_thread_t main_thread_id;
LL_COMMON_API bool is_main_thread() { return apr_os_thread_equal(main_thread_id, apr_os_thread_current()); }
#endif
// The thread private handle to access the AIThreadLocalData instance.
apr_threadkey_t* AIThreadLocalData::sThreadLocalDataKey;
//static
void AIThreadLocalData::init(void)
{
// Only do this once.
if (sThreadLocalDataKey)
{
return;
}
apr_status_t status = apr_threadkey_private_create(&sThreadLocalDataKey, &AIThreadLocalData::destroy, AIAPRRootPool::get()());
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 data for the main thread (this function is called by the main thread).
AIThreadLocalData::create(NULL);
#ifdef SHOW_ASSERT
// This function is called by the main thread.
main_thread_id = apr_os_thread_current();
#endif
}
// This is called once for every thread when the thread is destructed.
//static
void AIThreadLocalData::destroy(void* thread_local_data)
{
delete reinterpret_cast<AIThreadLocalData*>(thread_local_data);
}
//static
void AIThreadLocalData::create(LLThread* threadp)
{
AIThreadLocalData* new_tld = new AIThreadLocalData;
if (threadp)
{
threadp->mThreadLocalData = new_tld;
}
apr_status_t status = apr_threadkey_private_set(new_tld, sThreadLocalDataKey);
llassert_always(status == APR_SUCCESS);
}
//static
AIThreadLocalData& AIThreadLocalData::tldata(void)
{
if (!sThreadLocalDataKey)
AIThreadLocalData::init();
void* data;
apr_status_t status = apr_threadkey_private_get(&data, sThreadLocalDataKey);
llassert_always(status == APR_SUCCESS);
return *static_cast<AIThreadLocalData*>(data);
}
//============================================================================
LLMutex::LLMutex(apr_pool_t *poolp) :
mAPRMutexp(NULL)
{
//if (poolp)
//{
// mIsLocalPool = FALSE;
// mAPRPoolp = poolp;
//}
//else
{
mIsLocalPool = TRUE;
apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
}
apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp);
}
LLMutex::~LLMutex()
{
#if _DEBUG
llassert(!isLocked()); // better not be locked!
#endif
apr_thread_mutex_destroy(mAPRMutexp);
mAPRMutexp = NULL;
if (mIsLocalPool)
{
apr_pool_destroy(mAPRPoolp);
}
}
bool LLMutex::isLocked()
bool LLMutexBase::isLocked()
{
if (!tryLock())
{
@@ -308,12 +326,9 @@ bool LLMutex::isLocked()
//============================================================================
LLCondition::LLCondition(apr_pool_t *poolp) :
LLMutex(poolp)
LLCondition::LLCondition(AIAPRPool& parent) : LLMutex(parent)
{
// base class (LLMutex) has already ensured that mAPRPoolp is set up.
apr_thread_cond_create(&mAPRCondp, mAPRPoolp);
apr_thread_cond_create(&mAPRCondp, mPool());
}
LLCondition::~LLCondition()
@@ -349,7 +364,7 @@ void LLThreadSafeRefCount::initThreadSafeRefCount()
{
if (!sMutex)
{
sMutex = new LLMutex(0);
sMutex = new LLMutex;
}
}

View File

@@ -38,11 +38,32 @@
#include "llmemory.h"
#include "apr_thread_cond.h"
#include "aiaprpool.h"
#ifdef SHOW_ASSERT
extern bool is_main_thread(void);
#endif
class LLThread;
class LLMutex;
class LLCondition;
class LL_COMMON_API AIThreadLocalData
{
private:
static apr_threadkey_t* sThreadLocalDataKey;
public:
// Thread-local memory pool.
AIAPRRootPool mRootPool;
AIVolatileAPRPool mVolatileAPRPool;
static void init(void);
static void destroy(void* thread_local_data);
static void create(LLThread* pthread);
static AIThreadLocalData& tldata(void);
};
class LL_COMMON_API LLThread
{
public:
@@ -53,7 +74,7 @@ public:
QUITTING= 2 // Someone wants this thread to quit
} EThreadStatus;
LLThread(const std::string& name, apr_pool_t *poolp = NULL);
LLThread(std::string const& name);
virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state.
virtual void shutdown(); // stops the thread
@@ -82,7 +103,8 @@ public:
// this kicks off the apr thread
void start(void);
apr_pool_t *getAPRPool() { return mAPRPoolp; }
// Return thread-local data for the current thread.
static AIThreadLocalData& tldata(void) { return AIThreadLocalData::tldata(); }
private:
BOOL mPaused;
@@ -95,10 +117,11 @@ protected:
LLCondition* mRunCondition;
apr_thread_t *mAPRThreadp;
apr_pool_t *mAPRPoolp;
BOOL mIsLocalPool;
EThreadStatus mStatus;
friend void AIThreadLocalData::create(LLThread* threadp);
AIThreadLocalData* mThreadLocalData;
void setQuitting();
// virtual function overridden by subclass -- this will be called when the thread runs
@@ -125,12 +148,9 @@ protected:
//============================================================================
class LL_COMMON_API LLMutex
class LL_COMMON_API LLMutexBase
{
public:
LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex
~LLMutex();
void lock() { apr_thread_mutex_lock(mAPRMutexp); }
void unlock() { apr_thread_mutex_unlock(mAPRMutexp); }
// Returns true if lock was obtained successfully.
@@ -139,16 +159,60 @@ public:
bool isLocked(); // non-blocking, but does do a lock/unlock so not free
protected:
apr_thread_mutex_t *mAPRMutexp;
apr_pool_t *mAPRPoolp;
BOOL mIsLocalPool;
// mAPRMutexp is initialized and uninitialized in the derived class.
apr_thread_mutex_t* mAPRMutexp;
};
class LL_COMMON_API LLMutex : public LLMutexBase
{
public:
LLMutex(AIAPRPool& parent = LLThread::tldata().mRootPool) : mPool(parent)
{
apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mPool());
}
~LLMutex()
{
llassert(!isLocked()); // better not be locked!
apr_thread_mutex_destroy(mAPRMutexp);
mAPRMutexp = NULL;
}
protected:
AIAPRPool mPool;
};
#if APR_HAS_THREADS
// No need to use a root pool in this case.
typedef LLMutex LLMutexRootPool;
#else // APR_HAS_THREADS
class LL_COMMON_API LLMutexRootPool : public LLMutexBase
{
public:
LLMutexRootPool(void)
{
apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mRootPool());
}
~LLMutexRootPool()
{
#if APR_POOL_DEBUG
// It is allowed to destruct root pools from a different thread.
mRootPool.grab_ownership();
#endif
llassert(!isLocked()); // better not be locked!
apr_thread_mutex_destroy(mAPRMutexp);
mAPRMutexp = NULL;
}
protected:
AIAPRRootPool mRootPool;
};
#endif // APR_HAS_THREADS
// Actually a condition/mutex pair (since each condition needs to be associated with a mutex).
class LL_COMMON_API LLCondition : public LLMutex
{
public:
LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well.
LLCondition(AIAPRPool& parent = LLThread::tldata().mRootPool);
~LLCondition();
void wait(); // blocks
@@ -162,7 +226,7 @@ protected:
class LL_COMMON_API LLMutexLock
{
public:
LLMutexLock(LLMutex* mutex)
LLMutexLock(LLMutexBase* mutex)
{
mMutex = mutex;
mMutex->lock();
@@ -172,7 +236,102 @@ public:
mMutex->unlock();
}
private:
LLMutex* mMutex;
LLMutexBase* mMutex;
};
class AIRWLock
{
public:
AIRWLock(AIAPRPool& parent = LLThread::tldata().mRootPool) :
mWriterWaitingMutex(parent), mNoHoldersCondition(parent), mHoldersCount(0), mWriterIsWaiting(false) { }
private:
LLMutex mWriterWaitingMutex; //!< This mutex is locked while some writer is waiting for access.
LLCondition mNoHoldersCondition; //!< Access control for mHoldersCount. Condition true when there are no more holders.
int mHoldersCount; //!< Number of readers or -1 if a writer locked this object.
// This is volatile because we read it outside the critical area of mWriterWaitingMutex, at [1].
// That means that other threads can change it while we are already in the (inlined) function rdlock.
// Without volatile, the following assembly would fail:
// register x = mWriterIsWaiting;
// /* some thread changes mWriterIsWaiting */
// if (x ...
// However, because the function is fuzzy to begin with (we don't mind that this race
// condition exists) it would work fine without volatile. So, basically it's just here
// out of principle ;). -- Aleric
bool volatile mWriterIsWaiting; //!< True when there is a writer waiting for write access.
public:
void rdlock(bool high_priority = false)
{
// Give a writer a higher priority (kinda fuzzy).
if (mWriterIsWaiting && !high_priority) // [1] If there is a writer interested,
{
mWriterWaitingMutex.lock(); // [2] then give it precedence and wait here.
// If we get here then the writer got it's access; mHoldersCount == -1.
mWriterWaitingMutex.unlock();
}
mNoHoldersCondition.lock(); // [3] Get exclusive access to mHoldersCount.
while (mHoldersCount == -1) // [4]
{
mNoHoldersCondition.wait(); // [5] Wait till mHoldersCount is (or just was) 0.
}
++mHoldersCount; // One more reader.
mNoHoldersCondition.unlock(); // Release lock on mHoldersCount.
}
void rdunlock(void)
{
mNoHoldersCondition.lock(); // Get exclusive access to mHoldersCount.
if (--mHoldersCount == 0) // Was this the last reader?
{
mNoHoldersCondition.signal(); // Tell waiting threads, see [5], [6] and [7].
}
mNoHoldersCondition.unlock(); // Release lock on mHoldersCount.
}
void wrlock(void)
{
mWriterWaitingMutex.lock(); // Block new readers, see [2],
mWriterIsWaiting = true; // from this moment on, see [1].
mNoHoldersCondition.lock(); // Get exclusive access to mHoldersCount.
while (mHoldersCount != 0) // Other readers or writers have this lock?
{
mNoHoldersCondition.wait(); // [6] Wait till mHoldersCount is (or just was) 0.
}
mWriterIsWaiting = false; // Stop checking the lock for new readers, see [1].
mWriterWaitingMutex.unlock(); // Release blocked readers, they will still hang at [3].
mHoldersCount = -1; // We are a writer now (will cause a hang at [5], see [4]).
mNoHoldersCondition.unlock(); // Release lock on mHolders (readers go from [3] to [5]).
}
void wrunlock(void)
{
mNoHoldersCondition.lock(); // Get exclusive access to mHoldersCount.
mHoldersCount = 0; // We have no writer anymore.
mNoHoldersCondition.signal(); // Tell waiting threads, see [5], [6] and [7].
mNoHoldersCondition.unlock(); // Release lock on mHoldersCount.
}
void rd2wrlock(void)
{
mNoHoldersCondition.lock(); // Get exclusive access to mHoldersCount. Blocks new readers at [3].
if (--mHoldersCount > 0) // Any other reads left?
{
mWriterWaitingMutex.lock(); // Block new readers, see [2],
mWriterIsWaiting = true; // from this moment on, see [1].
while (mHoldersCount != 0) // Other readers (still) have this lock?
{
mNoHoldersCondition.wait(); // [7] Wait till mHoldersCount is (or just was) 0.
}
mWriterIsWaiting = false; // Stop checking the lock for new readers, see [1].
mWriterWaitingMutex.unlock(); // Release blocked readers, they will still hang at [3].
}
mHoldersCount = -1; // We are a writer now (will cause a hang at [5], see [4]).
mNoHoldersCondition.unlock(); // Release lock on mHolders (readers go from [3] to [5]).
}
void wr2rdlock(void)
{
mNoHoldersCondition.lock(); // Get exclusive access to mHoldersCount.
mHoldersCount = 1; // Turn writer into a reader.
mNoHoldersCondition.signal(); // Tell waiting readers, see [5].
mNoHoldersCondition.unlock(); // Release lock on mHoldersCount.
}
};
//============================================================================
@@ -187,7 +346,6 @@ void LLThread::unlockData()
mRunCondition->unlock();
}
//============================================================================
// see llmemory.h for LLPointer<> definition

View File

@@ -43,7 +43,7 @@
LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded) :
LLQueuedThread(name, threaded)
{
mDeleteMutex = new LLMutex(NULL);
mDeleteMutex = new LLMutex;
}
LLWorkerThread::~LLWorkerThread()
@@ -205,7 +205,6 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na
mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
mWorkerClassName(name),
mRequestHandle(LLWorkerThread::nullHandle()),
mMutex(NULL),
mWorkFlags(0)
{
if (!mWorkerThread)

View File

@@ -200,7 +200,7 @@ protected:
U32 mRequestPriority; // last priority set
private:
LLMutex mMutex;
LLMutexRootPool mMutex; // Use LLMutexRootPool since this object is created and destructed by multiple threads.
LLAtomicU32 mWorkFlags;
};

3
indra/llcrashlogger/llcrashlogger.cpp Executable file → Normal file
View File

@@ -387,8 +387,7 @@ bool LLCrashLogger::init()
return false;
}
gServicePump = new LLPumpIO(gAPRPoolp);
gServicePump->prime(gAPRPoolp);
gServicePump = new LLPumpIO;
LLHTTPClient::setPump(*gServicePump);
//If we've opened the crash logger, assume we can delete the marker file if it exists

0
indra/llcrashlogger/llcrashlogger.h Executable file → Normal file
View File

View File

@@ -57,7 +57,7 @@ LLMutex* LLImage::sMutex = NULL;
//static
void LLImage::initClass()
{
sMutex = new LLMutex(NULL);
sMutex = new LLMutex;
LLImageJ2C::openDSO();
}

View File

@@ -47,7 +47,7 @@ typedef const char* (*EngineInfoLLImageJ2CFunction)();
CreateLLImageJ2CFunction j2cimpl_create_func;
DestroyLLImageJ2CFunction j2cimpl_destroy_func;
EngineInfoLLImageJ2CFunction j2cimpl_engineinfo_func;
apr_pool_t *j2cimpl_dso_memory_pool;
AIAPRPool j2cimpl_dso_memory_pool;
apr_dso_handle_t *j2cimpl_dso_handle;
//Declare the prototype for theses functions here, their functionality
@@ -82,13 +82,12 @@ void LLImageJ2C::openDSO()
gDirUtilp->getExecutableDir());
j2cimpl_dso_handle = NULL;
j2cimpl_dso_memory_pool = NULL;
j2cimpl_dso_memory_pool.create();
//attempt to load the shared library
apr_pool_create(&j2cimpl_dso_memory_pool, NULL);
rv = apr_dso_load(&j2cimpl_dso_handle,
dso_path.c_str(),
j2cimpl_dso_memory_pool);
j2cimpl_dso_memory_pool());
//now, check for success
if ( rv == APR_SUCCESS )
@@ -152,11 +151,7 @@ void LLImageJ2C::openDSO()
j2cimpl_dso_handle = NULL;
}
if ( j2cimpl_dso_memory_pool )
{
apr_pool_destroy(j2cimpl_dso_memory_pool);
j2cimpl_dso_memory_pool = NULL;
}
j2cimpl_dso_memory_pool.destroy();
}
}
@@ -164,7 +159,7 @@ void LLImageJ2C::openDSO()
void LLImageJ2C::closeDSO()
{
if ( j2cimpl_dso_handle ) apr_dso_unload(j2cimpl_dso_handle);
if (j2cimpl_dso_memory_pool) apr_pool_destroy(j2cimpl_dso_memory_pool);
j2cimpl_dso_memory_pool.destroy();
}
//static

View File

@@ -41,20 +41,13 @@
LLImageDecodeThread::LLImageDecodeThread(bool threaded)
: LLQueuedThread("imagedecode", threaded)
{
mCreationMutex = new LLMutex(getAPRPool());
}
//virtual
LLImageDecodeThread::~LLImageDecodeThread()
{
delete mCreationMutex ;
}
// MAIN THREAD
// virtual
S32 LLImageDecodeThread::update(U32 max_time_ms)
{
LLMutexLock lock(mCreationMutex);
LLMutexLock lock(&mCreationMutex);
for (creation_list_t::iterator iter = mCreationList.begin();
iter != mCreationList.end(); ++iter)
{
@@ -77,7 +70,7 @@ S32 LLImageDecodeThread::update(U32 max_time_ms)
LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* image,
U32 priority, S32 discard, BOOL needs_aux, Responder* responder)
{
LLMutexLock lock(mCreationMutex);
LLMutexLock lock(&mCreationMutex);
handle_t handle = generateHandle();
mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder));
return handle;
@@ -87,7 +80,7 @@ LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted*
// Returns the size of the mutex guarded list as an indication of sanity
S32 LLImageDecodeThread::tut_size()
{
LLMutexLock lock(mCreationMutex);
LLMutexLock lock(&mCreationMutex);
S32 res = mCreationList.size();
return res;
}

View File

@@ -78,8 +78,6 @@ public:
public:
LLImageDecodeThread(bool threaded = true);
virtual ~LLImageDecodeThread();
handle_t decodeImage(LLImageFormatted* image,
U32 priority, S32 discard, BOOL needs_aux,
Responder* responder);
@@ -103,7 +101,7 @@ private:
};
typedef std::list<creation_info> creation_list_t;
creation_list_t mCreationList;
LLMutex* mCreationMutex;
LLMutex mCreationMutex;
};
#endif

View File

@@ -55,7 +55,7 @@ LLVolumeMgr::LLVolumeMgr()
{
// the LLMutex magic interferes with easy unit testing,
// so you now must manually call useMutex() to use it
//mDataMutex = new LLMutex(gAPRPoolp);
//mDataMutex = new LLMutex;
}
LLVolumeMgr::~LLVolumeMgr()
@@ -222,7 +222,7 @@ void LLVolumeMgr::useMutex()
{
if (!mDataMutex)
{
mDataMutex = new LLMutex(gAPRPoolp);
mDataMutex = new LLMutex;
}
}

View File

@@ -44,6 +44,7 @@
#include "llapr.h"
#define CARES_STATICLIB
#include "llares.h"
#include "llscopedvolatileaprpool.h"
#if defined(LL_WINDOWS)
# define ns_c_in 1
@@ -467,11 +468,6 @@ void LLAres::search(const std::string &query, LLResType type,
bool LLAres::process(U64 timeout)
{
if (!gAPRPoolp)
{
ll_init_apr();
}
ares_socket_t socks[ARES_GETSOCK_MAXNUM];
apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM];
apr_int32_t nsds = 0;
@@ -485,10 +481,7 @@ bool LLAres::process(U64 timeout)
return nsds > 0;
}
apr_status_t status;
LLAPRPool pool;
status = pool.getStatus() ;
ll_apr_assert_status(status);
LLScopedVolatileAPRPool scoped_pool;
for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++)
{
@@ -505,7 +498,7 @@ bool LLAres::process(U64 timeout)
apr_socket_t *aprSock = NULL;
status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], pool.getAPRPool());
apr_status_t status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], scoped_pool);
if (status != APR_SUCCESS)
{
ll_apr_warn_status(status);
@@ -514,7 +507,7 @@ bool LLAres::process(U64 timeout)
aprFds[nactive].desc.s = aprSock;
aprFds[nactive].desc_type = APR_POLL_SOCKET;
aprFds[nactive].p = pool.getAPRPool();
aprFds[nactive].p = scoped_pool;
aprFds[nactive].rtnevents = 0;
aprFds[nactive].client_data = &socks[i];
@@ -523,7 +516,7 @@ bool LLAres::process(U64 timeout)
if (nactive > 0)
{
status = apr_poll(aprFds, nactive, &nsds, timeout);
apr_status_t status = apr_poll(aprFds, nactive, &nsds, timeout);
if (status != APR_SUCCESS && status != APR_TIMEUP)
{

View File

@@ -1082,7 +1082,7 @@ void LLCurl::initClass()
S32 mutex_count = CRYPTO_num_locks();
for (S32 i=0; i<mutex_count; i++)
{
sSSLMutex.push_back(new LLMutex(NULL));
sSSLMutex.push_back(new LLMutex);
}
CRYPTO_set_id_callback(&LLCurl::ssl_thread_id);
CRYPTO_set_locking_callback(&LLCurl::ssl_locking_callback);

View File

@@ -960,13 +960,9 @@ private:
// static
LLHTTPNode& LLIOHTTPServer::create(
apr_pool_t* pool, LLPumpIO& pump, U16 port)
LLHTTPNode& LLIOHTTPServer::create(LLPumpIO& pump, U16 port)
{
LLSocket::ptr_t socket = LLSocket::create(
pool,
LLSocket::STREAM_TCP,
port);
LLSocket::ptr_t socket = LLSocket::create(LLSocket::STREAM_TCP, port);
if(!socket)
{
llerrs << "Unable to initialize socket" << llendl;
@@ -975,7 +971,7 @@ LLHTTPNode& LLIOHTTPServer::create(
LLHTTPResponseFactory* factory = new LLHTTPResponseFactory;
boost::shared_ptr<LLChainIOFactory> factory_ptr(factory);
LLIOServerSocket* server = new LLIOServerSocket(pool, socket, factory_ptr);
LLIOServerSocket* server = new LLIOServerSocket(socket, factory_ptr);
LLPumpIO::chain_t chain;
chain.push_back(LLIOPipe::ptr_t(server));

View File

@@ -56,7 +56,7 @@ class LLIOHTTPServer
public:
typedef void (*timing_callback_t)(const char* hashed_name, F32 time, void* data);
static LLHTTPNode& create(apr_pool_t* pool, LLPumpIO& pump, U16 port);
static LLHTTPNode& create(LLPumpIO& pump, U16 port);
/**< Creates an HTTP wire server on the pump for the given TCP port.
*
* Returns the root node of the new server. Add LLHTTPNode instances

View File

@@ -41,6 +41,7 @@
#include "llhost.h"
#include "llmemtype.h"
#include "llpumpio.h"
#include "llthread.h"
//
// constants
@@ -104,51 +105,31 @@ void ll_debug_socket(const char* msg, apr_socket_t* apr_sock)
///
// static
LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
LLSocket::ptr_t LLSocket::create(EType type, U16 port)
{
LLMemType m1(LLMemType::MTYPE_IO_TCP);
LLSocket::ptr_t rv;
apr_socket_t* socket = NULL;
apr_pool_t* new_pool = NULL;
apr_status_t status = APR_EGENERAL;
// create a pool for the socket
status = apr_pool_create(&new_pool, pool);
if(ll_apr_warn_status(status))
{
if(new_pool) apr_pool_destroy(new_pool);
return rv;
}
LLSocket::ptr_t rv(new LLSocket);
if(STREAM_TCP == type)
{
status = apr_socket_create(
&socket,
APR_INET,
SOCK_STREAM,
APR_PROTO_TCP,
new_pool);
status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, rv->mPool());
}
else if(DATAGRAM_UDP == type)
{
status = apr_socket_create(
&socket,
APR_INET,
SOCK_DGRAM,
APR_PROTO_UDP,
new_pool);
status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, rv->mPool());
}
else
{
if(new_pool) apr_pool_destroy(new_pool);
rv.reset();
return rv;
}
if(ll_apr_warn_status(status))
{
if(new_pool) apr_pool_destroy(new_pool);
rv->mSocket = NULL;
rv.reset();
return rv;
}
rv = ptr_t(new LLSocket(socket, new_pool));
if(port > 0)
{
apr_sockaddr_t* sa = NULL;
@@ -158,7 +139,7 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
APR_UNSPEC,
port,
0,
new_pool);
rv->mPool());
if(ll_apr_warn_status(status))
{
rv.reset();
@@ -166,8 +147,8 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
}
// This allows us to reuse the address on quick down/up. This
// is unlikely to create problems.
ll_apr_warn_status(apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1));
status = apr_socket_bind(socket, sa);
ll_apr_warn_status(apr_socket_opt_set(rv->mSocket, APR_SO_REUSEADDR, 1));
status = apr_socket_bind(rv->mSocket, sa);
if(ll_apr_warn_status(status))
{
rv.reset();
@@ -181,7 +162,7 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
// to keep a queue of incoming connections for ACCEPT.
lldebugs << "Setting listen state for socket." << llendl;
status = apr_socket_listen(
socket,
rv->mSocket,
LL_DEFAULT_LISTEN_BACKLOG);
if(ll_apr_warn_status(status))
{
@@ -202,21 +183,28 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
}
// static
LLSocket::ptr_t LLSocket::create(apr_socket_t* socket, apr_pool_t* pool)
LLSocket::ptr_t LLSocket::create(apr_status_t& status, LLSocket::ptr_t& listen_socket)
{
LLMemType m1(LLMemType::MTYPE_IO_TCP);
LLSocket::ptr_t rv;
if(!socket)
if (!listen_socket->getSocket())
{
status = APR_ENOSOCKET;
return LLSocket::ptr_t();
}
LLSocket::ptr_t rv(new LLSocket);
lldebugs << "accepting socket" << llendl;
status = apr_socket_accept(&rv->mSocket, listen_socket->getSocket(), rv->mPool());
if (status != APR_SUCCESS)
{
rv->mSocket = NULL;
rv.reset();
return rv;
}
rv = ptr_t(new LLSocket(socket, pool));
rv->mPort = PORT_EPHEMERAL;
rv->setOptions();
return rv;
}
bool LLSocket::blockingConnect(const LLHost& host)
{
if(!mSocket) return false;
@@ -229,7 +217,7 @@ bool LLSocket::blockingConnect(const LLHost& host)
APR_UNSPEC,
host.getPort(),
0,
mPool)))
mPool())))
{
return false;
}
@@ -240,13 +228,11 @@ bool LLSocket::blockingConnect(const LLHost& host)
return true;
}
LLSocket::LLSocket(apr_socket_t* socket, apr_pool_t* pool) :
mSocket(socket),
mPool(pool),
LLSocket::LLSocket() :
mSocket(NULL),
mPool(LLThread::tldata().mRootPool),
mPort(PORT_INVALID)
{
ll_debug_socket("Constructing wholely formed socket", mSocket);
LLMemType m1(LLMemType::MTYPE_IO_TCP);
}
LLSocket::~LLSocket()
@@ -258,10 +244,6 @@ LLSocket::~LLSocket()
ll_debug_socket("Destroying socket", mSocket);
apr_socket_close(mSocket);
}
if(mPool)
{
apr_pool_destroy(mPool);
}
}
void LLSocket::setOptions()
@@ -522,10 +504,8 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl(
///
LLIOServerSocket::LLIOServerSocket(
apr_pool_t* pool,
LLIOServerSocket::socket_t listener,
factory_t factory) :
mPool(pool),
mListenSocket(listener),
mReactor(factory),
mInitialized(false),
@@ -585,21 +565,15 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
lldebugs << "accepting socket" << llendl;
PUMP_DEBUG;
apr_pool_t* new_pool = NULL;
apr_status_t status = apr_pool_create(&new_pool, mPool);
apr_socket_t* socket = NULL;
status = apr_socket_accept(
&socket,
mListenSocket->getSocket(),
new_pool);
LLSocket::ptr_t llsocket(LLSocket::create(socket, new_pool));
apr_status_t status;
LLSocket::ptr_t llsocket(LLSocket::create(status, mListenSocket));
//EStatus rv = STATUS_ERROR;
if(llsocket)
if(llsocket && status == APR_SUCCESS)
{
PUMP_DEBUG;
apr_sockaddr_t* remote_addr;
apr_socket_addr_get(&remote_addr, APR_REMOTE, socket);
apr_socket_addr_get(&remote_addr, APR_REMOTE, llsocket->getSocket());
char* remote_host_string;
apr_sockaddr_ip_get(&remote_host_string, remote_addr);
@@ -614,7 +588,6 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
{
chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(llsocket)));
pump->addChain(chain, mResponseTimeout);
status = STATUS_OK;
}
else
{
@@ -623,7 +596,8 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
}
else
{
llwarns << "Unable to create linden socket." << llendl;
char buf[256];
llwarns << "Unable to accept linden socket: " << apr_strerror(status, buf, sizeof(buf)) << llendl;
}
PUMP_DEBUG;
@@ -636,11 +610,10 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
#if 0
LLIODataSocket::LLIODataSocket(
U16 suggested_port,
U16 start_discovery_port,
apr_pool_t* pool) :
U16 start_discovery_port) :
mSocket(NULL)
{
if(!pool || (PORT_INVALID == suggested_port)) return;
if(PORT_INVALID == suggested_port) return;
if(ll_apr_warn_status(apr_socket_create(&mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, pool))) return;
apr_sockaddr_t* sa = NULL;
if(ll_apr_warn_status(apr_sockaddr_info_get(&sa, APR_ANYADDR, APR_UNSPEC, suggested_port, 0, pool))) return;

View File

@@ -44,7 +44,6 @@
*/
#include "lliopipe.h"
#include "apr_pools.h"
#include "apr_network_io.h"
#include "llchainio.h"
@@ -94,34 +93,22 @@ public:
* socket. If you intend the socket to be known to external
* clients without prior port notification, do not use
* PORT_EPHEMERAL.
* @param pool The apr pool to use. A child pool will be created
* and associated with the socket.
* @param type The type of socket to create
* @param port The port for the socket
* @return A valid socket shared pointer if the call worked.
*/
static ptr_t create(
apr_pool_t* pool,
EType type,
U16 port = PORT_EPHEMERAL);
/**
* @brief Create a LLSocket when you already have an apr socket.
* @brief Create a LLSocket by accepting a connection from a listen socket.
*
* This method assumes an ephemeral port. This is typically used
* by calls which spawn a socket such as a call to
* <code>accept()</code> as in the server socket. This call should
* not fail if you have a valid apr socket.
* Because of the nature of how accept() works, you are expected
* to create a new pool for the socket, use that pool for the
* accept, and pass it in here where it will be bound with the
* socket and destroyed at the same time.
* @param socket The apr socket to use
* @param pool The pool used to create the socket. *NOTE: The pool
* passed in will be DESTROYED.
* @param status Output. Status of the accept if a valid listen socket was passed.
* @param listen_socket The listen socket to use.
* @return A valid socket shared pointer if the call worked.
*/
static ptr_t create(apr_socket_t* socket, apr_pool_t* pool);
static ptr_t create(apr_status_t& status, ptr_t& listen_socket);
/**
* @brief Perform a blocking connect to a host. Do not use in production.
@@ -156,7 +143,7 @@ protected:
* @brief Protected constructor since should only make sockets
* with one of the two <code>create()</code> calls.
*/
LLSocket(apr_socket_t* socket, apr_pool_t* pool);
LLSocket(void);
/**
* @brief Set default socket options.
@@ -173,8 +160,8 @@ protected:
// The apr socket.
apr_socket_t* mSocket;
// our memory pool
apr_pool_t* mPool;
// Our memory pool.
AIAPRPool mPool;
// The port if we know it.
U16 mPort;
@@ -299,7 +286,7 @@ class LLIOServerSocket : public LLIOPipe
public:
typedef LLSocket::ptr_t socket_t;
typedef boost::shared_ptr<LLChainIOFactory> factory_t;
LLIOServerSocket(apr_pool_t* pool, socket_t listener, factory_t reactor);
LLIOServerSocket(socket_t listener, factory_t reactor);
virtual ~LLIOServerSocket();
/**
@@ -331,7 +318,6 @@ protected:
//@}
protected:
apr_pool_t* mPool;
socket_t mListenSocket;
factory_t mReactor;
bool mInitialized;
@@ -365,8 +351,7 @@ public:
*/
LLIODataSocket(
U16 suggested_port,
U16 start_discovery_port,
apr_pool_t* pool);
U16 start_discovery_port);
virtual ~LLIODataSocket();
protected:

View File

@@ -56,6 +56,7 @@
#include "llstring.h"
#include "lluuid.h"
#include "net.h"
#include "aiaprpool.h"
//
// constants
@@ -63,7 +64,7 @@
const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE = 4096;
static bool gMailEnabled = true;
static apr_pool_t* gMailPool;
static AIAPRPool gMailPool;
static apr_sockaddr_t* gSockAddr;
static apr_socket_t* gMailSocket;
@@ -88,7 +89,7 @@ bool connect_smtp()
gSockAddr->sa.sin.sin_family,
SOCK_STREAM,
APR_PROTO_TCP,
gMailPool);
gMailPool());
if(ll_apr_warn_status(status)) return false;
status = apr_socket_connect(gMailSocket, gSockAddr);
if(ll_apr_warn_status(status))
@@ -145,19 +146,19 @@ BOOL LLMail::send(
}
// static
void LLMail::init(const std::string& hostname, apr_pool_t* pool)
void LLMail::init(const std::string& hostname)
{
gMailSocket = NULL;
if(hostname.empty() || !pool)
if (hostname.empty())
{
gMailPool = NULL;
gSockAddr = NULL;
gMailPool.destroy();
}
else
{
gMailPool = pool;
gMailPool.create();
// collect all the information into a socaddr sturcture. the
// Collect all the information into a sockaddr structure. the
// documentation is a bit unclear, but I either have to
// specify APR_UNSPEC or not specify any flags. I am not sure
// which option is better.
@@ -167,7 +168,7 @@ void LLMail::init(const std::string& hostname, apr_pool_t* pool)
APR_UNSPEC,
25,
APR_IPV4_ADDR_OK,
gMailPool);
gMailPool());
ll_apr_warn_status(status);
}
}

View File

@@ -33,15 +33,13 @@
#ifndef LL_LLMAIL_H
#define LL_LLMAIL_H
typedef struct apr_pool_t apr_pool_t;
#include "llsd.h"
class LLMail
{
public:
// if hostname is NULL, then the host is resolved as 'mail'
static void init(const std::string& hostname, apr_pool_t* pool);
static void init(const std::string& hostname);
// Allow all email transmission to be disabled/enabled.
static void enable(bool mail_enabled);

View File

@@ -43,6 +43,7 @@
#include "llmemtype.h"
#include "llstl.h"
#include "llstat.h"
#include "llthread.h"
#include "llfasttimer.h"
#include <iterator> //VS2010
@@ -170,14 +171,12 @@ struct ll_delete_apr_pollset_fd_client_data
/**
* LLPumpIO
*/
LLPumpIO::LLPumpIO(apr_pool_t* pool) :
LLPumpIO::LLPumpIO(void) :
mState(LLPumpIO::NORMAL),
mRebuildPollset(false),
mPollset(NULL),
mPollsetClientID(0),
mNextLock(0),
mPool(NULL),
mCurrentPool(NULL),
mCurrentPoolReallocCount(0),
mChainsMutex(NULL),
mCallbackMutex(NULL),
@@ -186,21 +185,24 @@ LLPumpIO::LLPumpIO(apr_pool_t* pool) :
mCurrentChain = mRunningChains.end();
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
initialize(pool);
initialize();
}
LLPumpIO::~LLPumpIO()
{
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
cleanup();
}
bool LLPumpIO::prime(apr_pool_t* pool)
{
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
cleanup();
initialize(pool);
return ((pool == NULL) ? false : true);
#if LL_THREADS_APR
if (mChainsMutex) apr_thread_mutex_destroy(mChainsMutex);
if (mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex);
#endif
mChainsMutex = NULL;
mCallbackMutex = NULL;
if(mPollset)
{
// lldebugs << "cleaning up pollset" << llendl;
apr_pollset_destroy(mPollset);
mPollset = NULL;
}
}
bool LLPumpIO::addChain(const chain_t& chain, F32 timeout)
@@ -360,8 +362,7 @@ bool LLPumpIO::setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll)
{
// each fd needs a pool to work with, so if one was
// not specified, use this pool.
// *FIX: Should it always be this pool?
value.second.p = mPool;
value.second.p = (*mCurrentChain).mDescriptorsPool->operator()();
}
value.second.client_data = new S32(++mPollsetClientID);
(*mCurrentChain).mDescriptors.push_back(value);
@@ -828,39 +829,15 @@ void LLPumpIO::control(LLPumpIO::EControl op)
}
}
void LLPumpIO::initialize(apr_pool_t* pool)
void LLPumpIO::initialize(void)
{
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
if(!pool) return;
mPool.create();
#if LL_THREADS_APR
// SJB: Windows defaults to NESTED and OSX defaults to UNNESTED, so use UNNESTED explicitly.
apr_thread_mutex_create(&mChainsMutex, APR_THREAD_MUTEX_UNNESTED, pool);
apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, pool);
apr_thread_mutex_create(&mChainsMutex, APR_THREAD_MUTEX_UNNESTED, mPool());
apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, mPool());
#endif
mPool = pool;
}
void LLPumpIO::cleanup()
{
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
#if LL_THREADS_APR
if(mChainsMutex) apr_thread_mutex_destroy(mChainsMutex);
if(mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex);
#endif
mChainsMutex = NULL;
mCallbackMutex = NULL;
if(mPollset)
{
// lldebugs << "cleaning up pollset" << llendl;
apr_pollset_destroy(mPollset);
mPollset = NULL;
}
if(mCurrentPool)
{
apr_pool_destroy(mCurrentPool);
mCurrentPool = NULL;
}
mPool = NULL;
}
void LLPumpIO::rebuildPollset()
@@ -888,21 +865,19 @@ void LLPumpIO::rebuildPollset()
if(mCurrentPool
&& (0 == (++mCurrentPoolReallocCount % POLLSET_POOL_RECYCLE_COUNT)))
{
apr_pool_destroy(mCurrentPool);
mCurrentPool = NULL;
mCurrentPool.destroy();
mCurrentPoolReallocCount = 0;
}
if(!mCurrentPool)
{
apr_status_t status = apr_pool_create(&mCurrentPool, mPool);
(void)ll_apr_warn_status(status);
mCurrentPool.create(mPool);
}
// add all of the file descriptors
run_it = mRunningChains.begin();
LLChainInfo::conditionals_t::iterator fd_it;
LLChainInfo::conditionals_t::iterator fd_end;
apr_pollset_create(&mPollset, size, mCurrentPool, 0);
apr_pollset_create(&mPollset, size, mCurrentPool(), 0);
for(; run_it != run_end; ++run_it)
{
fd_it = (*run_it).mDescriptors.begin();
@@ -1160,7 +1135,8 @@ bool LLPumpIO::handleChainError(
LLPumpIO::LLChainInfo::LLChainInfo() :
mInit(false),
mLock(0),
mEOS(false)
mEOS(false),
mDescriptorsPool(new AIAPRPool(LLThread::tldata().mRootPool))
{
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
mTimer.setTimerExpirySec(DEFAULT_CHAIN_EXPIRY_SECS);

View File

@@ -36,11 +36,12 @@
#define LL_LLPUMPIO_H
#include <set>
#include <boost/shared_ptr.hpp>
#if LL_LINUX // needed for PATH_MAX in APR.
#include <sys/param.h>
#endif
#include "apr_pools.h"
#include "aiaprpool.h"
#include "llbuffer.h"
#include "llframetimer.h"
#include "lliopipe.h"
@@ -64,9 +65,8 @@ extern const F32 NEVER_CHAIN_EXPIRY_SECS;
* <code>pump()</code> on a thread used for IO and call
* <code>respond()</code> on a thread that is expected to do higher
* level processing. You can call almost any other method from any
* thread - see notes for each method for details. In order for the
* threading abstraction to work, you need to call <code>prime()</code>
* with a valid apr pool.
* thread - see notes for each method for details.
*
* A pump instance manages much of the state for the pipe, including
* the list of pipes in the chain, the channel for each element in the
* chain, the buffer, and if any pipe has marked the stream or process
@@ -85,24 +85,13 @@ public:
/**
* @brief Constructor.
*/
LLPumpIO(apr_pool_t* pool);
LLPumpIO(void);
/**
* @brief Destructor.
*/
~LLPumpIO();
/**
* @brief Prepare this pump for usage.
*
* If you fail to call this method prior to use, the pump will
* try to work, but will not come with any thread locking
* mechanisms.
* @param pool The apr pool to use.
* @return Returns true if the pump is primed.
*/
bool prime(apr_pool_t* pool);
/**
* @brief Typedef for having a chain of pipes.
*/
@@ -374,6 +363,7 @@ protected:
typedef std::pair<LLIOPipe::ptr_t, apr_pollfd_t> pipe_conditional_t;
typedef std::vector<pipe_conditional_t> conditionals_t;
conditionals_t mDescriptors;
boost::shared_ptr<AIAPRPool> mDescriptorsPool;
};
// All the running chains & info
@@ -392,9 +382,9 @@ protected:
callbacks_t mPendingCallbacks;
callbacks_t mCallbacks;
// memory allocator for pollsets & mutexes.
apr_pool_t* mPool;
apr_pool_t* mCurrentPool;
// Memory pool for pollsets & mutexes.
AIAPRPool mPool;
AIAPRPool mCurrentPool;
S32 mCurrentPoolReallocCount;
#if LL_THREADS_APR
@@ -406,8 +396,7 @@ protected:
#endif
protected:
void initialize(apr_pool_t* pool);
void cleanup();
void initialize();
/**
* @brief Given the internal state of the chains, rebuild the pollset

0
indra/llmessage/llsdmessagebuilder.cpp Executable file → Normal file
View File

0
indra/llmessage/llsdmessagebuilder.h Executable file → Normal file
View File

0
indra/llmessage/llsdmessagereader.cpp Executable file → Normal file
View File

0
indra/llmessage/llsdmessagereader.h Executable file → Normal file
View File

View File

@@ -45,6 +45,7 @@
#include "llstring.h"
#include "apr_env.h"
#include "llapr.h"
#include "llscopedvolatileaprpool.h"
static const U32 HTTP_STATUS_PIPE_ERROR = 499;
/**
@@ -161,27 +162,31 @@ void LLURLRequest::setCallback(LLURLRequestComplete* callback)
// is called with use_proxy = FALSE
void LLURLRequest::useProxy(bool use_proxy)
{
static char *env_proxy;
static std::string env_proxy;
if (use_proxy && (env_proxy == NULL))
if (use_proxy && env_proxy.empty())
{
apr_status_t status;
LLAPRPool pool;
status = apr_env_get(&env_proxy, "ALL_PROXY", pool.getAPRPool());
char* env_proxy_str;
LLScopedVolatileAPRPool scoped_pool;
apr_status_t status = apr_env_get(&env_proxy_str, "ALL_PROXY", scoped_pool);
if (status != APR_SUCCESS)
{
status = apr_env_get(&env_proxy, "http_proxy", pool.getAPRPool());
status = apr_env_get(&env_proxy_str, "http_proxy", scoped_pool);
}
if (status != APR_SUCCESS)
{
use_proxy = FALSE;
use_proxy = false;
}
else
{
// env_proxy_str is stored in the scoped_pool, so we have to make a copy.
env_proxy = env_proxy_str;
}
}
lldebugs << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = \"" << env_proxy << "\"" << llendl;
lldebugs << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (env_proxy ? env_proxy : "(null)") << llendl;
if (env_proxy && use_proxy)
if (use_proxy)
{
mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, env_proxy);
}

View File

@@ -107,8 +107,10 @@ std::string get_shared_secret();
class LLMessagePollInfo
{
public:
LLMessagePollInfo(void) : mPool(LLThread::tldata().mRootPool) { }
apr_socket_t *mAPRSocketp;
apr_pollfd_t mPollFD;
AIAPRPool mPool;
};
namespace
@@ -297,20 +299,13 @@ LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port,
}
// LL_DEBUGS("Messaging") << << "*** port: " << mPort << llendl;
//
// Create the data structure that we can poll on
//
if (!gAPRPoolp)
{
LL_ERRS("Messaging") << "No APR pool before message system initialization!" << llendl;
ll_init_apr();
}
apr_socket_t *aprSocketp = NULL;
apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, gAPRPoolp);
mPollInfop = new LLMessagePollInfo;
apr_socket_t *aprSocketp = NULL;
apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, mPollInfop->mPool());
mPollInfop->mAPRSocketp = aprSocketp;
mPollInfop->mPollFD.p = gAPRPoolp;
mPollInfop->mPollFD.p = mPollInfop->mPool();
mPollInfop->mPollFD.desc_type = APR_POLL_SOCKET;
mPollInfop->mPollFD.reqevents = APR_POLLIN;
mPollInfop->mPollFD.rtnevents = 0;

0
indra/llplugin/llpluginclassmedia.cpp Executable file → Normal file
View File

0
indra/llplugin/llpluginclassmedia.h Executable file → Normal file
View File

0
indra/llplugin/llpluginclassmediaowner.h Executable file → Normal file
View File

5
indra/llplugin/llplugininstance.cpp Executable file → Normal file
View File

@@ -36,8 +36,7 @@
#include "linden_common.h"
#include "llplugininstance.h"
#include "llapr.h"
#include "aiaprpool.h"
/** Virtual destructor. */
LLPluginInstanceMessageListener::~LLPluginInstanceMessageListener()
@@ -86,7 +85,7 @@ int LLPluginInstance::load(std::string &plugin_file)
int result = apr_dso_load(&mDSOHandle,
plugin_file.c_str(),
gAPRPoolp);
AIAPRRootPool::get()());
if(result != APR_SUCCESS)
{
char buf[1024];

0
indra/llplugin/llplugininstance.h Executable file → Normal file
View File

0
indra/llplugin/llpluginmessage.cpp Executable file → Normal file
View File

0
indra/llplugin/llpluginmessage.h Executable file → Normal file
View File

0
indra/llplugin/llpluginmessageclasses.h Executable file → Normal file
View File

2
indra/llplugin/llpluginmessagepipe.cpp Executable file → Normal file
View File

@@ -99,8 +99,6 @@ void LLPluginMessagePipeOwner::killMessagePipe(void)
}
LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket):
mInputMutex(gAPRPoolp),
mOutputMutex(gAPRPoolp),
mOwner(owner),
mSocket(socket)
{

0
indra/llplugin/llpluginmessagepipe.h Executable file → Normal file
View File

2
indra/llplugin/llpluginprocesschild.cpp Executable file → Normal file
View File

@@ -47,7 +47,7 @@ LLPluginProcessChild::LLPluginProcessChild()
{
mState = STATE_UNINITIALIZED;
mInstance = NULL;
mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
mSocket = LLSocket::create(LLSocket::STREAM_TCP);
mSleepTime = PLUGIN_IDLE_SECONDS; // default: send idle messages at 100Hz
mCPUElapsed = 0.0f;
mBlockingRequest = false;

0
indra/llplugin/llpluginprocesschild.h Executable file → Normal file
View File

55
indra/llplugin/llpluginprocessparent.cpp Executable file → Normal file
View File

@@ -49,6 +49,7 @@ LLPluginProcessParentOwner::~LLPluginProcessParentOwner()
bool LLPluginProcessParent::sUseReadThread = false;
apr_pollset_t *LLPluginProcessParent::sPollSet = NULL;
AIAPRPool LLPluginProcessParent::sPollSetPool;
bool LLPluginProcessParent::sPollsetNeedsRebuild = false;
LLMutex *LLPluginProcessParent::sInstancesMutex;
std::list<LLPluginProcessParent*> LLPluginProcessParent::sInstances;
@@ -59,7 +60,7 @@ class LLPluginProcessParentPollThread: public LLThread
{
public:
LLPluginProcessParentPollThread() :
LLThread("LLPluginProcessParentPollThread", gAPRPoolp)
LLThread("LLPluginProcessParentPollThread")
{
}
protected:
@@ -84,12 +85,11 @@ protected:
};
LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
mIncomingQueueMutex(gAPRPoolp)
LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner)
{
if(!sInstancesMutex)
{
sInstancesMutex = new LLMutex(gAPRPoolp);
sInstancesMutex = new LLMutex;
}
mOwner = owner;
@@ -102,6 +102,7 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
mBlocked = false;
mPolledInput = false;
mPollFD.client_data = NULL;
mPollFDPool.create();
mPluginLaunchTimeout = 60.0f;
mPluginLockupTimeout = 15.0f;
@@ -177,44 +178,28 @@ void LLPluginProcessParent::init(const std::string &launcher_filename, const std
bool LLPluginProcessParent::accept()
{
bool result = false;
apr_status_t status = APR_EGENERAL;
apr_socket_t *new_socket = NULL;
status = apr_socket_accept(
&new_socket,
mListenSocket->getSocket(),
gAPRPoolp);
mSocket = LLSocket::create(status, mListenSocket);
if(status == APR_SUCCESS)
{
// llinfos << "SUCCESS" << llendl;
// Success. Create a message pipe on the new socket
// we MUST create a new pool for the LLSocket, since it will take ownership of it and delete it in its destructor!
apr_pool_t* new_pool = NULL;
status = apr_pool_create(&new_pool, gAPRPoolp);
mSocket = LLSocket::create(new_socket, new_pool);
new LLPluginMessagePipe(this, mSocket);
result = true;
}
else if(APR_STATUS_IS_EAGAIN(status))
{
// llinfos << "EAGAIN" << llendl;
// No incoming connections. This is not an error.
status = APR_SUCCESS;
}
else
{
// llinfos << "Error:" << llendl;
ll_apr_warn_status(status);
// Some other error.
errorState();
mSocket.reset();
// EAGAIN means "No incoming connections". This is not an error.
if (!APR_STATUS_IS_EAGAIN(status))
{
// Some other error.
ll_apr_warn_status(status);
errorState();
}
}
return result;
@@ -283,7 +268,7 @@ void LLPluginProcessParent::idle(void)
apr_status_t status = APR_SUCCESS;
apr_sockaddr_t* addr = NULL;
mListenSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
mListenSocket = LLSocket::create(LLSocket::STREAM_TCP);
mBoundPort = 0;
// This code is based on parts of LLSocket::create() in lliosocket.cpp.
@@ -294,7 +279,7 @@ void LLPluginProcessParent::idle(void)
APR_INET,
0, // port 0 = ephemeral ("find me a port")
0,
gAPRPoolp);
AIAPRRootPool::get()());
if(ll_apr_warn_status(status))
{
@@ -617,7 +602,8 @@ void LLPluginProcessParent::setMessagePipe(LLPluginMessagePipe *message_pipe)
if(message_pipe != NULL)
{
// Set up the apr_pollfd_t
mPollFD.p = gAPRPoolp;
mPollFD.p = mPollFDPool();
mPollFD.desc_type = APR_POLL_SOCKET;
mPollFD.reqevents = APR_POLLIN|APR_POLLERR|APR_POLLHUP;
mPollFD.rtnevents = 0;
@@ -664,6 +650,7 @@ void LLPluginProcessParent::updatePollset()
// delete the existing pollset.
apr_pollset_destroy(sPollSet);
sPollSet = NULL;
sPollSetPool.destroy();
}
std::list<LLPluginProcessParent*>::iterator iter;
@@ -686,12 +673,14 @@ void LLPluginProcessParent::updatePollset()
{
#ifdef APR_POLLSET_NOCOPY
// The pollset doesn't exist yet. Create it now.
apr_status_t status = apr_pollset_create(&sPollSet, count, gAPRPoolp, APR_POLLSET_NOCOPY);
sPollSetPool.create();
apr_status_t status = apr_pollset_create(&sPollSet, count, sPollSetPool(), APR_POLLSET_NOCOPY);
if(status != APR_SUCCESS)
{
#endif // APR_POLLSET_NOCOPY
LL_WARNS("PluginPoll") << "Couldn't create pollset. Falling back to non-pollset mode." << LL_ENDL;
sPollSet = NULL;
sPollSetPool.destroy();
#ifdef APR_POLLSET_NOCOPY
}
else

2
indra/llplugin/llpluginprocessparent.h Executable file → Normal file
View File

@@ -186,7 +186,9 @@ private:
static bool sUseReadThread;
apr_pollfd_t mPollFD;
AIAPRPool mPollFDPool;
static apr_pollset_t *sPollSet;
static AIAPRPool sPollSetPool;
static bool sPollsetNeedsRebuild;
static LLMutex *sInstancesMutex;
static std::list<LLPluginProcessParent*> sInstances;

9
indra/llplugin/llpluginsharedmemory.cpp Executable file → Normal file
View File

@@ -201,7 +201,8 @@ bool LLPluginSharedMemory::create(size_t size)
mName += createName();
mSize = size;
apr_status_t status = apr_shm_create( &(mImpl->mAprSharedMemory), mSize, mName.c_str(), gAPRPoolp );
mPool.create();
apr_status_t status = apr_shm_create( &(mImpl->mAprSharedMemory), mSize, mName.c_str(), mPool());
if(ll_apr_warn_status(status))
{
@@ -224,7 +225,7 @@ bool LLPluginSharedMemory::destroy(void)
}
mImpl->mAprSharedMemory = NULL;
}
mPool.destroy();
return true;
}
@@ -233,7 +234,8 @@ bool LLPluginSharedMemory::attach(const std::string &name, size_t size)
mName = name;
mSize = size;
apr_status_t status = apr_shm_attach( &(mImpl->mAprSharedMemory), mName.c_str(), gAPRPoolp );
mPool.create();
apr_status_t status = apr_shm_attach( &(mImpl->mAprSharedMemory), mName.c_str(), mPool() );
if(ll_apr_warn_status(status))
{
@@ -255,6 +257,7 @@ bool LLPluginSharedMemory::detach(void)
}
mImpl->mAprSharedMemory = NULL;
}
mPool.destroy();
return true;
}

3
indra/llplugin/llpluginsharedmemory.h Executable file → Normal file
View File

@@ -35,6 +35,8 @@
#ifndef LL_LLPLUGINSHAREDMEMORY_H
#define LL_LLPLUGINSHAREDMEMORY_H
#include "aiaprpool.h"
class LLPluginSharedMemoryPlatformImpl;
/**
@@ -115,6 +117,7 @@ private:
bool close(void);
bool unlink(void);
AIAPRPool mPool;
std::string mName;
size_t mSize;
void *mMappedAddress;

4
indra/llplugin/slplugin/slplugin.cpp Executable file → Normal file
View File

@@ -183,8 +183,6 @@ int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdL
int main(int argc, char **argv)
#endif
{
ll_init_apr();
// Set up llerror logging
{
LLError::initForApplication(".");
@@ -400,8 +398,6 @@ int main(int argc, char **argv)
delete plugin;
ll_cleanup_apr();
return 0;
}

0
indra/llui/llmemberlistener.h Executable file → Normal file
View File

View File

@@ -1194,13 +1194,13 @@ void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements)
if (found != replacements.end())
{
replacement = found->second;
//llwarns << "replaceSubstituionStrings: value: " << value << " repl: " << replacement << llendl;
//llinfos << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << llendl;
it->second->setValue(replacement);
}
else
{
llwarns << "replaceSubstituionStrings FAILURE: value: " << value << " repl: " << replacement << llendl;
llwarns << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << llendl;
}
}
}

View File

@@ -58,6 +58,7 @@
#include "llimagegl.h"
#include "llwindow.h"
#include "lltextparser.h"
#include "lldir.h"
#include <queue>
#include "llmenugl.h"
#include "../newview/lgghunspell_wrapper.h"
@@ -4004,7 +4005,10 @@ void LLTextEditor::appendColoredText(const std::string &new_text,
const std::string& font_name)
{
LLColor4 lcolor=color;
if (mParseHighlights)
// If LindenUserDir is empty then we didn't login yet.
// In that case we can't instantiate LLTextParser, which
// is initialized per user.
if (mParseHighlights && !gDirUtilp->getLindenUserDir(true).empty())
{
LLTextParser* highlight = LLTextParser::getInstance();
highlight->parseFullLineHighlights(new_text, &lcolor);
@@ -4082,7 +4086,10 @@ void LLTextEditor::appendHighlightedText(const std::string &new_text,
S32 highlight_part,
LLStyleSP stylep)
{
if (mParseHighlights)
// If LindenUserDir is empty then we didn't login yet.
// In that case we can't instantiate LLTextParser, which
// is initialized per user.
if (mParseHighlights && !gDirUtilp->getLindenUserDir(true).empty())
{
LLTextParser* highlight = LLTextParser::getInstance();

0
indra/llui/lluistring.cpp Executable file → Normal file
View File

0
indra/llui/lluistring.h Executable file → Normal file
View File

View File

@@ -193,8 +193,9 @@ const std::string &LLDir::getOSUserAppDir() const
return mOSUserAppDir;
}
const std::string &LLDir::getLindenUserDir() const
const std::string &LLDir::getLindenUserDir(bool empty_ok) const
{
llassert(empty_ok || !mLindenUserDir.empty());
return mLindenUserDir;
}

View File

@@ -92,7 +92,7 @@ class LLDir
const std::string &getAppRODataDir() const; // Location of read-only data files
const std::string &getOSUserDir() const; // Location of the os-specific user dir
const std::string &getOSUserAppDir() const; // Location of the os-specific user app dir
const std::string &getLindenUserDir() const; // Location of the Linden user dir.
const std::string &getLindenUserDir(bool empty_ok = false) const; // Location of the Linden user dir.
const std::string &getChatLogsDir() const; // Location of the chat logs dir.
const std::string &getPerAccountChatLogsDir() const; // Location of the per account chat logs dir.
const std::string &getTempDir() const; // Common temporary directory

View File

@@ -97,7 +97,7 @@ LLDir_Linux::LLDir_Linux()
mAppRODataDir = tmp_str;
mOSUserDir = getCurrentUserHome(tmp_str);
mOSUserAppDir = "";
mLindenUserDir = tmp_str;
mLindenUserDir = "";
char path [32]; /* Flawfinder: ignore */

View File

@@ -100,7 +100,7 @@ LLDir_Solaris::LLDir_Solaris()
mAppRODataDir = strdup(tmp_str);
mOSUserDir = getCurrentUserHome(tmp_str);
mOSUserAppDir = "";
mLindenUserDir = tmp_str;
mLindenUserDir = "";
char path [LL_MAX_PATH]; /* Flawfinder: ignore */

0
indra/llvfs/llpidlock.cpp Executable file → Normal file
View File

0
indra/llvfs/llpidlock.h Executable file → Normal file
View File

View File

@@ -219,7 +219,7 @@ const S32 LLVFSFileBlock::SERIAL_SIZE = 34;
LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename, const BOOL read_only, const U32 presize, const BOOL remove_after_crash)
: mRemoveAfterCrash(remove_after_crash)
{
mDataMutex = new LLMutex(0);
mDataMutex = new LLMutex;
S32 i;
for (i = 0; i < VFSLOCK_COUNT; i++)
@@ -566,8 +566,9 @@ LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename
}
}
LL_WARNS("VFS") << "Using index file " << mIndexFilename << LL_ENDL;
LL_WARNS("VFS") << "Using data file " << mDataFilename << LL_ENDL;
// Success!
LL_INFOS("VFS") << "Using index file " << mIndexFilename << LL_ENDL;
LL_INFOS("VFS") << "Using data file " << mDataFilename << LL_ENDL;
mValid = VFSVALID_OK;
}

0
indra/llwindow/glh/glh_linear.h Executable file → Normal file
View File

View File

@@ -66,7 +66,20 @@ const S32 CURRENT_VERSION = 101;
//So, a global it is!
bool gCOAEnabled = false;
LLControlVariable *LLControlVariable::getCOAActive()
LLControlVariable* LLControlVariable::getCOAActive()
{
//if no coa connection, return 'this'
//if per account is ON and this IS a parent, return child var
//if per account is ON and this IS NOT a parent, return 'this'
//if per account is OFF and this IS NOT a parent, return parent var
//if per account is OFF and this IS a parent, return 'this'
if(getCOAConnection() && gCOAEnabled == isCOAParent())
return getCOAConnection();
else
return this;
}
LLControlVariable const* LLControlVariable::getCOAActive() const
{
//if no coa connection, return 'this'
//if per account is ON and this IS a parent, return child var
@@ -282,11 +295,9 @@ LLSD LLControlVariable::getSaveValue() const
#if PROF_CTRL_CALLS
std::vector<std::pair<std::string, U32>> gSettingsCallMap;
#endif //PROF_CTRL_CALLS
LLPointer<LLControlVariable> LLControlGroup::getControl(const std::string& name)
static update_gSettingsCallMap(ctrl_name_table_t::const_iterator const& iter)
{
ctrl_name_table_t::iterator iter = mNameTable.find(name);
#if PROF_CTRL_CALLS
if(iter != mNameTable.end())
{
std::vector<std::pair<std::string, U32>>::iterator iter2 = gSettingsCallMap.begin();
@@ -302,13 +313,32 @@ LLPointer<LLControlVariable> LLControlGroup::getControl(const std::string& name)
if(iter2 == gSettingsCallMap.end())
gSettingsCallMap.push_back(std::pair<std::string, U32>(name.c_str(),1));
}
}
#endif //PROF_CTRL_CALLS
LLControlVariable* LLControlGroup::getControl(std::string const& name)
{
ctrl_name_table_t::iterator iter = mNameTable.find(name);
#if PROF_CTRL_CALLS
update_gSettingsCallMap(iter);
#endif //PROF_CTRL_CALLS
if(iter != mNameTable.end())
return iter->second->getCOAActive();
else
return LLPointer<LLControlVariable>();
return NULL;
}
LLControlVariable const* LLControlGroup::getControl(std::string const& name) const
{
ctrl_name_table_t::const_iterator iter = mNameTable.find(name);
#if PROF_CTRL_CALLS
update_gSettingsCallMap(iter);
#endif //PROF_CTRL_CALLS
if(iter != mNameTable.end())
return iter->second->getCOAActive();
else
return NULL;
}
////////////////////////////////////////////////////////////////////////////
@@ -502,9 +532,9 @@ std::string LLControlGroup::findString(const std::string& name)
return LLStringUtil::null;
}
std::string LLControlGroup::getString(const std::string& name)
std::string LLControlGroup::getString(const std::string& name) const
{
LLControlVariable* control = getControl(name);
LLControlVariable const* control = getControl(name);
if (control && control->isType(TYPE_STRING))
return control->get().asString();
@@ -649,9 +679,9 @@ LLSD LLControlGroup::getLLSD(const std::string& name)
return LLSD();
}
BOOL LLControlGroup::controlExists(const std::string& name)
BOOL LLControlGroup::controlExists(const std::string& name) const
{
ctrl_name_table_t::iterator iter = mNameTable.find(name);
ctrl_name_table_t::const_iterator iter = mNameTable.find(name);
return iter != mNameTable.end();
}

View File

@@ -122,7 +122,7 @@ public:
const std::string& getComment() const { return mComment; }
eControlType type() { return mType; }
bool isType(eControlType tp) { return tp == mType; }
bool isType(eControlType tp) const { return tp == mType; }
void resetToDefault(bool fire_signal = false);
@@ -153,7 +153,8 @@ public:
bool isCOA() const { return mIsCOA; }
bool isCOAParent() const { return mIsCOAParent; }
LLControlVariable *getCOAConnection() const { return mCOAConnectedVar; }
LLControlVariable *getCOAActive();
LLControlVariable* getCOAActive();
LLControlVariable const* getCOAActive() const;
void setIsCOA(bool IsCOA) { mIsCOA=IsCOA; }
void setCOAConnect(LLControlVariable *pConnect, bool IsParent)
{
@@ -185,7 +186,8 @@ public:
~LLControlGroup();
void cleanup();
LLPointer<LLControlVariable> getControl(const std::string& name);
LLControlVariable* getControl(std::string const& name);
LLControlVariable const* getControl(std::string const& name) const;
struct ApplyFunctor
{
@@ -210,7 +212,7 @@ public:
std::string findString(const std::string& name);
std::string getString(const std::string& name);
std::string getString(const std::string& name) const;
LLWString getWString(const std::string& name);
std::string getText(const std::string& name);
LLVector3 getVector3(const std::string& name);
@@ -245,7 +247,7 @@ public:
void setValue(const std::string& name, const LLSD& val);
BOOL controlExists(const std::string& name);
BOOL controlExists(const std::string& name) const;
// Returns number of controls loaded, 0 if failed
// If require_declaration is false, will auto-declare controls it finds

View File

@@ -46,7 +46,7 @@ public:
LLControlGroupReader() {}
virtual ~LLControlGroupReader() {}
virtual std::string getString(const std::string& name) = 0;
virtual std::string getString(const std::string& name) const = 0;
//virtual LLWString getWString(const std::string& name) = 0;
virtual std::string getText(const std::string& name) = 0;
//virtual LLVector3 getVector3(const std::string& name) = 0;

0
indra/media_plugins/CMakeLists.txt Executable file → Normal file
View File

0
indra/media_plugins/base/media_plugin_base.cpp Executable file → Normal file
View File

0
indra/media_plugins/base/media_plugin_base.h Executable file → Normal file
View File

View File

@@ -79,4 +79,4 @@ if (DARWIN)
LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp"
)
endif (DARWIN)
endif (DARWIN)

0
indra/media_plugins/example/media_plugin_example.cpp Executable file → Normal file
View File

0
indra/media_plugins/quicktime/CMakeLists.txt Executable file → Normal file
View File

View File

1
indra/media_plugins/webkit/CMakeLists.txt Executable file → Normal file
View File

@@ -27,6 +27,7 @@ include_directories(
${LLIMAGE_INCLUDE_DIRS}
${LLRENDER_INCLUDE_DIRS}
${LLWINDOW_INCLUDE_DIRS}
${LLQTWEBKIT_INCLUDE_DIR}
)

0
indra/media_plugins/webkit/dummy_volume_catcher.cpp Executable file → Normal file
View File

14
indra/media_plugins/webkit/linux_volume_catcher.cpp Executable file → Normal file
View File

@@ -50,7 +50,7 @@ extern "C" {
#include <pulse/subscribe.h>
#include <pulse/glib-mainloop.h> // There's no special reason why we want the *glib* PA mainloop, but the generic polling implementation seems broken.
#include "apr_pools.h"
#include "aiaprpool.h"
#include "apr_dso.h"
}
@@ -66,7 +66,7 @@ extern "C" {
#undef LL_PA_SYM
static bool sSymsGrabbed = false;
static apr_pool_t *sSymPADSOMemoryPool = NULL;
static AIAPRPool sSymPADSOMemoryPool;
static apr_dso_handle_t *sSymPADSOHandleG = NULL;
bool grab_pa_syms(std::string pulse_dso_name)
@@ -85,11 +85,11 @@ bool grab_pa_syms(std::string pulse_dso_name)
#define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##PASYM, sSymPADSOHandle, #PASYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #PASYM); if (REQUIRED) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #PASYM, (void*)ll##PASYM);}while(0)
//attempt to load the shared library
apr_pool_create(&sSymPADSOMemoryPool, NULL);
sSymPADSOMemoryPool.create();
if ( APR_SUCCESS == (rv = apr_dso_load(&sSymPADSOHandle,
pulse_dso_name.c_str(),
sSymPADSOMemoryPool) ))
sSymPADSOMemoryPool()) ))
{
INFOMSG("Found DSO: %s", pulse_dso_name.c_str());
@@ -132,11 +132,7 @@ void ungrab_pa_syms()
sSymPADSOHandleG = NULL;
}
if ( sSymPADSOMemoryPool )
{
apr_pool_destroy(sSymPADSOMemoryPool);
sSymPADSOMemoryPool = NULL;
}
sSymPADSOMemoryPool.destroy();
// NULL-out all of the symbols we'd grabbed
#define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) do{ll##PASYM = NULL;}while(0)

View File

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