diff --git a/linden/doc/contributions.txt b/linden/doc/contributions.txt
index f51891160..9712c6ec7 100644
--- a/linden/doc/contributions.txt
+++ b/linden/doc/contributions.txt
@@ -80,6 +80,8 @@ Aleric Inglewood
IMP-578
IMP-579
IMP-581
+ IMP-590
+ IMP-592
IMP-595
IMP-660
IMP-661
@@ -88,6 +90,11 @@ Aleric Inglewood
IMP-664
IMP-667
IMP-670
+ IMP-688
+ IMP-692
+ IMP-701
+ IMP-712
+ IMP-734
Alissa Sabre
VWR-81
VWR-83
@@ -336,6 +343,8 @@ Khyota Wulluf
Kunnis Basiat
VWR-82
VWR-102
+Lance Corrimal
+ SNOW-717
Lisa Lowe
CT-218
CT-219
@@ -463,6 +472,9 @@ Nicholaz Beresford
VWR-2412
VWR-2682
VWR-2684
+Nicky Perian
+ IMP-680
+ IMP-685
Nounouch Hapmouche
VWR-238
Patric Mills
diff --git a/linden/indra/cmake/00-Common.cmake b/linden/indra/cmake/00-Common.cmake
index 4c04be975..7e85ce0c0 100644
--- a/linden/indra/cmake/00-Common.cmake
+++ b/linden/indra/cmake/00-Common.cmake
@@ -194,8 +194,8 @@ if (DARWIN)
add_definitions(-DLL_DARWIN=1)
set(CMAKE_CXX_LINK_FLAGS "-Wl,-headerpad_max_install_names,-search_paths_first")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_LINK_FLAGS}")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mlong-branch -msse3 -msse4.1 -msse4.2 -mssse3 -w")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mlong-branch -msse3 -msse4.1 -msse4.2 -mssse3 -w")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mlong-branch -msse3 -mssse3 -w")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mlong-branch -msse3 -mssse3 -w")
# NOTE: it's critical that the optimization flag is put in front.
# NOTE: it's critical to have both CXX_FLAGS and C_FLAGS covered.
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O0 ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
@@ -210,7 +210,7 @@ if (LINUX OR DARWIN)
set(GCC_WARNINGS "${GCC_WARNINGS} -Werror")
endif (NOT GCC_DISABLE_FATAL_WARNINGS)
- set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor")
+ set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual")
set(CMAKE_C_FLAGS "${GCC_WARNINGS} ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${GCC_CXX_WARNINGS} ${CMAKE_CXX_FLAGS}")
diff --git a/linden/indra/cmake/APR.cmake b/linden/indra/cmake/APR.cmake
index e9f64118d..d1f089891 100644
--- a/linden/indra/cmake/APR.cmake
+++ b/linden/indra/cmake/APR.cmake
@@ -14,27 +14,27 @@ 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}/apriconv-1.lib
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/apriconv-1.lib
+ 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 ${APRICONV_LIBRARIES}
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/aprutil-1.lib ${APRICONV_LIBRARIES}
+ 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
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.a
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.a
+ debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.0.3.7.dylib
+ optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.0.3.7.dylib
)
set(APRUTIL_LIBRARIES
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.a
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.a
+ debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.0.3.8.dylib
+ optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.0.3.8.dylib
)
set(APRICONV_LIBRARIES iconv)
else (WINDOWS)
diff --git a/linden/indra/cmake/BerkeleyDB.cmake b/linden/indra/cmake/BerkeleyDB.cmake
index d98e79179..de627638a 100644
--- a/linden/indra/cmake/BerkeleyDB.cmake
+++ b/linden/indra/cmake/BerkeleyDB.cmake
@@ -6,6 +6,11 @@ set(DB_FIND_REQUIRED ON)
if (STANDALONE)
include(FindBerkeleyDB)
else (STANDALONE)
- set(DB_LIBRARIES db-4.2)
+ if (LINUX)
+ # Need to add dependency pthread explicitely to support ld.gold.
+ set(DB_LIBRARIES db-4.2 pthread)
+ else (LINUX)
+ set(DB_LIBRARIES db-4.2)
+ endif (LINUX)
set(DB_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
endif (STANDALONE)
diff --git a/linden/indra/cmake/CopyWinLibs.cmake b/linden/indra/cmake/CopyWinLibs.cmake
index a091a3177..f5846891b 100644
--- a/linden/indra/cmake/CopyWinLibs.cmake
+++ b/linden/indra/cmake/CopyWinLibs.cmake
@@ -29,6 +29,9 @@ set(debug_files
openal32.dll
openjpegd.dll
libhunspell.dll
+ libapr-1.dll
+ libaprutil-1.dll
+ libapriconv-1.dll
)
copy_if_different(
@@ -209,6 +212,9 @@ set(release_files
openal32.dll
openjpeg.dll
libhunspell.dll
+ libapr-1.dll
+ libaprutil-1.dll
+ libapriconv-1.dll
)
copy_if_different(
diff --git a/linden/indra/cmake/LLCommon.cmake b/linden/indra/cmake/LLCommon.cmake
index 9158e9824..d87d3c015 100644
--- a/linden/indra/cmake/LLCommon.cmake
+++ b/linden/indra/cmake/LLCommon.cmake
@@ -7,20 +7,15 @@ include(ZLIB)
set(LLCOMMON_INCLUDE_DIRS
${LIBS_OPEN_DIR}/llcommon
- ${APRUTIL_INCLUDE_DIR}
${APR_INCLUDE_DIR}
${Boost_INCLUDE_DIRS}
)
-# Files that need PIC code (pluginAPI) need to set REQUIRE_PIC on 64bit systems
-# this will link against a llcommon built with Position Independent Code
-# this is a requirment to link a static library (.a) to a DSO on 64 bit systems
-
-if(REQUIRE_PIC)
- set(LLCOMMON_LIBRARIES llcommonPIC)
-else(REQUIRE_PIC)
- set(LLCOMMON_LIBRARIES llcommon)
-endif(REQUIRE_PIC)
-
-#force clear the flag, files that need this must explicity set it themselves
-set(REQUIRE_PIC 0)
\ No newline at end of file
+if (LINUX)
+ # In order to support using ld.gold on linux, we need to explicitely
+ # specify all libraries that llcommon uses.
+ # llcommon uses `clock_gettime' which is provided by librt on linux.
+ set(LLCOMMON_LIBRARIES llcommon rt)
+else (LINUX)
+ set(LLCOMMON_LIBRARIES llcommon)
+endif (LINUX)
diff --git a/linden/indra/cmake/LLPlugin.cmake b/linden/indra/cmake/LLPlugin.cmake
index 9722f16c3..7ee404b9b 100644
--- a/linden/indra/cmake/LLPlugin.cmake
+++ b/linden/indra/cmake/LLPlugin.cmake
@@ -5,4 +5,10 @@ set(LLPLUGIN_INCLUDE_DIRS
${LIBS_OPEN_DIR}/llplugin
)
-set(LLPLUGIN_LIBRARIES llplugin)
+if (LINUX)
+ # In order to support using ld.gold on linux, we need to explicitely
+ # specify all libraries that llplugin uses.
+ set(LLPLUGIN_LIBRARIES llplugin pthread)
+else (LINUX)
+ set(LLPLUGIN_LIBRARIES llplugin)
+endif (LINUX)
diff --git a/linden/indra/cmake/ViewerMiscLibs.cmake b/linden/indra/cmake/ViewerMiscLibs.cmake
index 35f4e3aaf..38d044473 100644
--- a/linden/indra/cmake/ViewerMiscLibs.cmake
+++ b/linden/indra/cmake/ViewerMiscLibs.cmake
@@ -4,10 +4,12 @@ include(Prebuilt)
if (NOT STANDALONE)
use_prebuilt_binary(libuuid)
use_prebuilt_binary(vivox)
- if(LINUX AND ${ARCH} STREQUAL "x86_64")
+ if(LINUX)
+ if (${ARCH} STREQUAL "x86_64")
use_prebuilt_binary(32bitcompatibilitylibs)
- endif(LINUX AND ${ARCH} STREQUAL "x86_64")
- use_prebuilt_binary(fontconfig)
+ endif (${ARCH} STREQUAL "x86_64")
+ use_prebuilt_binary(fontconfig)
+ endif(LINUX)
else (NOT STANDALONE)
# Download there even when using standalone.
set(STANDALONE OFF)
diff --git a/linden/indra/develop.py b/linden/indra/develop.py
index 2ce9f91af..e80437473 100755
--- a/linden/indra/develop.py
+++ b/linden/indra/develop.py
@@ -76,6 +76,7 @@ class PlatformSetup(object):
build_type = build_types['relwithdebinfo']
standalone = 'OFF'
unattended = 'OFF'
+ universal = 'OFF'
project_name = 'Imprudence'
distcc = True
cmake_opts = []
@@ -404,7 +405,7 @@ def os(self):
return 'darwin'
def arch(self):
- if self.unattended == 'ON':
+ if self.universal == 'ON':
return 'universal'
else:
return UnixSetup.arch(self)
@@ -417,10 +418,10 @@ def cmake_commandline(self, src_dir, build_dir, opts, simple):
standalone=self.standalone,
unattended=self.unattended,
project_name=self.project_name,
- universal='',
+ universal=self.universal,
type=self.build_type.upper()
)
- if self.unattended == 'ON':
+ if self.universal == 'ON':
args['universal'] = '-DCMAKE_OSX_ARCHITECTURES:STRING=\'i386\''
#if simple:
# return 'cmake %(opts)s %(dir)r' % args
@@ -696,6 +697,7 @@ def cmake_commandline(self, src_dir, build_dir, opts, simple):
--standalone build standalone, without Linden prebuild libraries
--unattended build unattended, do not invoke any tools requiring
a human response
+ --universal build a universal binary on Mac OS X (unsupported)
-t | --type=NAME build type ("Debug", "Release", or "RelWithDebInfo")
-N | --no-distcc disable use of distcc
-G | --generator=NAME generator name
diff --git a/linden/indra/lib/python/indra/util/llmanifest.py b/linden/indra/lib/python/indra/util/llmanifest.py
index 3444a1585..fc777b27a 100644
--- a/linden/indra/lib/python/indra/util/llmanifest.py
+++ b/linden/indra/lib/python/indra/util/llmanifest.py
@@ -121,6 +121,9 @@ def get_channel(srctree):
default=""),
dict(name='artwork', description='Artwork directory.', default=DEFAULT_SRCTREE),
dict(name='build', description='Build directory.', default=DEFAULT_SRCTREE),
+ dict(name='buildtype',
+ description='Set to DEBUG if this is a debug build.',
+ default="RELEASE"),
dict(name='channel',
description="""The channel to use for updates, packaging, settings name, etc.""",
default=get_channel),
diff --git a/linden/indra/llcharacter/llcharacter.cpp b/linden/indra/llcharacter/llcharacter.cpp
index dcdfe074e..46ac3262e 100644
--- a/linden/indra/llcharacter/llcharacter.cpp
+++ b/linden/indra/llcharacter/llcharacter.cpp
@@ -38,6 +38,7 @@
#include "llcharacter.h"
#include "llstring.h"
+#include "llfasttimer.h"
#define SKEL_HEADER "Linden Skeleton 1.0"
diff --git a/linden/indra/llcommon/CMakeLists.txt b/linden/indra/llcommon/CMakeLists.txt
index 7d001ae57..2444b004b 100644
--- a/linden/indra/llcommon/CMakeLists.txt
+++ b/linden/indra/llcommon/CMakeLists.txt
@@ -4,6 +4,7 @@ project(llcommon)
include(00-Common)
include(LLCommon)
+include(Linking)
include_directories(
${EXPAT_INCLUDE_DIRS}
@@ -12,6 +13,7 @@ include_directories(
)
set(llcommon_SOURCE_FILES
+ aiaprpool.cpp
imageids.cpp
indra_constants.cpp
llapp.cpp
@@ -73,6 +75,8 @@ set(llcommon_SOURCE_FILES
set(llcommon_HEADER_FILES
CMakeLists.txt
+ aiaprpool.h
+ aithreadsafe.h
bitpack.h
ctype_workaround.h
doublelinkedlist.h
@@ -146,6 +150,7 @@ set(llcommon_HEADER_FILES
llqueuedthread.h
llrand.h
llrun.h
+ llscopedvolatileaprpool.h
llsd.h
llsdserialize.h
llsdserialize_xml.h
@@ -192,31 +197,22 @@ 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})
target_link_libraries(
llcommon
${APRUTIL_LIBRARIES}
${APR_LIBRARIES}
${EXPAT_LIBRARIES}
${ZLIB_LIBRARIES}
+ ${WINDOWS_LIBRARIES}
)
-if(HAVE_64_BIT)
- add_library (llcommonPIC ${llcommon_SOURCE_FILES})
- add_dependencies(llcommonPIC prepare)
-
- if(WINDOWS)
- add_definitions(/FIXED:NO)
- else(WINDOWS) # not windows therefore gcc LINUX and DARWIN
- add_definitions(-fPIC)
- endif(WINDOWS)
-
- target_link_libraries(
- llcommonPIC
- ${APRUTIL_LIBRARIES}
- ${APR_LIBRARIES}
- ${EXPAT_LIBRARIES}
- ${ZLIB_LIBRARIES}
- )
-endif(HAVE_64_BIT)
-
+if (DARWIN)
+ # don't embed a full path in the library's install name
+ set_target_properties(
+ llcommon
+ PROPERTIES
+ BUILD_WITH_INSTALL_RPATH 1
+ INSTALL_NAME_DIR "@executable_path/../Resources"
+ )
+endif (DARWIN)
diff --git a/linden/indra/llcommon/aiaprpool.cpp b/linden/indra/llcommon/aiaprpool.cpp
new file mode 100644
index 000000000..d3748e983
--- /dev/null
+++ b/linden/indra/llcommon/aiaprpool.cpp
@@ -0,0 +1,198 @@
+/**
+ * @file aiaprpool.cpp
+ *
+ * Copyright (c) 2010, Aleric Inglewood.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution.
+ *
+ * CHANGELOG
+ * and additional copyright holders.
+ *
+ * 04/04/2010
+ * - Initial version, written by Aleric Inglewood @ SL
+ *
+ * 10/11/2010
+ * - Changed filename, class names and license to a more
+ * company-neutral format.
+ * - Added APR_HAS_THREADS #if's to allow creation and destruction
+ * of subpools by threads other than the parent pool owner.
+ */
+
+#include "linden_common.h"
+
+#include "llerror.h"
+#include "aiaprpool.h"
+#include "llthread.h"
+
+// Create a subpool from parent.
+void AIAPRPool::create(AIAPRPool& parent)
+{
+ llassert(!mPool); // Must be non-initialized.
+ mParent = &parent;
+ if (!mParent) // Using the default parameter?
+ {
+ // By default use the root pool of the current thread.
+ mParent = &AIThreadLocalData::tldata().mRootPool;
+ }
+ llassert(mParent->mPool); // Parent must be initialized.
+#if APR_HAS_THREADS
+ // As per the documentation of APR (ie http://apr.apache.org/docs/apr/1.4/apr__pools_8h.html):
+ //
+ // Note that most operations on pools are not thread-safe: a single pool should only be
+ // accessed by a single thread at any given time. The one exception to this rule is creating
+ // a subpool of a given pool: one or more threads can safely create subpools at the same
+ // time that another thread accesses the parent pool.
+ //
+ // In other words, it's safe for any thread to create a (sub)pool, independent of who
+ // owns the parent pool.
+ mOwner = apr_os_thread_current();
+#else
+ mOwner = mParent->mOwner;
+ llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
+#endif
+ apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, mParent->mPool);
+ llassert_always(apr_pool_create_status == APR_SUCCESS);
+ llassert(mPool); // Initialized.
+ apr_pool_cleanup_register(mPool, this, &s_plain_cleanup, &apr_pool_cleanup_null);
+}
+
+// Destroy the (sub)pool, if any.
+void AIAPRPool::destroy(void)
+{
+ // Only do anything if we are not already (being) destroyed.
+ if (mPool)
+ {
+#if !APR_HAS_THREADS
+ // If we are a root pool, then every thread may destruct us: in that case
+ // we have to assume that no other thread will use this pool concurrently,
+ // of course. Otherwise, if we are a subpool, only the thread that owns
+ // the parent may destruct us, since that is the pool that is still alive,
+ // possibly being used by others and being altered here.
+ llassert(!mParent || apr_os_thread_equal(mParent->mOwner, apr_os_thread_current()));
+#endif
+ apr_pool_t* pool = mPool;
+ mPool = NULL; // Mark that we are BEING destructed.
+ apr_pool_cleanup_kill(pool, this, &s_plain_cleanup);
+ apr_pool_destroy(pool);
+ }
+}
+
+bool AIAPRPool::parent_is_being_destructed(void)
+{
+ return mParent && (!mParent->mPool || mParent->parent_is_being_destructed());
+}
+
+AIAPRInitialization::AIAPRInitialization(void)
+{
+ static bool apr_initialized = false;
+
+ if (!apr_initialized)
+ {
+ apr_initialize();
+ }
+
+ apr_initialized = true;
+}
+
+bool AIAPRRootPool::sCountInitialized = false;
+apr_uint32_t volatile AIAPRRootPool::sCount;
+
+extern apr_thread_mutex_t* gLogMutexp;
+extern apr_thread_mutex_t* gCallStacksLogMutexp;
+
+AIAPRRootPool::AIAPRRootPool(void) : AIAPRInitialization(), AIAPRPool(0)
+{
+ // sCountInitialized don't need locking because when we get here there is still only a single thread.
+ if (!sCountInitialized)
+ {
+ // Initialize the logging mutex
+ apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, mPool);
+ apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, mPool);
+
+ apr_status_t status = apr_atomic_init(mPool);
+ llassert_always(status == APR_SUCCESS);
+ apr_atomic_set32(&sCount, 1); // Set to 1 to account for the global root pool.
+ sCountInitialized = true;
+
+ // Initialize thread-local APR pool support.
+ // Because this recursively calls AIAPRRootPool::AIAPRRootPool(void)
+ // it must be done last, so that sCount is already initialized.
+ AIThreadLocalData::init();
+ }
+ apr_atomic_inc32(&sCount);
+}
+
+AIAPRRootPool::~AIAPRRootPool()
+{
+ if (!apr_atomic_dec32(&sCount))
+ {
+ // The last pool was destructed. Cleanup remainder of APR.
+ LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL;
+
+ if (gLogMutexp)
+ {
+ // Clean up the logging mutex
+
+ // All other threads NEED to be done before we clean up APR, so this is okay.
+ apr_thread_mutex_destroy(gLogMutexp);
+ gLogMutexp = NULL;
+ }
+ if (gCallStacksLogMutexp)
+ {
+ // Clean up the logging mutex
+
+ // All other threads NEED to be done before we clean up APR, so this is okay.
+ apr_thread_mutex_destroy(gCallStacksLogMutexp);
+ gCallStacksLogMutexp = NULL;
+ }
+
+ // Must destroy ALL, and therefore this last AIAPRRootPool, before terminating APR.
+ static_cast(this)->destroy();
+
+ apr_terminate();
+ }
+}
+
+//static
+AIAPRRootPool& AIAPRRootPool::get(void)
+{
+ static AIAPRRootPool global_APRpool(0); // This is what used to be gAPRPoolp.
+ return global_APRpool;
+}
+
+void AIVolatileAPRPool::clearVolatileAPRPool()
+{
+ llassert_always(mNumActiveRef > 0);
+ if (--mNumActiveRef == 0)
+ {
+ if (isOld())
+ {
+ destroy();
+ mNumTotalRef = 0 ;
+ }
+ else
+ {
+ // This does not actually free the memory,
+ // it just allows the pool to re-use this memory for the next allocation.
+ clear();
+ }
+ }
+
+ // Paranoia check if the pool is jammed.
+ llassert(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ;
+}
diff --git a/linden/indra/llcommon/aiaprpool.h b/linden/indra/llcommon/aiaprpool.h
new file mode 100644
index 000000000..ac523a9b9
--- /dev/null
+++ b/linden/indra/llcommon/aiaprpool.h
@@ -0,0 +1,240 @@
+/**
+ * @file aiaprpool.h
+ * @brief Implementation of AIAPRPool.
+ *
+ * Copyright (c) 2010, Aleric Inglewood.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution.
+ *
+ * CHANGELOG
+ * and additional copyright holders.
+ *
+ * 04/04/2010
+ * - Initial version, written by Aleric Inglewood @ SL
+ *
+ * 10/11/2010
+ * - Changed filename, class names and license to a more
+ * company-neutral format.
+ * - Added APR_HAS_THREADS #if's to allow creation and destruction
+ * of subpools by threads other than the parent pool owner.
+ */
+
+#ifndef AIAPRPOOL_H
+#define AIAPRPOOL_H
+
+#ifdef LL_WINDOWS
+//#include
+# define WIN32_LEAN_AND_MEAN
+# include // Needed before including apr_portable.h
+#endif
+
+#include "apr_portable.h"
+#include "apr_pools.h"
+#include "llerror.h"
+
+extern void ll_init_apr();
+
+/**
+ * @brief A wrapper around the APR memory pool API.
+ *
+ * Usage of this class should be restricted to passing it to libapr-1 function calls that need it.
+ *
+ */
+class LL_COMMON_API AIAPRPool
+{
+protected:
+ apr_pool_t* mPool; //!< Pointer to the underlaying pool. NULL if not initialized.
+ AIAPRPool* mParent; //!< Pointer to the parent pool, if any. Only valid when mPool is non-zero.
+ apr_os_thread_t mOwner; //!< The thread that owns this memory pool. Only valid when mPool is non-zero.
+
+public:
+ //! Construct an uninitialized (destructed) pool.
+ AIAPRPool(void) : mPool(NULL) { }
+
+ //! Construct a subpool from an existing pool.
+ // This is not a copy-constructor, this class doesn't have one!
+ AIAPRPool(AIAPRPool& parent) : mPool(NULL) { create(parent); }
+
+ //! Destruct the memory pool (free all of it's subpools and allocated memory).
+ ~AIAPRPool() { destroy(); }
+
+protected:
+ // Create a pool that is allocated from the Operating System. Only used by AIAPRRootPool.
+ AIAPRPool(int) : mPool(NULL), mParent(NULL), mOwner(apr_os_thread_current())
+ {
+ apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, NULL);
+ llassert_always(apr_pool_create_status == APR_SUCCESS);
+ llassert(mPool);
+ apr_pool_cleanup_register(mPool, this, &s_plain_cleanup, &apr_pool_cleanup_null);
+ }
+
+public:
+ //! Create a subpool from parent. May only be called for an uninitialized/destroyed pool.
+ // The default parameter causes the root pool of the current thread to be used.
+ void create(AIAPRPool& parent = *static_cast(NULL));
+
+ //! Destroy the (sub)pool, if any.
+ void destroy(void);
+
+ // Use some safebool idiom (http://www.artima.com/cppsource/safebool.html) rather than operator bool.
+ typedef apr_pool_t* const AIAPRPool::* const bool_type;
+ //! Return true if the pool is initialized.
+ operator bool_type() const { return mPool ? &AIAPRPool::mPool : 0; }
+
+ // Painful, but we have to either provide access to this, or wrap
+ // every APR function call that needs a apr_pool_t* to be passed.
+ // NEVER destroy a pool that is returned by this function!
+ apr_pool_t* operator()(void) const
+ {
+ llassert(mPool);
+ llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
+ return mPool;
+ }
+
+ // Free all memory without destructing the pool.
+ void clear(void)
+ {
+ llassert(mPool);
+ llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
+ apr_pool_clear(mPool);
+ }
+
+// These methods would make this class 'complete' (as wrapper around the libapr
+// pool functions), but we don't use memory pools in the viewer (only when
+// we are forced to pass one to a libapr call), so don't define them in order
+// not to encourage people to use them.
+#if 0
+ void* palloc(size_t size)
+ {
+ llassert(mPool);
+ llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
+ return apr_palloc(mPool, size);
+ }
+ void* pcalloc(size_t size)
+ {
+ llassert(mPool);
+ llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
+ return apr_pcalloc(mPool, size);
+ }
+#endif
+
+private:
+ bool parent_is_being_destructed(void);
+ static apr_status_t s_plain_cleanup(void* userdata) { return static_cast(userdata)->plain_cleanup(); }
+
+ apr_status_t plain_cleanup(void)
+ {
+ if (mPool && // We are not being destructed,
+ parent_is_being_destructed()) // but our parent is.
+ // This means the pool is being destructed recursively by libapr
+ // because one of it's parents is being destructed.
+ {
+ mPool = NULL; // Stop destroy() from destructing the pool again.
+ }
+ return APR_SUCCESS;
+ }
+};
+
+class AIAPRInitialization
+{
+public:
+ AIAPRInitialization(void);
+};
+
+/**
+ * @brief Root memory pool (allocates memory from the operating system).
+ *
+ * This class should only be used by AIThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase
+ * (and LLMutexRootPool when APR_HAS_THREADS isn't defined).
+ */
+class LL_COMMON_API AIAPRRootPool : public AIAPRInitialization, public AIAPRPool
+{
+private:
+ friend class AIThreadLocalData;
+ friend class AIThreadSafeSimpleDCRootPool_pbase;
+#if !APR_HAS_THREADS
+ friend class LLMutexRootPool;
+#endif
+ //! Construct a root memory pool.
+ // Should only be used by AIThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase.
+ AIAPRRootPool(void);
+ ~AIAPRRootPool();
+
+private:
+ // Keep track of how many root pools exist and when the last one is destructed.
+ static bool sCountInitialized;
+ static apr_uint32_t volatile sCount;
+
+public:
+ // Return a global root pool that is independent of AIThreadLocalData.
+ // Normally you should not use this. Only use for early initialization
+ // (before main) and deinitialization (after main).
+ static AIAPRRootPool& get(void);
+
+#if APR_POOL_DEBUG
+ void grab_ownership(void)
+ {
+ // You need a patched libapr to use this.
+ // See http://web.archiveorange.com/archive/v/5XO9y2zoxUOMt6Gmi1OI
+ apr_pool_owner_set(mPool);
+ }
+#endif
+
+private:
+ // Used for constructing the Special Global Root Pool (returned by AIAPRRootPool::get).
+ // It is the same as the default constructor but omits to increment sCount. As a result,
+ // we must be sure that at least one other AIAPRRootPool is created before termination
+ // of the application (which is the case: we create one AIAPRRootPool per thread).
+ AIAPRRootPool(int) : AIAPRInitialization(), AIAPRPool(0) { }
+};
+
+//! Volatile memory pool
+//
+// 'Volatile' APR memory pool which normally only clears memory,
+// and does not destroy the pool (the same pool is reused) for
+// greater efficiency. However, as a safe guard the apr pool
+// is destructed every FULL_VOLATILE_APR_POOL uses to allow
+// the system memory to be allocated more efficiently and not
+// get scattered through RAM.
+//
+class LL_COMMON_API AIVolatileAPRPool : protected AIAPRPool
+{
+public:
+ AIVolatileAPRPool(void) : mNumActiveRef(0), mNumTotalRef(0) { }
+
+ apr_pool_t* getVolatileAPRPool(void)
+ {
+ if (!mPool) create();
+ ++mNumActiveRef;
+ ++mNumTotalRef;
+ return AIAPRPool::operator()();
+ }
+ void clearVolatileAPRPool(void);
+
+ bool isOld(void) const { return mNumTotalRef > FULL_VOLATILE_APR_POOL; }
+ bool isUnused() const { return mNumActiveRef == 0; }
+
+private:
+ S32 mNumActiveRef; // Number of active uses of the pool.
+ S32 mNumTotalRef; // Number of total uses of the pool since last creation.
+
+ // Maximum number of references to AIVolatileAPRPool until the pool is recreated.
+ static S32 const FULL_VOLATILE_APR_POOL = 1024;
+};
+
+#endif // AIAPRPOOL_H
diff --git a/linden/indra/llcommon/aithreadsafe.h b/linden/indra/llcommon/aithreadsafe.h
new file mode 100644
index 000000000..70cd2a3db
--- /dev/null
+++ b/linden/indra/llcommon/aithreadsafe.h
@@ -0,0 +1,482 @@
+/**
+ * @file aithreadsafe.h
+ * @brief Implementation of AIThreadSafe, AIReadAccessConst, AIReadAccess and AIWriteAccess.
+ *
+ * Copyright (c) 2010, Aleric Inglewood.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution.
+ *
+ * CHANGELOG
+ * and additional copyright holders.
+ *
+ * 31/03/2010
+ * Initial version, written by Aleric Inglewood @ SL
+ */
+
+#ifndef AITHREADSAFE_H
+#define AITHREADSAFE_H
+
+#include
+
+#include "llthread.h"
+#include "llerror.h"
+
+template struct AIReadAccessConst;
+template struct AIReadAccess;
+template struct AIWriteAccess;
+template struct AIAccess;
+
+template
+class AIThreadSafeBits
+{
+private:
+ // AIThreadSafe is a wrapper around an instance of T.
+ // Because T might not have a default constructor, it is constructed
+ // 'in place', with placement new, in the memory reserved here.
+ //
+ // Make sure that the memory that T will be placed in is properly
+ // aligned by using an array of long's.
+ long mMemory[(sizeof(T) + sizeof(long) - 1) / sizeof(long)];
+
+public:
+ // The wrapped objects are constructed in-place with placement new *outside*
+ // of this object (by AITHREADSAFE macro(s) or derived classes).
+ // However, we are responsible for the destruction of the wrapped object.
+ ~AIThreadSafeBits() { ptr()->~T(); }
+
+ // Only for use by AITHREADSAFE, see below.
+ void* memory() const { return const_cast(&mMemory[0]); }
+
+protected:
+ // Accessors.
+ T const* ptr() const { return reinterpret_cast(mMemory); }
+ T* ptr() { return reinterpret_cast(mMemory); }
+};
+
+/**
+ * @brief A wrapper class for objects that need to be accessed by more than one thread, allowing concurrent readers.
+ *
+ * Use AITHREADSAFE to define instances of any type, and use AIReadAccessConst,
+ * AIReadAccess and AIWriteAccess to get access to the instance.
+ *
+ * For example,
+ *
+ *
+ * class Foo { public: Foo(int, int); };
+ *
+ * AITHREADSAFE(Foo, foo, (2, 3));
+ *
+ * AIReadAccess foo_r(foo);
+ * // Use foo_r-> for read access.
+ *
+ * AIWriteAccess foo_w(foo);
+ * // Use foo_w-> for write access.
+ *
+ *
+ * If foo is constant, you have to use AIReadAccessConst.
+ *
+ * It is possible to pass access objects to a function that
+ * downgrades the access, for example:
+ *
+ *
+ * void readfunc(AIReadAccess const& access);
+ *
+ * AIWriteAccess foo_w(foo);
+ * readfunc(foo_w); // readfunc will perform read access to foo_w.
+ *
+ *
+ * If AIReadAccess is non-const, you can upgrade the access by creating
+ * an AIWriteAccess object from it. For example:
+ *
+ *
+ * AIWriteAccess foo_w(foo_r);
+ *
+ *
+ * This API is Robust(tm). If you try anything that could result in problems,
+ * it simply won't compile. The only mistake you can still easily make is
+ * to obtain write access to an object when it is not needed, or to unlock
+ * an object in between accesses while the state of the object should be
+ * preserved. For example:
+ *
+ *
+ * // This resets foo to point to the first file and then returns that.
+ * std::string filename = AIWriteAccess(foo)->get_first_filename();
+ *
+ * // WRONG! The state between calling get_first_filename and get_next_filename should be preserved!
+ *
+ * AIWriteAccess foo_w(foo); // Wrong. The code below only needs read-access.
+ * while (!filename.empty())
+ * {
+ * something(filename);
+ * filename = foo_w->next_filename();
+ * }
+ *
+ *
+ * Correct would be
+ *
+ *
+ * AIReadAccess foo_r(foo);
+ * std::string filename = AIWriteAccess(foo_r)->get_first_filename();
+ * while (!filename.empty())
+ * {
+ * something(filename);
+ * filename = foo_r->next_filename();
+ * }
+ *
+ *
+ */
+template
+class AIThreadSafe : public AIThreadSafeBits
+{
+protected:
+ // Only these may access the object (through ptr()).
+ friend struct AIReadAccessConst;
+ friend struct AIReadAccess;
+ friend struct AIWriteAccess;
+
+ // Locking control.
+ AIRWLock mRWLock;
+
+ // For use by AIThreadSafeDC
+ AIThreadSafe(void) { }
+ AIThreadSafe(AIAPRPool& parent) : mRWLock(parent) { }
+
+public:
+ // Only for use by AITHREADSAFE, see below.
+ AIThreadSafe(T* object) { llassert(object == AIThreadSafeBits::ptr()); }
+};
+
+/**
+ * @brief Instantiate an static, global or local object of a given type wrapped in AIThreadSafe, using an arbitrary constructor.
+ *
+ * For example, instead of doing
+ *
+ *
+ * Foo foo(x, y);
+ * static Bar bar;
+ *
+ *
+ * One can instantiate a thread-safe instance with
+ *
+ *
+ * AITHREADSAFE(Foo, foo, (x, y));
+ * static AITHREADSAFE(Bar, bar, );
+ *
+ *
+ * Note: This macro does not allow to allocate such object on the heap.
+ * If that is needed, have a look at AIThreadSafeDC.
+ */
+#define AITHREADSAFE(type, var, paramlist) AIThreadSafe var(new (var.memory()) type paramlist)
+
+/**
+ * @brief A wrapper class for objects that need to be accessed by more than one thread.
+ *
+ * This class is the same as an AIThreadSafe wrapper, except that it can only
+ * be used for default constructed objects.
+ *
+ * For example, instead of
+ *
+ *
+ * Foo foo;
+ *
+ *
+ * One would use
+ *
+ *
+ * AIThreadSafeDC foo;
+ *
+ *
+ * The advantage over AITHREADSAFE is that this object can be allocated with
+ * new on the heap. For example:
+ *
+ *
+ * AIThreadSafeDC* ptr = new AIThreadSafeDC;
+ *
+ *
+ * which is not possible with AITHREADSAFE.
+ */
+template
+class AIThreadSafeDC : public AIThreadSafe
+{
+public:
+ // Construct a wrapper around a default constructed object.
+ AIThreadSafeDC(void) { new (AIThreadSafe::ptr()) T; }
+};
+
+/**
+ * @brief Read lock object and provide read access.
+ */
+template
+struct AIReadAccessConst
+{
+ //! Internal enum for the lock-type of the AI*Access object.
+ enum state_type
+ {
+ readlocked, //!< A AIReadAccessConst or AIReadAccess.
+ read2writelocked, //!< A AIWriteAccess constructed from a AIReadAccess.
+ writelocked, //!< A AIWriteAccess constructed from a AIThreadSafe.
+ write2writelocked //!< A AIWriteAccess constructed from (the AIReadAccess base class of) a AIWriteAccess.
+ };
+
+ //! Construct a AIReadAccessConst from a constant AIThreadSafe.
+ AIReadAccessConst(AIThreadSafe const& wrapper)
+ : mWrapper(const_cast&>(wrapper)),
+ mState(readlocked)
+ {
+ mWrapper.mRWLock.rdlock();
+ }
+
+ //! Destruct the AI*Access object.
+ // These should never be dynamically allocated, so there is no need to make this virtual.
+ ~AIReadAccessConst()
+ {
+ if (mState == readlocked)
+ mWrapper.mRWLock.rdunlock();
+ else if (mState == writelocked)
+ mWrapper.mRWLock.wrunlock();
+ else if (mState == read2writelocked)
+ mWrapper.mRWLock.wr2rdlock();
+ }
+
+ //! Access the underlaying object for read access.
+ T const* operator->() const { return mWrapper.ptr(); }
+
+ //! Access the underlaying object for read access.
+ T const& operator*() const { return *mWrapper.ptr(); }
+
+protected:
+ //! Constructor used by AIReadAccess.
+ AIReadAccessConst(AIThreadSafe& wrapper, state_type state)
+ : mWrapper(wrapper), mState(state) { }
+
+ AIThreadSafe& mWrapper; //!< Reference to the object that we provide access to.
+ state_type const mState; //!< The lock state that mWrapper is in.
+
+private:
+ // Disallow copy constructing directly.
+ AIReadAccessConst(AIReadAccessConst const&);
+};
+
+/**
+ * @brief Read lock object and provide read access, with possible promotion to write access.
+ */
+template
+struct AIReadAccess : public AIReadAccessConst
+{
+ typedef typename AIReadAccessConst::state_type state_type;
+ using AIReadAccessConst::readlocked;
+
+ //! Construct a AIReadAccess from a non-constant AIThreadSafe.
+ AIReadAccess(AIThreadSafe& wrapper) : AIReadAccessConst(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(); }
+
+protected:
+ //! Constructor used by AIWriteAccess.
+ AIReadAccess(AIThreadSafe& wrapper, state_type state) : AIReadAccessConst(wrapper, state) { }
+
+ friend class AIWriteAccess;
+};
+
+/**
+ * @brief Write lock object and provide read/write access.
+ */
+template
+struct AIWriteAccess : public AIReadAccess
+{
+ using AIReadAccessConst::readlocked;
+ using AIReadAccessConst::read2writelocked;
+ using AIReadAccessConst::writelocked;
+ using AIReadAccessConst::write2writelocked;
+
+ //! Construct a AIWriteAccess from a non-constant AIThreadSafe.
+ AIWriteAccess(AIThreadSafe& wrapper) : AIReadAccess(wrapper, writelocked) { this->mWrapper.mRWLock.wrlock();}
+
+ //! Promote read access to write access.
+ explicit AIWriteAccess(AIReadAccess& access)
+ : AIReadAccess(access.mWrapper, (access.mState == readlocked) ? read2writelocked : write2writelocked)
+ {
+ if (this->mState == read2writelocked)
+ {
+ this->mWrapper.mRWLock.rd2wrlock();
+ }
+ }
+
+ //! Access the underlaying object for (read and) write access.
+ T* operator->() const { return this->mWrapper.ptr(); }
+
+ //! Access the underlaying object for (read and) write access.
+ T& operator*() const { return *this->mWrapper.ptr(); }
+};
+
+/**
+ * @brief A wrapper class for objects that need to be accessed by more than one thread.
+ *
+ * Use AITHREADSAFESIMPLE to define instances of any type, and use AIAccess
+ * to get access to the instance.
+ *
+ * For example,
+ *
+ *
+ * class Foo { public: Foo(int, int); };
+ *
+ * AITHREADSAFESIMPLE(Foo, foo, (2, 3));
+ *
+ * AIAccess foo_w(foo);
+ * // Use foo_w-> for read and write access.
+ *
+ * See also AIThreadSafe
+ */
+template
+class AIThreadSafeSimple : public AIThreadSafeBits
+{
+protected:
+ // Only this one may access the object (through ptr()).
+ friend struct AIAccess;
+
+ // Locking control.
+ LLMutex mMutex;
+
+ // For use by AIThreadSafeSimpleDC
+ AIThreadSafeSimple(void) { }
+ AIThreadSafeSimple(AIAPRPool& parent) : mMutex(parent) { }
+
+public:
+ // Only for use by AITHREADSAFESIMPLE, see below.
+ AIThreadSafeSimple(T* object) { llassert(object == AIThreadSafeBits::ptr()); }
+};
+
+/**
+ * @brief Instantiate an static, global or local object of a given type wrapped in AIThreadSafeSimple, using an arbitrary constructor.
+ *
+ * For example, instead of doing
+ *
+ *
+ * Foo foo(x, y);
+ * static Bar bar;
+ *
+ *
+ * One can instantiate a thread-safe instance with
+ *
+ *
+ * AITHREADSAFESIMPLE(Foo, foo, (x, y));
+ * static AITHREADSAFESIMPLE(Bar, bar, );
+ *
+ *
+ * Note: This macro does not allow to allocate such object on the heap.
+ * If that is needed, have a look at AIThreadSafeSimpleDC.
+ */
+#define AITHREADSAFESIMPLE(type, var, paramlist) AIThreadSafeSimple var(new (var.memory()) type paramlist)
+
+/**
+ * @brief A wrapper class for objects that need to be accessed by more than one thread.
+ *
+ * This class is the same as an AIThreadSafeSimple wrapper, except that it can only
+ * be used for default constructed objects.
+ *
+ * For example, instead of
+ *
+ *
+ * Foo foo;
+ *
+ *
+ * One would use
+ *
+ *
+ * AIThreadSafeSimpleDC foo;
+ *
+ *
+ * The advantage over AITHREADSAFESIMPLE is that this object can be allocated with
+ * new on the heap. For example:
+ *
+ *
+ * AIThreadSafeSimpleDC* ptr = new AIThreadSafeSimpleDC;
+ *
+ *
+ * which is not possible with AITHREADSAFESIMPLE.
+ */
+template
+class AIThreadSafeSimpleDC : public AIThreadSafeSimple
+{
+public:
+ // Construct a wrapper around a default constructed object.
+ AIThreadSafeSimpleDC(void) { new (AIThreadSafeSimple::ptr()) T; }
+
+protected:
+ // For use by AIThreadSafeSimpleDCRootPool
+ AIThreadSafeSimpleDC(AIAPRPool& parent) : AIThreadSafeSimple(parent) { new (AIThreadSafeSimple::ptr()) T; }
+};
+
+// Helper class for AIThreadSafeSimpleDCRootPool to assure initialization of
+// the root pool before constructing AIThreadSafeSimpleDC.
+class AIThreadSafeSimpleDCRootPool_pbase
+{
+protected:
+ AIAPRRootPool mRootPool;
+
+private:
+ template friend class AIThreadSafeSimpleDCRootPool;
+ AIThreadSafeSimpleDCRootPool_pbase(void) { }
+};
+
+/**
+ * @brief A wrapper class for objects that need to be accessed by more than one thread.
+ *
+ * The same as AIThreadSafeSimpleDC except that this class creates its own AIAPRRootPool
+ * for the internally used mutexes and condition, instead of using the current threads
+ * root pool. The advantage of this is that it can be used for objects that need to
+ * be accessed from the destructors of global objects (after main). The disadvantage
+ * is that it's less efficient to use your own root pool, therefore it's use should be
+ * restricted to those cases where it is absolutely necessary.
+ */
+template
+class AIThreadSafeSimpleDCRootPool : private AIThreadSafeSimpleDCRootPool_pbase, public AIThreadSafeSimpleDC
+{
+public:
+ // Construct a wrapper around a default constructed object, using memory allocated
+ // from the operating system for the internal APR objects (mutexes and conditional),
+ // as opposed to allocated from the current threads root pool.
+ AIThreadSafeSimpleDCRootPool(void) :
+ AIThreadSafeSimpleDCRootPool_pbase(),
+ AIThreadSafeSimpleDC(mRootPool) { }
+};
+
+/**
+ * @brief Write lock object and provide read/write access.
+ */
+template
+struct AIAccess
+{
+ //! Construct a AIAccess from a non-constant AIThreadSafeSimple.
+ AIAccess(AIThreadSafeSimple& wrapper) : mWrapper(wrapper) { this->mWrapper.mMutex.lock(); }
+
+ //! Access the underlaying object for (read and) write access.
+ T* operator->() const { return this->mWrapper.ptr(); }
+
+ //! Access the underlaying object for (read and) write access.
+ T& operator*() const { return *this->mWrapper.ptr(); }
+
+ ~AIAccess() { this->mWrapper.mMutex.unlock(); }
+
+protected:
+ AIThreadSafeSimple& mWrapper; //!< Reference to the object that we provide access to.
+
+private:
+ // Disallow copy constructing directly.
+ AIAccess(AIAccess const&);
+};
+
+#endif
diff --git a/linden/indra/llcommon/imageids.h b/linden/indra/llcommon/imageids.h
index 7bae496e7..dc726dcf5 100644
--- a/linden/indra/llcommon/imageids.h
+++ b/linden/indra/llcommon/imageids.h
@@ -41,35 +41,35 @@
class LLUUID;
-extern const LLUUID IMG_SMOKE;
+LL_COMMON_API extern const LLUUID IMG_SMOKE;
-extern const LLUUID IMG_DEFAULT;
+LL_COMMON_API extern const LLUUID IMG_DEFAULT;
-extern const LLUUID IMG_SUN;
-extern const LLUUID IMG_MOON;
-extern const LLUUID IMG_CLOUD_POOF;
-extern const LLUUID IMG_SHOT;
-extern const LLUUID IMG_SPARK;
-extern const LLUUID IMG_FIRE;
-extern const LLUUID IMG_FACE_SELECT;
-extern const LLUUID IMG_DEFAULT_AVATAR;
-extern const LLUUID IMG_INVISIBLE;
+LL_COMMON_API extern const LLUUID IMG_SUN;
+LL_COMMON_API extern const LLUUID IMG_MOON;
+LL_COMMON_API extern const LLUUID IMG_CLOUD_POOF;
+LL_COMMON_API extern const LLUUID IMG_SHOT;
+LL_COMMON_API extern const LLUUID IMG_SPARK;
+LL_COMMON_API extern const LLUUID IMG_FIRE;
+LL_COMMON_API extern const LLUUID IMG_FACE_SELECT;
+LL_COMMON_API extern const LLUUID IMG_DEFAULT_AVATAR;
+LL_COMMON_API extern const LLUUID IMG_INVISIBLE;
-extern const LLUUID IMG_EXPLOSION;
-extern const LLUUID IMG_EXPLOSION_2;
-extern const LLUUID IMG_EXPLOSION_3;
-extern const LLUUID IMG_EXPLOSION_4;
-extern const LLUUID IMG_SMOKE_POOF;
+LL_COMMON_API extern const LLUUID IMG_EXPLOSION;
+LL_COMMON_API extern const LLUUID IMG_EXPLOSION_2;
+LL_COMMON_API extern const LLUUID IMG_EXPLOSION_3;
+LL_COMMON_API extern const LLUUID IMG_EXPLOSION_4;
+LL_COMMON_API extern const LLUUID IMG_SMOKE_POOF;
-extern const LLUUID IMG_BIG_EXPLOSION_1;
-extern const LLUUID IMG_BIG_EXPLOSION_2;
+LL_COMMON_API extern const LLUUID IMG_BIG_EXPLOSION_1;
+LL_COMMON_API extern const LLUUID IMG_BIG_EXPLOSION_2;
-extern const LLUUID IMG_BLOOM1;
-extern const LLUUID TERRAIN_DIRT_DETAIL;
-extern const LLUUID TERRAIN_GRASS_DETAIL;
-extern const LLUUID TERRAIN_MOUNTAIN_DETAIL;
-extern const LLUUID TERRAIN_ROCK_DETAIL;
+LL_COMMON_API extern const LLUUID IMG_BLOOM1;
+LL_COMMON_API extern const LLUUID TERRAIN_DIRT_DETAIL;
+LL_COMMON_API extern const LLUUID TERRAIN_GRASS_DETAIL;
+LL_COMMON_API extern const LLUUID TERRAIN_MOUNTAIN_DETAIL;
+LL_COMMON_API extern const LLUUID TERRAIN_ROCK_DETAIL;
-extern const LLUUID DEFAULT_WATER_NORMAL;
+LL_COMMON_API extern const LLUUID DEFAULT_WATER_NORMAL;
#endif
diff --git a/linden/indra/llcommon/indra_constants.h b/linden/indra/llcommon/indra_constants.h
index 34d1538d3..279d280df 100644
--- a/linden/indra/llcommon/indra_constants.h
+++ b/linden/indra/llcommon/indra_constants.h
@@ -263,15 +263,15 @@ const U8 GOD_LIKE = 1;
const U8 GOD_NOT = 0;
// "agent id" for things that should be done to ALL agents
-extern const LLUUID LL_UUID_ALL_AGENTS;
+LL_COMMON_API extern const LLUUID LL_UUID_ALL_AGENTS;
// inventory library owner
-extern const LLUUID ALEXANDRIA_LINDEN_ID;
+LL_COMMON_API extern const LLUUID ALEXANDRIA_LINDEN_ID;
-extern const LLUUID GOVERNOR_LINDEN_ID;
-extern const LLUUID REALESTATE_LINDEN_ID;
+LL_COMMON_API extern const LLUUID GOVERNOR_LINDEN_ID;
+LL_COMMON_API extern const LLUUID REALESTATE_LINDEN_ID;
// Maintenance's group id.
-extern const LLUUID MAINTENANCE_GROUP_ID;
+LL_COMMON_API extern const LLUUID MAINTENANCE_GROUP_ID;
// Flags for kick message
const U32 KICK_FLAGS_DEFAULT = 0x0;
diff --git a/linden/indra/llcommon/linden_common.h b/linden/indra/llcommon/linden_common.h
index 25dd62947..bf844b99b 100644
--- a/linden/indra/llcommon/linden_common.h
+++ b/linden/indra/llcommon/linden_common.h
@@ -51,16 +51,16 @@
#include
#include
#include
-#include
-#include
+#include
-// Work Microsoft compiler warnings
+// Work around Microsoft compiler warnings in STL headers
#ifdef LL_WINDOWS
#pragma warning (disable : 4702) // unreachable code
#pragma warning (disable : 4244) // conversion from time_t to S32
#endif // LL_WINDOWS
-#include
+// *TODO: Eliminate these, most library .cpp files don't need them.
+// Add them to llviewerprecompiledheaders.h if necessary.
#include
#include