From 5246fc9cddc834365fea9e0fe8e0d328e98186f9 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 2 May 2011 03:44:00 +0200 Subject: [PATCH 01/16] Uninstall files of old packages when new packages are installed over an old one. Also automatically add missing -dev symlinks to packages and check SONAME's. This patch was originally written by me for Imprudence. --- scripts/install.py | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/scripts/install.py b/scripts/install.py index 85818bc9a..605dcc103 100755 --- a/scripts/install.py +++ b/scripts/install.py @@ -535,24 +535,24 @@ windows/i686/vs/2003 -- specify a windows visual studio 2003 package""" platform, cache_dir)) to_install = [] + to_uninstall = [] #print "self._installed",self._installed for ifile in ifiles: if ifile.pkgname not in self._installed: to_install.append(ifile) elif ifile.url not in self._installed[ifile.pkgname].urls(): + to_uninstall.append(ifile.pkgname) to_install.append(ifile) elif ifile.md5sum != \ self._installed[ifile.pkgname].get_md5sum(ifile.url): - # *TODO: We may want to uninstall the old version too - # when we detect it is installed, but the md5 sum is - # different. + to_uninstall.append(ifile.pkgname) to_install.append(ifile) else: #print "Installation up to date:", # ifile.pkgname,ifile.platform_path pass #print "to_install",to_install - return to_install + return [to_install, to_uninstall] def _install(self, to_install, install_dir): for ifile in to_install: @@ -565,17 +565,43 @@ windows/i686/vs/2003 -- specify a windows visual studio 2003 package""" tar.extractall(path=install_dir) except AttributeError: _extractall(tar, path=install_dir) + symlinks = [] + if _get_platform() == 'linux' or _get_platform() == 'linux64': + first = 1 + for tfile in tar.getnames(): + if tfile.find('.so.') > 0: + LINK = re.sub(r'\.so\.[0-9.]*$', '.so', tfile) + link_name = install_dir + "/" + LINK + if not os.path.exists(link_name): + if first == 1: + first = 0 + print "Adding missing symlink(s) for package %s:" % ifile.filename + target = os.path.basename(tfile) + soname = os.popen("readelf -d \"%(install_dir)s/%(tfile)s\" %(stderr_redirect)s" + " | grep SONAME | sed -e 's/.*\[//;s/\].*//'" % + {"install_dir": install_dir, "tfile": tfile, "stderr_redirect": ("2>/dev/null" if self._dryrun else "")}).read() + soname = soname.strip() + if soname: # not empty + tmpfname = os.path.dirname(LINK) + "/" + soname + if os.path.exists(install_dir + "/" + tmpfname): + target = soname + else: + print "WARNING: SONAME %s doesn't exist!" % tmpfname + if not self._dryrun: + os.symlink(target, link_name) + symlinks += [LINK] + print " %s --> %s" % (LINK, target) if ifile.pkgname in self._installed: self._installed[ifile.pkgname].add_files( ifile.url, - tar.getnames()) + tar.getnames() + symlinks) self._installed[ifile.pkgname].set_md5sum( ifile.url, ifile.md5sum) else: # *HACK: this understands the installed package syntax. definition = { ifile.url : - {'files': tar.getnames(), + {'files': tar.getnames() + symlinks, 'md5sum' : ifile.md5sum } } self._installed[ifile.pkgname] = InstalledPackage(definition) self._installed_changed = True @@ -595,12 +621,17 @@ windows/i686/vs/2003 -- specify a windows visual studio 2003 package""" cache_dir = os.path.realpath(cache_dir) _mkdir(install_dir) _mkdir(cache_dir) - to_install = self._build_ifiles(platform, cache_dir) + to_install_uninstall = self._build_ifiles(platform, cache_dir) + to_install = to_install_uninstall[0] + to_uninstall = to_install_uninstall[1] # Filter for files which we actually requested to install. to_install = [ifl for ifl in to_install if ifl.pkgname in installables] + to_uninstall = [ifl for ifl in to_uninstall if ifl in installables] for ifile in to_install: ifile.fetch_local() + if to_uninstall: + self.uninstall(to_uninstall, install_dir) self._install(to_install, install_dir) def do_install(self, installables, platform, install_dir, cache_dir=None, From 1510d5ff5a55438eec39b59905bafc1bbaaf53f7 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 2 May 2011 04:35:56 +0200 Subject: [PATCH 02/16] Use linux64 key on x86_64 --- scripts/install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/install.py b/scripts/install.py index 605dcc103..e53f664b4 100755 --- a/scripts/install.py +++ b/scripts/install.py @@ -818,7 +818,7 @@ def _get_platform(): # TODO -- someday when install.py accepts a platform of the form # os/arch/compiler/compiler_version then we can replace the # 'linux64' platform with 'linux/x86_64/gcc/4.1' - this_platform = 'linux' + this_platform = 'linux64' return this_platform def _getuser(): From 9bcc08df1aa20aad340307c4ac6f0d6884a56f4f Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 2 May 2011 04:36:47 +0200 Subject: [PATCH 03/16] Don't barf when Google PerfTools are not found, but simply disable it. Plus bug fix (missing NOT): in the case that USE_GOOGLE_PERFTOOLS is not set we DON'T want to build with Google TCMalloc. --- indra/cmake/GooglePerfTools.cmake | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/indra/cmake/GooglePerfTools.cmake b/indra/cmake/GooglePerfTools.cmake index a5f957a20..0b483e5cf 100644 --- a/indra/cmake/GooglePerfTools.cmake +++ b/indra/cmake/GooglePerfTools.cmake @@ -25,9 +25,11 @@ else (STANDALONE) endif (LINUX) endif (STANDALONE) -#if (GOOGLE_PERFTOOLS_FOUND) -# set(USE_GOOGLE_PERFTOOLS ON CACHE BOOL "Build with Google PerfTools support.") -#endif (GOOGLE_PERFTOOLS_FOUND) +if (GOOGLE_PERFTOOLS_FOUND) + set(USE_GOOGLE_PERFTOOLS ON CACHE BOOL "Build with Google PerfTools support.") +else (GOOGLE_PERFTOOLS_FOUND) + set(USE_GOOGLE_PERFTOOLS OFF) +endif (GOOGLE_PERFTOOLS_FOUND) # XXX Disable temporarily, until we have compilation issues on 64-bit # Etch sorted. @@ -41,7 +43,7 @@ else (USE_GOOGLE_PERFTOOLS) set(TCMALLOC_FLAG -ULL_USE_TCMALLOC) endif (USE_GOOGLE_PERFTOOLS) -if (NOT(DISABLE_TCMALLOC OR USE_GOOGLE_PERFTOOLS)) +if (NOT(DISABLE_TCMALLOC OR NOT USE_GOOGLE_PERFTOOLS)) message(STATUS "Building with Google TCMalloc") set(TCMALLOC_FLAG -DLL_USE_TCMALLOC=1_) include_directories(${GOOGLE_PERFTOOLS_INCLUDE_DIR}) From b7aaef7e91529819f36600953765a9cc9e11111f Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 2 May 2011 15:15:23 +0200 Subject: [PATCH 04/16] Set appropriate compiler options for x86_64. Using -march=pentium4 break compilation on 64bit. A pentium isn't a 64bit cpu. The used options were copied from imprudence. --- indra/cmake/00-Common.cmake | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 1e423bd29..fdc18ff3c 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -201,10 +201,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}") @@ -212,6 +220,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) From 1b4ae2e3b5285af910c8daeaf5280d8a110df1cd Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 2 May 2011 15:26:49 +0200 Subject: [PATCH 05/16] Removed generated file mime_types.xml, and fixed indentation in the source files. indra/newview/skins/default/xui/en-us/mime_types.xml should be generated from mime_types_linux.xml, mime_types_mac.xml or mime_types_windows.xml by copying it when packaging. Hence, it should never be used. Note, this is an exact sync with imprudence. --- .../skins/default/xui/en-us/mime_types.xml | 445 ------------------ .../default/xui/en-us/mime_types_linux.xml | 34 +- .../default/xui/en-us/mime_types_mac.xml | 34 +- 3 files changed, 34 insertions(+), 479 deletions(-) delete mode 100644 indra/newview/skins/default/xui/en-us/mime_types.xml diff --git a/indra/newview/skins/default/xui/en-us/mime_types.xml b/indra/newview/skins/default/xui/en-us/mime_types.xml deleted file mode 100644 index 4a7a6e17a..000000000 --- a/indra/newview/skins/default/xui/en-us/mime_types.xml +++ /dev/null @@ -1,445 +0,0 @@ - - - - (Unknown) - - - none - - - media_plugin_webkit - - - - - icn_media_web.tga - - - text/html - - - This location has Web content - - - Show Web content - - - true - - - false - - - - - - video/* - - - icn_media_movie.tga - - - There is a movie to play here - - - Play movie - - - false - - - true - - - - - - icn_media_web.tga - - - image/* - - - There is an image at this location - - - View this location's image - - - false - - - false - - - - - - icn_media_web.tga - - - audio/* - - - There is audio at this location - - - Play this location's audio - - - false - - - true - - - - - - movie - - - media_plugin_quicktime - - - - - - none - - - media_plugin_quicktime - - - - - - none - - - - - - audio - - - - - - movie - - - - - - image - - - - - - movie - - - media_plugin_quicktime - - - - - - web - - - - - - audio - - - - - - image - - - - - - image - - - - - - image - - - - - - movie - - - media_plugin_quicktime - - - - - - web - - - - - - image - - - - - - audio - - - media_plugin_quicktime - - - - - - audio - - - media_plugin_quicktime - - - - - - audio - - - media_plugin_quicktime - - - - - - audio - - - media_plugin_quicktime - - - - - - image - - - media_plugin_webkit - - - - - - image - - - media_plugin_webkit - - - - - - image - - - media_plugin_webkit - - - - - - image - - - media_plugin_webkit - - - - - - image - - - media_plugin_webkit - - - - - - image - - - media_plugin_webkit - - - - - - web - - - media_plugin_webkit - - - - - - text - - - media_plugin_webkit - - - - - - text - - - media_plugin_webkit - - - - - - movie - - - media_plugin_quicktime - - - - - - movie - - - media_plugin_quicktime - - - - - - movie - - - media_plugin_quicktime - - - - - - movie - - - media_plugin_quicktime - - - - - - movie - - - media_plugin_quicktime - - - - - - movie - - - media_plugin_quicktime - - - diff --git a/indra/newview/skins/default/xui/en-us/mime_types_linux.xml b/indra/newview/skins/default/xui/en-us/mime_types_linux.xml index f04992ade..e95b371d0 100644 --- a/indra/newview/skins/default/xui/en-us/mime_types_linux.xml +++ b/indra/newview/skins/default/xui/en-us/mime_types_linux.xml @@ -175,8 +175,8 @@ movie - media_plugin_gstreamer - + media_plugin_gstreamer + movie @@ -384,8 +384,8 @@ web - media_plugin_webkit - + media_plugin_webkit + diff --git a/indra/newview/skins/default/xui/en-us/mime_types_mac.xml b/indra/newview/skins/default/xui/en-us/mime_types_mac.xml index 5b66271a5..7931e55c0 100644 --- a/indra/newview/skins/default/xui/en-us/mime_types_mac.xml +++ b/indra/newview/skins/default/xui/en-us/mime_types_mac.xml @@ -175,8 +175,8 @@ movie - media_plugin_quicktime - + media_plugin_quicktime + movie @@ -384,8 +384,8 @@ web - media_plugin_webkit - + media_plugin_webkit + From 094587aefd6afcb5346ec67e48676f17201ea7b1 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 2 May 2011 19:40:33 +0200 Subject: [PATCH 06/16] Make viewer compile on standalone linux x86_64 This involves making libllcommon shared, a change that was not finished for windows/Mac. More changes are needed to indra/newview/viewer_manifest.py for those two operating systems, as well as to indra/copy_win_scripts. I did not test this on linux 32bit, nor non-standalone on that OS, either. I did not check voice (which will very likely not work anyway on 64bit). And currently the webkit plugin doesn't work for me, but I'll fix that in a different commit. --- indra/cmake/APR.cmake | 13 ++-- indra/cmake/LLCommon.cmake | 10 ++- indra/cmake/ViewerMiscLibs.cmake | 21 +++++- indra/lib/python/indra/util/llmanifest.py | 17 +++-- indra/llcommon/CMakeLists.txt | 2 +- indra/llcommon/llpreprocessor.h | 17 +---- indra/llcommon/llstring.h | 1 + indra/media_plugins/example/CMakeLists.txt | 2 +- indra/media_plugins/webkit/CMakeLists.txt | 1 + indra/newview/CMakeLists.txt | 23 ++++--- indra/newview/linux_tools/wrapper.sh | 53 ++++---------- indra/newview/llfolderview.h | 2 +- indra/newview/llinventorybridge.h | 2 +- indra/newview/llpanelinventory.cpp | 5 +- indra/newview/viewer_manifest.py | 80 ++++++++++++++++++---- install.xml | 23 +++++++ 16 files changed, 167 insertions(+), 105 deletions(-) diff --git a/indra/cmake/APR.cmake b/indra/cmake/APR.cmake index 5cd150d58..d1f089891 100644 --- a/indra/cmake/APR.cmake +++ b/indra/cmake/APR.cmake @@ -14,16 +14,18 @@ else (STANDALONE) use_prebuilt_binary(apr_suite) if (WINDOWS) set(APR_LIBRARIES - debug ${ARCH_PREBUILT_DIRS_DEBUG}/apr-1.lib - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/apr-1.lib + debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.lib + optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.lib ) set(APRICONV_LIBRARIES debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapriconv-1.lib optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapriconv-1.lib ) + # Doesn't need to link with iconv.dll + set(APRICONV_LIBRARIES "") set(APRUTIL_LIBRARIES - debug ${ARCH_PREBUILT_DIRS_DEBUG}/aprutil-1.lib - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/aprutil-1.lib + debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.lib ${APRICONV_LIBRARIES} + optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.lib ${APRICONV_LIBRARIES} ) elseif (DARWIN) set(APR_LIBRARIES @@ -41,9 +43,8 @@ else (STANDALONE) set(APRICONV_LIBRARIES iconv) endif (WINDOWS) set(APR_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/apr-1) - set(APRUTIL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/apr-1) if (LINUX AND VIEWER) - list(APPEND APRUTIL_LIBRARIES ${DB_LIBRARIES} uuid) + list(APPEND APRUTIL_LIBRARIES ${DB_LIBRARIES}) endif (LINUX AND VIEWER) endif (STANDALONE) diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake index 410766e4f..d87d3c015 100644 --- a/indra/cmake/LLCommon.cmake +++ b/indra/cmake/LLCommon.cmake @@ -7,9 +7,15 @@ include(ZLIB) set(LLCOMMON_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llcommon - ${APRUTIL_INCLUDE_DIR} ${APR_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ) -set(LLCOMMON_LIBRARIES llcommon) +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/indra/cmake/ViewerMiscLibs.cmake b/indra/cmake/ViewerMiscLibs.cmake index 746de0fe9..38d044473 100644 --- a/indra/cmake/ViewerMiscLibs.cmake +++ b/indra/cmake/ViewerMiscLibs.cmake @@ -2,10 +2,25 @@ include(Prebuilt) if (NOT STANDALONE) + use_prebuilt_binary(libuuid) use_prebuilt_binary(vivox) - if (LINUX) - #use_prebuilt_binary(libuuid) + if(LINUX) + if (${ARCH} STREQUAL "x86_64") + use_prebuilt_binary(32bitcompatibilitylibs) + endif (${ARCH} STREQUAL "x86_64") use_prebuilt_binary(fontconfig) - endif (LINUX) + endif(LINUX) +else (NOT STANDALONE) + # Download there even when using standalone. + set(STANDALONE OFF) + use_prebuilt_binary(vivox) + if(LINUX AND ${ARCH} STREQUAL "x86_64") + use_prebuilt_binary(32bitcompatibilitylibs) + endif(LINUX AND ${ARCH} STREQUAL "x86_64") + set(STANDALONE ON) endif(NOT STANDALONE) +if (WINDOWS) + use_prebuilt_binary(dbghelp) +endif (WINDOWS) + diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py index bfac97981..585b47d4a 100644 --- a/indra/lib/python/indra/util/llmanifest.py +++ b/indra/lib/python/indra/util/llmanifest.py @@ -119,6 +119,7 @@ ARGUMENTS=[ Example use: %(name)s --arch=i686 On Linux this would try to use Linux_i686Manifest.""", default=""), + dict(name='artwork', description='Artwork directory.', default=DEFAULT_SRCTREE), dict(name='build', description='Build directory.', default=DEFAULT_SRCTREE), dict(name='buildtype', description="""The build type used. ('Debug', 'Release', 'ReleaseSSE2' or 'RelWithDebInfo') Default is Release """, @@ -126,6 +127,9 @@ ARGUMENTS=[ dict(name='branding_id', description="""Identifier for the branding set to use. Currently, 'secondlife' or 'snowglobe')""", default='secondlife'), + dict(name='channel', + description="""The channel to use for updates, packaging, settings name, etc.""", + default=get_channel), dict(name='configuration', description="""The build configuration used. Only used on OS X for now, but it could be used for other platforms as well.""", @@ -136,16 +140,13 @@ ARGUMENTS=[ though it's not strictly a grid, 'firstlook' is also an acceptable value for this parameter.""", default=""), - dict(name='channel', - description="""The channel to use for updates, packaging, settings name, etc.""", - default=get_channel), - dict(name='login_channel', - description="""The channel to use for login handshake/updates only.""", - default=None), dict(name='installer_name', description=""" The name of the file that the installer should be packaged up into. Only used on Linux at the moment.""", default=None), + dict(name='login_channel', + description="""The channel to use for login handshake/updates only.""", + default=None), dict(name='login_url', description="""The url that the login screen displays in the client.""", default=None), @@ -156,7 +157,9 @@ ARGUMENTS=[ dict(name='source', description='Source directory.', default=DEFAULT_SRCTREE), - dict(name='artwork', description='Artwork directory.', default=DEFAULT_SRCTREE), + dict(name='standalone', + description='Set to ON if this is a standalone build.', + default="OFF"), dict(name='touch', description="""File to touch when action is finished. Touch file will contain the name of the final package in a form suitable diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index ca26d492a..4bcfce5b0 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -201,7 +201,7 @@ set_source_files_properties(${llcommon_HEADER_FILES} list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES}) -add_library (llcommon ${llcommon_SOURCE_FILES}) +add_library (llcommon SHARED ${llcommon_SOURCE_FILES}) add_dependencies(llcommon prepare) target_link_libraries( llcommon diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index 39a745f25..df49757a6 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -107,17 +107,7 @@ #endif -// Static linking with apr on windows needs to be declared. -#ifdef LL_WINDOWS -#ifndef APR_DECLARE_STATIC -#define APR_DECLARE_STATIC // For APR on Windows -#endif -#ifndef APU_DECLARE_STATIC -#define APU_DECLARE_STATIC // For APR util on Windows -#endif -#endif - -// Deal with the differeneces on Windows +// Deal with the differences on Windows #if defined(LL_WINDOWS) #define BOOST_REGEX_NO_LIB 1 #define CURL_STATICLIB 1 @@ -169,7 +159,6 @@ #define LL_DLLIMPORT #endif // LL_WINDOWS -/* #ifdef llcommon_EXPORTS // Compiling llcommon (shared) #define LL_COMMON_API LL_DLLEXPORT @@ -177,9 +166,5 @@ // Using llcommon (shared) #define LL_COMMON_API LL_DLLIMPORT #endif // llcommon_EXPORTS -*/ - -//I hate DLLs -SG -#define LL_COMMON_API #endif // not LL_LINDEN_PREPROCESSOR_H diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 6b1115a54..4343a6385 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -36,6 +36,7 @@ #include #include #include +#include #if LL_LINUX || LL_SOLARIS #include diff --git a/indra/media_plugins/example/CMakeLists.txt b/indra/media_plugins/example/CMakeLists.txt index 56cefde4b..54dc5de1e 100644 --- a/indra/media_plugins/example/CMakeLists.txt +++ b/indra/media_plugins/example/CMakeLists.txt @@ -79,4 +79,4 @@ if (DARWIN) LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" ) -endif (DARWIN) \ No newline at end of file +endif (DARWIN) diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/media_plugins/webkit/CMakeLists.txt index 05f123660..3b1f67954 100755 --- a/indra/media_plugins/webkit/CMakeLists.txt +++ b/indra/media_plugins/webkit/CMakeLists.txt @@ -27,6 +27,7 @@ include_directories( ${LLIMAGE_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} + ${LLQTWEBKIT_INCLUDE_DIR} ) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index cecdbddbc..57a6163d7 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1467,6 +1467,7 @@ if (LINUX) COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + --standalone=${STANDALONE} --grid=${GRID} --channel=${VIEWER_CHANNEL} --login_channel=${VIEWER_LOGIN_CHANNEL} @@ -1591,17 +1592,17 @@ endif (LL_TESTS) # Don't do these for DARWIN or LINUX here -- they're taken care of by viewer_manifest.py if (WINDOWS) - #~ get_target_property(BUILT_LLCOMMON llcommon LOCATION) - #~ add_custom_command( - #~ TARGET ${VIEWER_BINARY_NAME} POST_BUILD - #~ COMMAND ${CMAKE_COMMAND} - #~ ARGS - #~ -E - #~ copy_if_different - #~ ${BUILT_LLCOMMON} - #~ ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} - #~ COMMENT "Copying llcommon.dll to the runtime folder." - #~ ) + get_target_property(BUILT_LLCOMMON llcommon LOCATION) + add_custom_command( + TARGET ${VIEWER_BINARY_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS + -E + copy_if_different + ${BUILT_LLCOMMON} + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} + COMMENT "Copying llcommon.dll to the runtime folder." + ) get_target_property(BUILT_SLPLUGIN SLPlugin LOCATION) add_custom_command( diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index ba101cdf9..77dd4d023 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -7,7 +7,7 @@ ## - Avoids using any OpenAL audio driver. #export LL_BAD_OPENAL_DRIVER=x ## - Avoids using any FMOD audio driver. -export LL_BAD_FMOD_DRIVER=x +#export LL_BAD_FMOD_DRIVER=x ## - Avoids using the FMOD ESD audio driver. #export LL_BAD_FMOD_ESD=x @@ -45,6 +45,7 @@ export LL_BAD_FMOD_DRIVER=x ## disable these by enabling this option: #export LL_DISABLE_GSTREAMER=x + ## Everything below this line is just for advanced troubleshooters. ##------------------------------------------------------------------- @@ -53,15 +54,8 @@ export LL_BAD_FMOD_DRIVER=x ## you're building your own viewer, bear in mind that the executable ## in the bin directory will be stripped: you should replace it with ## an unstripped binary before you run. -## -## I keep crashing without having GDB running, always run it if an -## environment variable is set. - -if [ -n "$ASCENDED_DEVELOPER" ]; then -# export LL_WRAPPER='cgdb --args' - export LL_WRAPPER='gdb --args' -# export LL_WRAPPER='valgrind --smc-check=all --error-limit=no --log-file=secondlife.vg --leak-check=full --suppressions=/usr/lib/valgrind/glibc-2.5.supp --suppressions=secondlife-i686.supp' -fi +#export LL_WRAPPER='gdb --args' +#export LL_WRAPPER='valgrind --smc-check=all --error-limit=no --log-file=secondlife.vg --leak-check=full --suppressions=/usr/lib/valgrind/glibc-2.5.supp --suppressions=secondlife-i686.supp' ## - Avoids an often-buggy X feature that doesn't really benefit us anyway. export SDL_VIDEO_X11_DGAMOUSE=0 @@ -74,13 +68,6 @@ if [ "$GTK_IM_MODULE" = "scim" ]; then export GTK_IM_MODULE=xim fi -# Work around for a crash bug when restarting OpenGL after a change in the -# graphic settings (anti-aliasing, VBO, FSAA, full screen mode, UI scale). -# When you enable this work around, you can change the settings without -# crashing, but you will have to restart the viewer after changing them -# because the display still gets corrupted. -export LL_OPENGL_RESTART_CRASH_BUG=x - ## - Automatically work around the ATI mouse cursor crash bug: ## (this workaround is disabled as most fglrx users do not see the bug) #if lsmod | grep fglrx &>/dev/null ; then @@ -121,7 +108,13 @@ if [ -n "$LL_TCMALLOC" ]; then fi export VIEWER_BINARY='singularity-do-not-run-directly' -export SL_ENV='LD_LIBRARY_PATH="`pwd`"/lib:"`pwd`"/app_settings/mozilla-runtime-linux-i686:"${LD_LIBRARY_PATH}"' +BINARY_TYPE=$(expr match "$(file -b bin/$VIEWER_BINARY)" '\(.*executable\)') +if [ "${BINARY_TYPE}" == "ELF 64-bit LSB executable" ]; then + export SL_ENV='LD_LIBRARY_PATH="`pwd`"/lib64:"`pwd`"/lib32:"${LD_LIBRARY_PATH}"' +else + export SL_ENV='LD_LIBRARY_PATH="`pwd`"/lib:"${LD_LIBRARY_PATH}"' +fi + export SL_CMD='$LL_WRAPPER bin/$VIEWER_BINARY' export SL_OPT="`cat gridargs.dat` $@" @@ -134,27 +127,7 @@ if [ -n "$LL_RUN_ERR" ]; then if [ "$LL_RUN_ERR" = "runerr" ]; then # generic error running the binary echo '*** Bad shutdown. ***' - BINARY_TYPE=$(expr match "$(file -b ${RUN_PATH}/bin/SLPlugin)" '\(.*executable\)') - BINARY_SYSTEM=$(expr match "$(file -b /bin/uname)" '\(.*executable\)') - if [ "${BINARY_SYSTEM}" == "ELF 64-bit LSB executable" -a "${BINARY_TYPE}" == "ELF 32-bit LSB executable" ]; then - echo - cat << EOFMARKER -You are running the Second Life Viewer on a x86_64 platform. The -most common problems when launching the Viewer (particularly -'bin/$VIEWER_BINARY: not found' and 'error while -loading shared libraries') may be solved by installing your Linux -distribution's 32-bit compatibility packages. -For example, on Ubuntu and other Debian-based Linuxes you might run: -$ sudo apt-get install ia32-libs ia32-libs-gtk ia32-libs-kde ia32-libs-sdl -EOFMARKER - fi + + fi fi - - -echo -echo '*******************************************************' -echo 'This is a BETA release of the Second Life linux client.' -echo 'Thank you for testing!' -echo 'Please see README-linux.txt before reporting problems.' -echo diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 71b4e638d..9e4f9e24b 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -97,7 +97,7 @@ public: virtual void move( LLFolderViewEventListener* parent_listener ) = 0; virtual BOOL isItemCopyable() const = 0; virtual BOOL copyToClipboard() const = 0; - virtual void cutToClipboard() = 0; + virtual BOOL cutToClipboard() const = 0; virtual BOOL isClipboardPasteable() const = 0; virtual void pasteFromClipboard() = 0; virtual void pasteLinkFromClipboard() = 0; diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index dcadc2781..a3108d653 100755 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -232,7 +232,7 @@ public: virtual void move(LLFolderViewEventListener* new_parent_bridge) {} virtual BOOL isItemCopyable() const { return FALSE; } virtual BOOL copyToClipboard() const { return FALSE; } - virtual void cutToClipboard() {} + virtual BOOL cutToClipboard() const { return FALSE; } virtual BOOL isClipboardPasteable() const; virtual BOOL isClipboardPasteableAsLink() const; virtual void pasteFromClipboard() {} diff --git a/indra/newview/llpanelinventory.cpp b/indra/newview/llpanelinventory.cpp index 38521e7ab..38c90783b 100644 --- a/indra/newview/llpanelinventory.cpp +++ b/indra/newview/llpanelinventory.cpp @@ -144,7 +144,7 @@ public: virtual void move(LLFolderViewEventListener* parent_listener); virtual BOOL isItemCopyable() const; virtual BOOL copyToClipboard() const; - virtual void cutToClipboard(); + virtual BOOL cutToClipboard() const; virtual BOOL isClipboardPasteable() const; virtual void pasteFromClipboard(); virtual void pasteLinkFromClipboard(); @@ -596,8 +596,9 @@ BOOL LLTaskInvFVBridge::copyToClipboard() const return FALSE; } -void LLTaskInvFVBridge::cutToClipboard() +BOOL LLTaskInvFVBridge::cutToClipboard() const { + return FALSE; } BOOL LLTaskInvFVBridge::isClipboardPasteable() const diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index e560b7b46..02eca9bff 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -121,6 +121,8 @@ class ViewerManifest(LLManifest): def buildtype(self): return self.args['buildtype'] + def standalone(self): + return self.args['standalone'] == "ON" def grid(self): return self.args['grid'] def channel(self): @@ -752,19 +754,9 @@ class Linux_i686Manifest(LinuxManifest): def construct(self): super(Linux_i686Manifest, self).construct() - # install either the libllkdu we just built, or a prebuilt one, in - # decreasing order of preference. for linux package, this goes to bin/ - #~ try: - #~ self.path(self.find_existing_file('../llkdu/libllkdu.so', - #~ '../../libraries/i686-linux/lib_release_client/libllkdu.so'), - #~ dst='bin/libllkdu.so') - #~ # keep this one to preserve syntax, open source mangling removes previous lines - #~ pass - #~ except: - #~ print "Skipping libllkdu.so - not found" - #~ pass + self.path("../llcommon/libllcommon.so", "lib/libllcommon.so") - if self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"): + if (not self.standalone()) and self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"): try: self.path("libkdu_v42R.so", "libkdu.so") @@ -807,12 +799,72 @@ class Linux_i686Manifest(LinuxManifest): self.path("libvivoxsdk.so") self.end_prefix("lib") + class Linux_x86_64Manifest(LinuxManifest): def construct(self): super(Linux_x86_64Manifest, self).construct() - # support file for valgrind debug tool - self.path("secondlife-i686.supp") + self.path("../llcommon/libllcommon.so", "lib64/libllcommon.so") + + if (not self.standalone()) and self.prefix("../../libraries/x86_64-linux/lib_release_client", dst="lib64"): + self.path("libapr-1.so.0") + self.path("libaprutil-1.so.0") + self.path("libdb-4.2.so") + self.path("libcrypto.so.0.9.8") + self.path("libexpat.so.1") + self.path("libhunspell-1.2.so.0.0.0", "libhunspell-1.2.so.0") + self.path("libssl.so.0.9.8") + self.path("libuuid.so", "libuuid.so.1") + self.path("libSDL-1.2.so.0") + self.path("libELFIO.so") + self.path("libjpeg.so.7") + self.path("libpng12.so.0") + self.path("libopenjpeg.so.2") + self.path("libxml2.so.2") + #self.path("libz.so.1") #not needed + + # OpenAL + self.path("libopenal.so.1") + self.path("libalut.so.0") + + # GTK+ and dependencies + ## Lets just use the system libraries for all of these: + ##self.path("libatk-1.0.so.0") + ##self.path("libcairo.so.2") + ##self.path("libfontconfig.so.1") + ##self.path("libfreetype.so.6") + self.path("libgdk_pixbuf-2.0.so.0") # was commented to use systems gdk pixbufs instead - + # but seems webkit needs it o_O . Packaging for testing now. + ##self.path("libgdk-x11-2.0.so.0") + ##self.path("libgtk-x11-2.0.so.0") +# self.path("libpango-1.0.so.0") # use systems pango instead +# self.path("libpangoft2-1.0.so.0") # Both gdk pixbufs and pango would load systems modules +# self.path("libpangox-1.0.so.0") # and crash if not compatible or present. +# self.path("libpangoxft-1.0.so.0") # So we depend system gdk pixbufs and pango anyway. + ##self.path("libpixman-1.so.0") + + self.end_prefix("lib64") + + + # Vivox runtimes and libs + if self.prefix(src="vivox-runtime/i686-linux", dst="bin"): + self.path("SLVoice") + self.end_prefix("bin") + + if self.prefix(src="vivox-runtime/i686-linux", dst="lib32"): + #self.path("libalut.so") + self.path("libortp.so") + self.path("libvivoxsdk.so") + self.end_prefix("lib32") + + # 32bit libs needed for voice + if self.prefix("../../libraries/x86_64-linux/lib_release_client/32bit-compat", dst="lib32"): + self.path("libalut.so") + self.path("libidn.so.11") + self.path("libopenal.so.1") + # self.path("libortp.so") + self.path("libuuid.so.1") + self.end_prefix("lib32") if __name__ == "__main__": main() diff --git a/install.xml b/install.xml index 2a8b831e5..2ea504fe5 100644 --- a/install.xml +++ b/install.xml @@ -1340,6 +1340,29 @@ anguage Infrstructure (CLI) international standard + 32bitcompatibilitylibs + + copyright + Copyrights: Libidn: Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + Simon Josefsson. License GPL v3.0. + Freealut, libuuid, openal-soft: see copyright and license of the + according main packages. + + description + 32bit libraries needed for using voice + license + gpl + packages + + linux64 + + md5sum + cbaafc55fb8b14283541791e82f13462 + url + http://imprudenceviewer.org/download/libs/linux64-32bitcompatibilitylibs-20100903.tar.bz2 + + + xmlrpc-epi copyright From 1ced64e0b4a202c88126f7cb027c4695b8caad31 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 2 May 2011 20:15:50 +0200 Subject: [PATCH 07/16] Add LLWeb::curlEscape Since curl 7.21.2 - (October 13 2010), curl_escape (a deprecated function that will be removed in the future) changed it's behavior and no longer escapes the characters '-', '.', '_' and '~'. The only reasonable solution for us is to stop using it and use our own version that mimics the old behavior. The only other alternative would be to rename every .xml file with escaped characters in their name upon installation, depending on the behavior of the installed libcurl (on standalone anyway). However, if you add to that in the future curl_escape has to be replaced with curl_easy_escape, which is far from easy to call as it requires a CURL to be passed for which LL invented a wrapper in libllmessage, but did hide that (Curl::Easy is only defined in a .cpp file), then we're better of just using our own function, which I named LLWeb::curlEscape. --- indra/newview/ascentdaycyclemanager.cpp | 15 +++------------ indra/newview/llpanellogin.cpp | 23 +++++------------------ indra/newview/lltranslate.cpp | 3 ++- indra/newview/llwaterparammanager.cpp | 15 +++------------ indra/newview/llweb.cpp | 14 ++++++++++++++ indra/newview/llweb.h | 3 +++ indra/newview/llwldaycycle.cpp | 11 +++-------- indra/newview/llwlparammanager.cpp | 15 +++------------ 8 files changed, 36 insertions(+), 63 deletions(-) diff --git a/indra/newview/ascentdaycyclemanager.cpp b/indra/newview/ascentdaycyclemanager.cpp index b83168f64..43f243f08 100644 --- a/indra/newview/ascentdaycyclemanager.cpp +++ b/indra/newview/ascentdaycyclemanager.cpp @@ -134,10 +134,7 @@ void AscentDayCycleManager::loadPreset(const std::string & name,bool propagate) { // bugfix for SL-46920: preventing filenames that break stuff. - char * curl_str = curl_escape(name.c_str(), name.size()); - std::string escaped_filename(curl_str); - curl_free(curl_str); - curl_str = NULL; + std::string escaped_filename = LLWeb::curlEscape(name); escaped_filename += ".xml"; @@ -186,10 +183,7 @@ void AscentDayCycleManager::loadPreset(const std::string & name,bool propagate) void AscentDayCycleManager::savePreset(const std::string & name) { // bugfix for SL-46920: preventing filenames that break stuff. - char * curl_str = curl_escape(name.c_str(), name.size()); - std::string escaped_filename(curl_str); - curl_free(curl_str); - curl_str = NULL; + std::string escaped_filename = LLWeb::curlEscape(name); escaped_filename += ".xml"; @@ -340,10 +334,7 @@ bool AscentDayCycleManager::removeParamSet(const std::string& name, bool delete_ std::string path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/days", "")); // use full curl escaped name - char * curl_str = curl_escape(name.c_str(), name.size()); - std::string escaped_name(curl_str); - curl_free(curl_str); - curl_str = NULL; + std::string escaped_name = LLWeb::curlEscape(name); gDirUtilp->deleteFilesInDir(path_name, escaped_name + ".xml"); } diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index ece744e5e..7d7d65a35 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -911,20 +911,11 @@ void LLPanelLogin::loadLoginPage() std::string version = llformat("%d.%d.%d (%d)", LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VERSION_BUILD); - char* curl_channel = curl_escape(LL_CHANNEL, 0); - - char* curl_version = curl_escape(version.c_str(), 0); - - oStr << "&channel=" << curl_channel; - oStr << "&version=" << curl_version; - - curl_free(curl_channel); - curl_free(curl_version); + oStr << "&channel=" << LLWeb::curlEscape(LL_CHANNEL); + oStr << "&version=" << LLWeb::curlEscape(version); // Grid - char* curl_grid = curl_escape(LLViewerLogin::getInstance()->getGridLabel().c_str(), 0); - oStr << "&grid=" << curl_grid; - curl_free(curl_grid); + oStr << "&grid=" << LLWeb::curlEscape(LLViewerLogin::getInstance()->getGridLabel()); if (gHippoGridManager->getConnectedGrid()->isSecondLife()) { // find second life grid from login URI @@ -938,9 +929,7 @@ void LLPanelLogin::loadLoginPage() i = tmp.rfind('/'); if (i != std::string::npos) { tmp = tmp.substr(i+1); - char* curl_grid = curl_escape(tmp.c_str(), 0); - oStr << "&grid=" << curl_grid; - curl_free(curl_grid); + oStr << "&grid=" << LLWeb::curlEscape(tmp); } } } @@ -997,13 +986,11 @@ void LLPanelLogin::loadLoginPage() lastname = gSavedSettings.getString("LastName"); } - char* curl_region = curl_escape(region.c_str(), 0); + std::string curl_region = LLWeb::curlEscape(region); oStr <<"firstname=" << firstname << "&lastname=" << lastname << "&location=" << location << "®ion=" << curl_region; - curl_free(curl_region); - if (!password.empty()) { oStr << "&password=" << password; diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index d4bb75913..501dfe29b 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -36,6 +36,7 @@ #include "lltranslate.h" #include "llui.h" #include "llversionviewer.h" +#include "llweb.h" // #include "llviewercontrol.h" @@ -79,7 +80,7 @@ void LLTranslate::translateMessage(LLHTTPClient::ResponderPtr &result, const std //static void LLTranslate::getTranslateUrl(std::string &translateUrl, const std::string &fromLang, const std::string &toLang, const std::string &mesg) { - std::string escaped_mesg = curl_escape(mesg.c_str(), mesg.size()); + std::string escaped_mesg = LLWeb::curlEscape(mesg); translateUrl = m_GoogleURL + escaped_mesg + m_GoogleLangSpec diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp index 848c8137f..682079249 100644 --- a/indra/newview/llwaterparammanager.cpp +++ b/indra/newview/llwaterparammanager.cpp @@ -143,10 +143,7 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name) void LLWaterParamManager::loadPreset(const std::string & name,bool propagate) { // bugfix for SL-46920: preventing filenames that break stuff. - char * curl_str = curl_escape(name.c_str(), name.size()); - std::string escaped_filename(curl_str); - curl_free(curl_str); - curl_str = NULL; + std::string escaped_filename = LLWeb::curlEscape(name); escaped_filename += ".xml"; @@ -199,10 +196,7 @@ void LLWaterParamManager::loadPreset(const std::string & name,bool propagate) void LLWaterParamManager::savePreset(const std::string & name) { // bugfix for SL-46920: preventing filenames that break stuff. - char * curl_str = curl_escape(name.c_str(), name.size()); - std::string escaped_filename(curl_str); - curl_free(curl_str); - curl_str = NULL; + std::string escaped_filename = LLWeb::curlEscape(name); escaped_filename += ".xml"; @@ -415,10 +409,7 @@ bool LLWaterParamManager::removeParamSet(const std::string& name, bool delete_fr std::string path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", "")); // use full curl escaped name - char * curl_str = curl_escape(name.c_str(), name.size()); - std::string escaped_name(curl_str); - curl_free(curl_str); - curl_str = NULL; + std::string escaped_name = LLWeb::curlEscape(name); gDirUtilp->deleteFilesInDir(path_name, escaped_name + ".xml"); } diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index 7a7c80fdf..b57e4bcc8 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -68,6 +68,20 @@ void LLWeb::loadURLExternal(const std::string& url) } +// static +std::string LLWeb::curlEscape(const std::string& url) +{ + std::stringstream escaped_url; + for (std::string::const_iterator iter = url.begin(); iter != url.end(); ++iter) + { + if (std::isalnum(*iter)) + escaped_url << *iter; + else + escaped_url << '%' << std::hex << std::setfill('0') << std::setw(2) << std::uppercase << (int)*iter; + } + return escaped_url.str(); +} + // static std::string LLWeb::escapeURL(const std::string& url) { diff --git a/indra/newview/llweb.h b/indra/newview/llweb.h index 278821bac..8dd13ffcb 100644 --- a/indra/newview/llweb.h +++ b/indra/newview/llweb.h @@ -51,6 +51,9 @@ public: // Loads unescaped url in external browser. static void loadURLExternal(const std::string& url); + // Behaves like the old curl_escape. + static std::string curlEscape(const std::string& url); + // Returns escaped (eg, " " to "%20") url static std::string escapeURL(const std::string& url); diff --git a/indra/newview/llwldaycycle.cpp b/indra/newview/llwldaycycle.cpp index 2abf9d45a..577d1edc1 100644 --- a/indra/newview/llwldaycycle.cpp +++ b/indra/newview/llwldaycycle.cpp @@ -35,6 +35,7 @@ #include "llwldaycycle.h" #include "llsdserialize.h" #include "llwlparammanager.h" +#include "llweb.h" #include "llviewerwindow.h" @@ -57,10 +58,7 @@ void LLWLDayCycle::loadDayCycle(const std::string & fileName) mTimeMap.clear(); // bugfix for SL-46920: preventing filenames that break stuff. - char * curl_str = curl_escape(fileName.c_str(), fileName.size()); - std::string escaped_filename(curl_str); - curl_free(curl_str); - curl_str = NULL; + std::string escaped_filename = LLWeb::curlEscape(fileName); escaped_filename += ".xml"; @@ -125,10 +123,7 @@ void LLWLDayCycle::saveDayCycle(const std::string & fileName) { // bugfix for SL-46920: preventing filenames that break stuff. - char * curl_str = curl_escape(fileName.c_str(), fileName.size()); - std::string escaped_filename(curl_str); - curl_free(curl_str); - curl_str = NULL; + std::string escaped_filename = LLWeb::curlEscape(fileName); escaped_filename += ".xml"; diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp index dfe921667..bb41f9aac 100644 --- a/indra/newview/llwlparammanager.cpp +++ b/indra/newview/llwlparammanager.cpp @@ -187,10 +187,7 @@ void LLWLParamManager::loadPreset(const std::string & name,bool propagate) { // bugfix for SL-46920: preventing filenames that break stuff. - char * curl_str = curl_escape(name.c_str(), name.size()); - std::string escaped_filename(curl_str); - curl_free(curl_str); - curl_str = NULL; + std::string escaped_filename = LLWeb::curlEscape(name); escaped_filename += ".xml"; @@ -244,10 +241,7 @@ void LLWLParamManager::loadPreset(const std::string & name,bool propagate) void LLWLParamManager::savePreset(const std::string & name) { // bugfix for SL-46920: preventing filenames that break stuff. - char * curl_str = curl_escape(name.c_str(), name.size()); - std::string escaped_filename(curl_str); - curl_free(curl_str); - curl_str = NULL; + std::string escaped_filename = LLWeb::curlEscape(name); escaped_filename += ".xml"; @@ -531,10 +525,7 @@ bool LLWLParamManager::removeParamSet(const std::string& name, bool delete_from_ std::string path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", "")); // use full curl escaped name - char * curl_str = curl_escape(name.c_str(), name.size()); - std::string escaped_name(curl_str); - curl_free(curl_str); - curl_str = NULL; + std::string escaped_name = LLWeb::curlEscape(name); gDirUtilp->deleteFilesInDir(path_name, escaped_name + ".xml"); } From c0c786b39f16e6900df4a902c7ed4d8b04043503 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 2 May 2011 20:50:26 +0200 Subject: [PATCH 08/16] Make loading prebuilts work. Copied indra/cmake/Prebuilt.cmake from imprudence, which fixed this issue. --- indra/cmake/Prebuilt.cmake | 47 ++++++++++++++++++++++++++++++++------ install.xml | 7 ++++++ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/indra/cmake/Prebuilt.cmake b/indra/cmake/Prebuilt.cmake index 6dd9c47bd..a91519278 100644 --- a/indra/cmake/Prebuilt.cmake +++ b/indra/cmake/Prebuilt.cmake @@ -1,11 +1,44 @@ # -*- cmake -*- +include(Python) +include(FindSCP) + macro (use_prebuilt_binary _binary) - if(NOT STANDALONE) - get_property(PREBUILT_PACKAGES TARGET prepare PROPERTY PREBUILT) - list(FIND PREBUILT_PACKAGES ${_binary} _index) - if(_index LESS 0) - set_property(TARGET prepare APPEND PROPERTY PREBUILT ${_binary}) - endif(_index LESS 0) - endif(NOT STANDALONE) + if (NOT STANDALONE) + if(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed) + if(INSTALL_PROPRIETARY) + include(FindSCP) + if(DEBUG_PREBUILT) + message("cd ${SCRIPTS_DIR} && ${PYTHON_EXECUTABLE} install.py --install-dir=${CMAKE_SOURCE_DIR}/.. --scp=${SCP_EXECUTABLE} ${_binary}") + endif(DEBUG_PREBUILT) + execute_process(COMMAND ${PYTHON_EXECUTABLE} + install.py + --install-dir=${CMAKE_SOURCE_DIR}/.. + --scp=${SCP_EXECUTABLE} + ${_binary} + WORKING_DIRECTORY ${SCRIPTS_DIR} + RESULT_VARIABLE ${_binary}_installed + ) + else(INSTALL_PROPRIETARY) + if(DEBUG_PREBUILT) + message("cd ${SCRIPTS_DIR} && ${PYTHON_EXECUTABLE} install.py --install-dir=${CMAKE_SOURCE_DIR}/.. ${_binary}") + endif(DEBUG_PREBUILT) + execute_process(COMMAND ${PYTHON_EXECUTABLE} + install.py + --install-dir=${CMAKE_SOURCE_DIR}/.. + ${_binary} + WORKING_DIRECTORY ${SCRIPTS_DIR} + RESULT_VARIABLE ${_binary}_installed + ) + endif(INSTALL_PROPRIETARY) + file(WRITE ${CMAKE_BINARY_DIR}/temp/${_binary}_installed "${${_binary}_installed}") + else(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed) + set(${_binary}_installed 0) + endif(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed) + if(NOT ${_binary}_installed EQUAL 0) + message(FATAL_ERROR + "Failed to download or unpack prebuilt '${_binary}'." + " Process returned ${${_binary}_installed}.") + endif (NOT ${_binary}_installed EQUAL 0) + endif (NOT STANDALONE) endmacro (use_prebuilt_binary _binary) diff --git a/install.xml b/install.xml index 2ea504fe5..2b31c307a 100644 --- a/install.xml +++ b/install.xml @@ -1331,6 +1331,13 @@ anguage Infrstructure (CLI) international standard url http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6270-linux-20090309.tar.bz2 + linux64 + + md5sum + 01573510dce7f380f44e561ef2f3dd9f + url + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6270-linux-20090309.tar.bz2 + windows md5sum From 6848c2df6f0e699aba92284fa4c9d18c7bf807c5 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 2 May 2011 23:13:15 +0200 Subject: [PATCH 09/16] Fix underlinkage of libmedia_plugin_webkit.so Fixed by updating indra/cmake/WebKitLibPlugin.cmake with version from imprudence. This commit also contains removal of execute permissions of source files and configure files, sorry... --- indra/cmake/WebKitLibPlugin.cmake | 61 +++++++++++++------ indra/llcrashlogger/llcrashlogger.cpp | 0 indra/llcrashlogger/llcrashlogger.h | 0 indra/llmessage/llsdmessagebuilder.cpp | 0 indra/llmessage/llsdmessagebuilder.h | 0 indra/llmessage/llsdmessagereader.cpp | 0 indra/llmessage/llsdmessagereader.h | 0 indra/llplugin/llpluginclassmedia.cpp | 0 indra/llplugin/llpluginclassmedia.h | 0 indra/llplugin/llpluginclassmediaowner.h | 0 indra/llplugin/llplugininstance.cpp | 0 indra/llplugin/llplugininstance.h | 0 indra/llplugin/llpluginmessage.cpp | 0 indra/llplugin/llpluginmessage.h | 0 indra/llplugin/llpluginmessageclasses.h | 0 indra/llplugin/llpluginmessagepipe.cpp | 0 indra/llplugin/llpluginmessagepipe.h | 0 indra/llplugin/llpluginprocesschild.cpp | 0 indra/llplugin/llpluginprocesschild.h | 0 indra/llplugin/llpluginprocessparent.cpp | 0 indra/llplugin/llpluginprocessparent.h | 0 indra/llplugin/llpluginsharedmemory.cpp | 0 indra/llplugin/llpluginsharedmemory.h | 0 indra/llplugin/slplugin/slplugin.cpp | 0 indra/llui/llmemberlistener.h | 0 indra/llui/lluistring.cpp | 0 indra/llui/lluistring.h | 0 indra/llvfs/llpidlock.cpp | 0 indra/llvfs/llpidlock.h | 0 indra/llwindow/glh/glh_linear.h | 0 indra/media_plugins/CMakeLists.txt | 0 .../media_plugins/base/media_plugin_base.cpp | 0 indra/media_plugins/base/media_plugin_base.h | 0 .../example/media_plugin_example.cpp | 0 indra/media_plugins/quicktime/CMakeLists.txt | 0 .../quicktime/media_plugin_quicktime.cpp | 0 indra/media_plugins/webkit/CMakeLists.txt | 0 .../webkit/dummy_volume_catcher.cpp | 0 .../webkit/linux_volume_catcher.cpp | 0 .../webkit/linux_volume_catcher_pa_syms.inc | 0 .../linux_volume_catcher_paglib_syms.inc | 0 .../webkit/mac_volume_catcher.cpp | 0 .../webkit/media_plugin_webkit.cpp | 0 indra/media_plugins/webkit/volume_catcher.h | 0 .../webkit/windows_volume_catcher.cpp | 0 indra/newview/hippofloaterxml.cpp | 0 indra/newview/hippofloaterxml.h | 0 indra/newview/llfloatersellland.cpp | 0 indra/newview/llfloatersellland.h | 0 indra/newview/llinventorybridge.h | 0 indra/newview/lltoolpipette.cpp | 0 indra/newview/lltoolpipette.h | 0 indra/newview/llviewerobjectbackup.cpp | 0 indra/newview/llviewerobjectbackup.h | 0 indra/test/llrandom_tut.cpp | 0 indra/test/llsdmessagebuilder_tut.cpp | 0 indra/test/llsdmessagereader_tut.cpp | 0 indra/test_apps/llplugintest/CMakeLists.txt | 0 indra/test_apps/llplugintest/bookmarks.txt | 0 .../llplugintest/demo_media_plugin.cpp | 0 .../llplugintest/demo_media_plugin_2.cpp | 0 indra/test_apps/llplugintest/demo_plugin.cpp | 0 .../llplugintest/llmediaplugintest.cpp | 0 .../llplugintest/llmediaplugintest.h | 0 .../test_apps/llplugintest/media_mappings.txt | 0 .../llplugintest/media_plugin_test.cpp | 0 .../llplugintest/media_simple_test.cpp | 0 indra/test_apps/llplugintest/plugin_host.cpp | 0 .../llplugintest/plugin_process_launcher.cpp | 0 69 files changed, 42 insertions(+), 19 deletions(-) mode change 100755 => 100644 indra/llcrashlogger/llcrashlogger.cpp mode change 100755 => 100644 indra/llcrashlogger/llcrashlogger.h mode change 100755 => 100644 indra/llmessage/llsdmessagebuilder.cpp mode change 100755 => 100644 indra/llmessage/llsdmessagebuilder.h mode change 100755 => 100644 indra/llmessage/llsdmessagereader.cpp mode change 100755 => 100644 indra/llmessage/llsdmessagereader.h mode change 100755 => 100644 indra/llplugin/llpluginclassmedia.cpp mode change 100755 => 100644 indra/llplugin/llpluginclassmedia.h mode change 100755 => 100644 indra/llplugin/llpluginclassmediaowner.h mode change 100755 => 100644 indra/llplugin/llplugininstance.cpp mode change 100755 => 100644 indra/llplugin/llplugininstance.h mode change 100755 => 100644 indra/llplugin/llpluginmessage.cpp mode change 100755 => 100644 indra/llplugin/llpluginmessage.h mode change 100755 => 100644 indra/llplugin/llpluginmessageclasses.h mode change 100755 => 100644 indra/llplugin/llpluginmessagepipe.cpp mode change 100755 => 100644 indra/llplugin/llpluginmessagepipe.h mode change 100755 => 100644 indra/llplugin/llpluginprocesschild.cpp mode change 100755 => 100644 indra/llplugin/llpluginprocesschild.h mode change 100755 => 100644 indra/llplugin/llpluginprocessparent.cpp mode change 100755 => 100644 indra/llplugin/llpluginprocessparent.h mode change 100755 => 100644 indra/llplugin/llpluginsharedmemory.cpp mode change 100755 => 100644 indra/llplugin/llpluginsharedmemory.h mode change 100755 => 100644 indra/llplugin/slplugin/slplugin.cpp mode change 100755 => 100644 indra/llui/llmemberlistener.h mode change 100755 => 100644 indra/llui/lluistring.cpp mode change 100755 => 100644 indra/llui/lluistring.h mode change 100755 => 100644 indra/llvfs/llpidlock.cpp mode change 100755 => 100644 indra/llvfs/llpidlock.h mode change 100755 => 100644 indra/llwindow/glh/glh_linear.h mode change 100755 => 100644 indra/media_plugins/CMakeLists.txt mode change 100755 => 100644 indra/media_plugins/base/media_plugin_base.cpp mode change 100755 => 100644 indra/media_plugins/base/media_plugin_base.h mode change 100755 => 100644 indra/media_plugins/example/media_plugin_example.cpp mode change 100755 => 100644 indra/media_plugins/quicktime/CMakeLists.txt mode change 100755 => 100644 indra/media_plugins/quicktime/media_plugin_quicktime.cpp mode change 100755 => 100644 indra/media_plugins/webkit/CMakeLists.txt mode change 100755 => 100644 indra/media_plugins/webkit/dummy_volume_catcher.cpp mode change 100755 => 100644 indra/media_plugins/webkit/linux_volume_catcher.cpp mode change 100755 => 100644 indra/media_plugins/webkit/linux_volume_catcher_pa_syms.inc mode change 100755 => 100644 indra/media_plugins/webkit/linux_volume_catcher_paglib_syms.inc mode change 100755 => 100644 indra/media_plugins/webkit/mac_volume_catcher.cpp mode change 100755 => 100644 indra/media_plugins/webkit/media_plugin_webkit.cpp mode change 100755 => 100644 indra/media_plugins/webkit/volume_catcher.h mode change 100755 => 100644 indra/media_plugins/webkit/windows_volume_catcher.cpp mode change 100755 => 100644 indra/newview/hippofloaterxml.cpp mode change 100755 => 100644 indra/newview/hippofloaterxml.h mode change 100755 => 100644 indra/newview/llfloatersellland.cpp mode change 100755 => 100644 indra/newview/llfloatersellland.h mode change 100755 => 100644 indra/newview/llinventorybridge.h mode change 100755 => 100644 indra/newview/lltoolpipette.cpp mode change 100755 => 100644 indra/newview/lltoolpipette.h mode change 100755 => 100644 indra/newview/llviewerobjectbackup.cpp mode change 100755 => 100644 indra/newview/llviewerobjectbackup.h mode change 100755 => 100644 indra/test/llrandom_tut.cpp mode change 100755 => 100644 indra/test/llsdmessagebuilder_tut.cpp mode change 100755 => 100644 indra/test/llsdmessagereader_tut.cpp mode change 100755 => 100644 indra/test_apps/llplugintest/CMakeLists.txt mode change 100755 => 100644 indra/test_apps/llplugintest/bookmarks.txt mode change 100755 => 100644 indra/test_apps/llplugintest/demo_media_plugin.cpp mode change 100755 => 100644 indra/test_apps/llplugintest/demo_media_plugin_2.cpp mode change 100755 => 100644 indra/test_apps/llplugintest/demo_plugin.cpp mode change 100755 => 100644 indra/test_apps/llplugintest/llmediaplugintest.cpp mode change 100755 => 100644 indra/test_apps/llplugintest/llmediaplugintest.h mode change 100755 => 100644 indra/test_apps/llplugintest/media_mappings.txt mode change 100755 => 100644 indra/test_apps/llplugintest/media_plugin_test.cpp mode change 100755 => 100644 indra/test_apps/llplugintest/media_simple_test.cpp mode change 100755 => 100644 indra/test_apps/llplugintest/plugin_host.cpp mode change 100755 => 100644 indra/test_apps/llplugintest/plugin_process_launcher.cpp diff --git a/indra/cmake/WebKitLibPlugin.cmake b/indra/cmake/WebKitLibPlugin.cmake index 44f5619e1..a4befa495 100644 --- a/indra/cmake/WebKitLibPlugin.cmake +++ b/indra/cmake/WebKitLibPlugin.cmake @@ -3,7 +3,29 @@ include(Linking) include(Prebuilt) if (STANDALONE) - find_package(LLQtWebkit REQUIRED) + # The minimal version, 4.4.3, is rather arbitrary: it's the version in Debian/Lenny. + find_package(Qt4 4.4.3 COMPONENTS QtCore QtGui QtNetwork QtOpenGL QtWebKit REQUIRED) + include(${QT_USE_FILE}) + set(QTDIR $ENV{QTDIR}) + if (QTDIR AND NOT "${QT_BINARY_DIR}" STREQUAL "${QTDIR}/bin") + message(FATAL_ERROR "\"${QT_BINARY_DIR}\" is unequal \"${QTDIR}/bin\"; " + "Qt is found by looking for qmake in your PATH. " + "Please set your PATH such that 'qmake' is found in \$QTDIR/bin, " + "or unset QTDIR if the found Qt is correct.") + endif (QTDIR AND NOT "${QT_BINARY_DIR}" STREQUAL "${QTDIR}/bin") + find_package(LLQtWebkit REQUIRED QUIET) + # Add the plugins. + set(QT_PLUGIN_LIBRARIES) + foreach(qlibname qgif qjpeg) + find_library(QT_PLUGIN_${qlibname} ${qlibname} PATHS ${QT_PLUGINS_DIR}/imageformats NO_DEFAULT_PATH) + if (QT_PLUGIN_${qlibname}) + list(APPEND QT_PLUGIN_LIBRARIES ${QT_PLUGIN_${qlibname}}) + else (QT_PLUGIN_${qtlibname}) + message(FATAL_ERROR "Could not find the Qt plugin ${qlibname} in \"${QT_PLUGINS_DIR}/imageformats\"!") + endif (QT_PLUGIN_${qlibname}) + endforeach(qlibname) + # qjpeg depends on libjpeg + list(APPEND QT_PLUGIN_LIBRARIES jpeg) set(WEBKITLIBPLUGIN OFF CACHE BOOL "WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.") else (STANDALONE) @@ -32,25 +54,26 @@ if (WINDOWS) elseif (DARWIN) set(WEBKIT_PLUGIN_LIBRARIES optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib - debug ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib + debug ${ARCH_PREBUILT_DIRS_DEBUG}/libllqtwebkit.dylib ) elseif (LINUX) - if (STANDALONE) - set(WEBKIT_PLUGIN_LIBRARIES ${LLQTWEBKIT_LIBRARY}) - else (STANDALONE) + if (STANDALONE) + set(WEBKIT_PLUGIN_LIBRARIES ${LLQTWEBKIT_LIBRARY} ${QT_LIBRARIES} ${QT_PLUGIN_LIBRARIES}) + else (STANDALONE) set(WEBKIT_PLUGIN_LIBRARIES - llqtwebkit - qgif - qjpeg - QtWebKit - QtOpenGL - QtNetwork - QtGui - QtCore - fontconfig - X11 - Xrender - GL - ) - endif (STANDALONE) + llqtwebkit + qgif + qjpeg + QtWebKit + QtOpenGL + QtNetwork + QtGui + QtCore + jpeg + fontconfig + X11 + Xrender + GL + ) + endif (STANDALONE) endif (WINDOWS) diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp old mode 100755 new mode 100644 diff --git a/indra/llcrashlogger/llcrashlogger.h b/indra/llcrashlogger/llcrashlogger.h old mode 100755 new mode 100644 diff --git a/indra/llmessage/llsdmessagebuilder.cpp b/indra/llmessage/llsdmessagebuilder.cpp old mode 100755 new mode 100644 diff --git a/indra/llmessage/llsdmessagebuilder.h b/indra/llmessage/llsdmessagebuilder.h old mode 100755 new mode 100644 diff --git a/indra/llmessage/llsdmessagereader.cpp b/indra/llmessage/llsdmessagereader.cpp old mode 100755 new mode 100644 diff --git a/indra/llmessage/llsdmessagereader.h b/indra/llmessage/llsdmessagereader.h old mode 100755 new mode 100644 diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp old mode 100755 new mode 100644 diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h old mode 100755 new mode 100644 diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h old mode 100755 new mode 100644 diff --git a/indra/llplugin/llplugininstance.cpp b/indra/llplugin/llplugininstance.cpp old mode 100755 new mode 100644 diff --git a/indra/llplugin/llplugininstance.h b/indra/llplugin/llplugininstance.h old mode 100755 new mode 100644 diff --git a/indra/llplugin/llpluginmessage.cpp b/indra/llplugin/llpluginmessage.cpp old mode 100755 new mode 100644 diff --git a/indra/llplugin/llpluginmessage.h b/indra/llplugin/llpluginmessage.h old mode 100755 new mode 100644 diff --git a/indra/llplugin/llpluginmessageclasses.h b/indra/llplugin/llpluginmessageclasses.h old mode 100755 new mode 100644 diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp old mode 100755 new mode 100644 diff --git a/indra/llplugin/llpluginmessagepipe.h b/indra/llplugin/llpluginmessagepipe.h old mode 100755 new mode 100644 diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp old mode 100755 new mode 100644 diff --git a/indra/llplugin/llpluginprocesschild.h b/indra/llplugin/llpluginprocesschild.h old mode 100755 new mode 100644 diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp old mode 100755 new mode 100644 diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h old mode 100755 new mode 100644 diff --git a/indra/llplugin/llpluginsharedmemory.cpp b/indra/llplugin/llpluginsharedmemory.cpp old mode 100755 new mode 100644 diff --git a/indra/llplugin/llpluginsharedmemory.h b/indra/llplugin/llpluginsharedmemory.h old mode 100755 new mode 100644 diff --git a/indra/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp old mode 100755 new mode 100644 diff --git a/indra/llui/llmemberlistener.h b/indra/llui/llmemberlistener.h old mode 100755 new mode 100644 diff --git a/indra/llui/lluistring.cpp b/indra/llui/lluistring.cpp old mode 100755 new mode 100644 diff --git a/indra/llui/lluistring.h b/indra/llui/lluistring.h old mode 100755 new mode 100644 diff --git a/indra/llvfs/llpidlock.cpp b/indra/llvfs/llpidlock.cpp old mode 100755 new mode 100644 diff --git a/indra/llvfs/llpidlock.h b/indra/llvfs/llpidlock.h old mode 100755 new mode 100644 diff --git a/indra/llwindow/glh/glh_linear.h b/indra/llwindow/glh/glh_linear.h old mode 100755 new mode 100644 diff --git a/indra/media_plugins/CMakeLists.txt b/indra/media_plugins/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/indra/media_plugins/base/media_plugin_base.cpp b/indra/media_plugins/base/media_plugin_base.cpp old mode 100755 new mode 100644 diff --git a/indra/media_plugins/base/media_plugin_base.h b/indra/media_plugins/base/media_plugin_base.h old mode 100755 new mode 100644 diff --git a/indra/media_plugins/example/media_plugin_example.cpp b/indra/media_plugins/example/media_plugin_example.cpp old mode 100755 new mode 100644 diff --git a/indra/media_plugins/quicktime/CMakeLists.txt b/indra/media_plugins/quicktime/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp old mode 100755 new mode 100644 diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/media_plugins/webkit/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/indra/media_plugins/webkit/dummy_volume_catcher.cpp b/indra/media_plugins/webkit/dummy_volume_catcher.cpp old mode 100755 new mode 100644 diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp old mode 100755 new mode 100644 diff --git a/indra/media_plugins/webkit/linux_volume_catcher_pa_syms.inc b/indra/media_plugins/webkit/linux_volume_catcher_pa_syms.inc old mode 100755 new mode 100644 diff --git a/indra/media_plugins/webkit/linux_volume_catcher_paglib_syms.inc b/indra/media_plugins/webkit/linux_volume_catcher_paglib_syms.inc old mode 100755 new mode 100644 diff --git a/indra/media_plugins/webkit/mac_volume_catcher.cpp b/indra/media_plugins/webkit/mac_volume_catcher.cpp old mode 100755 new mode 100644 diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp old mode 100755 new mode 100644 diff --git a/indra/media_plugins/webkit/volume_catcher.h b/indra/media_plugins/webkit/volume_catcher.h old mode 100755 new mode 100644 diff --git a/indra/media_plugins/webkit/windows_volume_catcher.cpp b/indra/media_plugins/webkit/windows_volume_catcher.cpp old mode 100755 new mode 100644 diff --git a/indra/newview/hippofloaterxml.cpp b/indra/newview/hippofloaterxml.cpp old mode 100755 new mode 100644 diff --git a/indra/newview/hippofloaterxml.h b/indra/newview/hippofloaterxml.h old mode 100755 new mode 100644 diff --git a/indra/newview/llfloatersellland.cpp b/indra/newview/llfloatersellland.cpp old mode 100755 new mode 100644 diff --git a/indra/newview/llfloatersellland.h b/indra/newview/llfloatersellland.h old mode 100755 new mode 100644 diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h old mode 100755 new mode 100644 diff --git a/indra/newview/lltoolpipette.cpp b/indra/newview/lltoolpipette.cpp old mode 100755 new mode 100644 diff --git a/indra/newview/lltoolpipette.h b/indra/newview/lltoolpipette.h old mode 100755 new mode 100644 diff --git a/indra/newview/llviewerobjectbackup.cpp b/indra/newview/llviewerobjectbackup.cpp old mode 100755 new mode 100644 diff --git a/indra/newview/llviewerobjectbackup.h b/indra/newview/llviewerobjectbackup.h old mode 100755 new mode 100644 diff --git a/indra/test/llrandom_tut.cpp b/indra/test/llrandom_tut.cpp old mode 100755 new mode 100644 diff --git a/indra/test/llsdmessagebuilder_tut.cpp b/indra/test/llsdmessagebuilder_tut.cpp old mode 100755 new mode 100644 diff --git a/indra/test/llsdmessagereader_tut.cpp b/indra/test/llsdmessagereader_tut.cpp old mode 100755 new mode 100644 diff --git a/indra/test_apps/llplugintest/CMakeLists.txt b/indra/test_apps/llplugintest/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/indra/test_apps/llplugintest/bookmarks.txt b/indra/test_apps/llplugintest/bookmarks.txt old mode 100755 new mode 100644 diff --git a/indra/test_apps/llplugintest/demo_media_plugin.cpp b/indra/test_apps/llplugintest/demo_media_plugin.cpp old mode 100755 new mode 100644 diff --git a/indra/test_apps/llplugintest/demo_media_plugin_2.cpp b/indra/test_apps/llplugintest/demo_media_plugin_2.cpp old mode 100755 new mode 100644 diff --git a/indra/test_apps/llplugintest/demo_plugin.cpp b/indra/test_apps/llplugintest/demo_plugin.cpp old mode 100755 new mode 100644 diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp old mode 100755 new mode 100644 diff --git a/indra/test_apps/llplugintest/llmediaplugintest.h b/indra/test_apps/llplugintest/llmediaplugintest.h old mode 100755 new mode 100644 diff --git a/indra/test_apps/llplugintest/media_mappings.txt b/indra/test_apps/llplugintest/media_mappings.txt old mode 100755 new mode 100644 diff --git a/indra/test_apps/llplugintest/media_plugin_test.cpp b/indra/test_apps/llplugintest/media_plugin_test.cpp old mode 100755 new mode 100644 diff --git a/indra/test_apps/llplugintest/media_simple_test.cpp b/indra/test_apps/llplugintest/media_simple_test.cpp old mode 100755 new mode 100644 diff --git a/indra/test_apps/llplugintest/plugin_host.cpp b/indra/test_apps/llplugintest/plugin_host.cpp old mode 100755 new mode 100644 diff --git a/indra/test_apps/llplugintest/plugin_process_launcher.cpp b/indra/test_apps/llplugintest/plugin_process_launcher.cpp old mode 100755 new mode 100644 From ccaa494e853704ca221f2faa6060e4916bb69d3d Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 4 May 2011 15:52:25 +0200 Subject: [PATCH 10/16] Updated doc/contributions.txt and added various missing patches from imprudence. This updates the source tree with patches that I committed to imprudence up till and including 2010-10-19. --- doc/contributions.txt | 47 +++++++++---- indra/cmake/CMakeLists.txt | 1 - indra/cmake/FindMyZLIB.cmake | 46 ------------- indra/cmake/UI.cmake | 1 + indra/cmake/ZLIB.cmake | 2 +- indra/newview/llappviewer.cpp | 10 --- indra/newview/llfloaterabout.cpp | 2 +- indra/newview/llselectmgr.h | 2 +- indra/newview/viewer_manifest.py | 17 ----- install.xml | 114 ------------------------------- 10 files changed, 36 insertions(+), 206 deletions(-) delete mode 100644 indra/cmake/FindMyZLIB.cmake diff --git a/doc/contributions.txt b/doc/contributions.txt index 6c39a77dd..b13dba64c 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -4,6 +4,10 @@ along with the issue identifier corresponding to the patches we've received from them. To see more about these contributions, visit the browsable version: http://wiki.secondlife.com/wiki/Source_contributions +Entries are related to URLs as follows: +IMP-xxx: http://redmine.kokuaviewer.org/issues/xxx +Everything else ([VWR|SNOW|CT|SVC|WEB]-xxx): https://jira.secondlife.com/browse/KEY-xxx + Able Whitman VWR-650 VWR-1460 @@ -60,7 +64,9 @@ Alejandro Rosenthal Aleric Inglewood VWR-10759 VWR-10837 + VWR-12838 (IMP-552) VWR-12984 + VWR-13040 (IMP-575) VWR-13996 VWR-14426 VWR-14914 @@ -72,18 +78,28 @@ 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-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 Alissa Sabre VWR-81 VWR-83 @@ -105,7 +121,7 @@ Alissa Sabre VWR-1351 VWR-1353 VWR-1410 - VWR-1843 + VWR-1843 VWR-2116 VWR-2826 VWR-3290 @@ -113,17 +129,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 +197,7 @@ Boroondas Gupte SNOW-201 SNOW-396 SNOW-589 + SNOW-623 (IMP-554) SNOW-624 VWR-233 WEB-262 @@ -549,7 +566,7 @@ Pf Shan CT-321 princess niven VWR-5733 - CT-85 + CT-85 CT-320 CT-352 Renault Clio @@ -590,6 +607,7 @@ Robin Cornelius VWR-11128 VWR-12758 VWR-12686 + VWR-12838 Ryozu Kojima VWR-53 VWR-287 @@ -788,4 +806,3 @@ Zi Ree Zipherius Turas VWR-76 VWR-77 - diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 6b9e342f4..b7ec75f54 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -35,7 +35,6 @@ set(cmake_SOURCE_FILES FindNDOF.cmake FindOpenJPEG.cmake FindXmlRpcEpi.cmake - FindMyZLIB.cmake FMOD.cmake FreeType.cmake GStreamer010Plugin.cmake diff --git a/indra/cmake/FindMyZLIB.cmake b/indra/cmake/FindMyZLIB.cmake deleted file mode 100644 index 6d630f1ba..000000000 --- a/indra/cmake/FindMyZLIB.cmake +++ /dev/null @@ -1,46 +0,0 @@ -# -*- cmake -*- - -# - Find zlib -# Find the ZLIB includes and library -# This module defines -# ZLIB_INCLUDE_DIRS, where to find zlib.h, etc. -# ZLIB_LIBRARIES, the libraries needed to use zlib. -# ZLIB_FOUND, If false, do not try to use zlib. -# -# This FindZLIB is about 43 times as fast the one provided with cmake (2.8.x), -# because it doesn't look up the version of zlib, resulting in a dramatic -# speed up for configure (from 4 minutes 22 seconds to 6 seconds). -# -# Note: Since this file is only used for standalone, the windows -# specific parts were left out. - -FIND_PATH(ZLIB_INCLUDE_DIR zlib.h - NO_SYSTEM_ENVIRONMENT_PATH - ) - -FIND_LIBRARY(ZLIB_LIBRARY z) - -if (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR) - SET(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR}) - SET(ZLIB_LIBRARIES ${ZLIB_LIBRARY}) - SET(ZLIB_FOUND "YES") -else (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR) - SET(ZLIB_FOUND "NO") -endif (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR) - -if (ZLIB_FOUND) - if (NOT ZLIB_FIND_QUIETLY) - message(STATUS "Found ZLIB: ${ZLIB_LIBRARIES}") - SET(ZLIB_FIND_QUIETLY TRUE) - endif (NOT ZLIB_FIND_QUIETLY) -else (ZLIB_FOUND) - if (ZLIB_FIND_REQUIRED) - message(FATAL_ERROR "Could not find ZLIB library") - endif (ZLIB_FIND_REQUIRED) -endif (ZLIB_FOUND) - -mark_as_advanced( - ZLIB_LIBRARY - ZLIB_INCLUDE_DIR - ) - diff --git a/indra/cmake/UI.cmake b/indra/cmake/UI.cmake index 6067602d5..64fa85ff2 100644 --- a/indra/cmake/UI.cmake +++ b/indra/cmake/UI.cmake @@ -42,6 +42,7 @@ else (STANDALONE) gdk_pixbuf-2.0 Xinerama glib-2.0 + gio-2.0 gmodule-2.0 gobject-2.0 gthread-2.0 diff --git a/indra/cmake/ZLIB.cmake b/indra/cmake/ZLIB.cmake index c233b3eec..48e5130ad 100644 --- a/indra/cmake/ZLIB.cmake +++ b/indra/cmake/ZLIB.cmake @@ -6,7 +6,7 @@ set(ZLIB_FIND_REQUIRED ON) include(Prebuilt) if (STANDALONE) - include(FindMyZLIB) + include(FindZLIB) else (STANDALONE) use_prebuilt_binary(zlib) if (WINDOWS) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 38ae9202e..10f52bf45 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1120,16 +1120,6 @@ bool LLAppViewer::mainLoop() bool LLAppViewer::cleanup() { - //---------------------------------------------- - //this test code will be removed after the test - //test manual call stack tracer - if(gSavedSettings.getBOOL("QAMode")) - { - LLError::LLCallStacks::print() ; - } - //end of the test code - //---------------------------------------------- - //flag all elements as needing to be destroyed immediately // to ensure shutdown order LLMortician::setZealous(TRUE); diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 043de9c23..ed4e378e3 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -275,7 +275,7 @@ LLFloaterAbout::LLFloaterAbout() // TODO: Implement media plugin version query - support.append("Qt Webkit Version: 4.7.1 "); + support.append("Qt Webkit Version: 4.7.1 (version number hard-coded)"); support.append("\n"); if (gPacketsIn > 0) diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 52d3f0b03..1ebe341bf 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -252,7 +252,7 @@ public: return (object != NULL) && node->mValid && !node->mIndividualSelection && (object->isRootEdit() || object->isJointChild()); } }; - typedef boost::filter_iterator valid_root_iterator; + typedef boost::filter_iterator valid_root_iterator; valid_root_iterator valid_root_begin() { return valid_root_iterator(mList.begin(), mList.end()); } valid_root_iterator valid_root_end() { return valid_root_iterator(mList.end(), mList.end()); } diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 02eca9bff..03f8c71ac 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -827,25 +827,8 @@ class Linux_x86_64Manifest(LinuxManifest): self.path("libopenal.so.1") self.path("libalut.so.0") - # GTK+ and dependencies - ## Lets just use the system libraries for all of these: - ##self.path("libatk-1.0.so.0") - ##self.path("libcairo.so.2") - ##self.path("libfontconfig.so.1") - ##self.path("libfreetype.so.6") - self.path("libgdk_pixbuf-2.0.so.0") # was commented to use systems gdk pixbufs instead - - # but seems webkit needs it o_O . Packaging for testing now. - ##self.path("libgdk-x11-2.0.so.0") - ##self.path("libgtk-x11-2.0.so.0") -# self.path("libpango-1.0.so.0") # use systems pango instead -# self.path("libpangoft2-1.0.so.0") # Both gdk pixbufs and pango would load systems modules -# self.path("libpangox-1.0.so.0") # and crash if not compatible or present. -# self.path("libpangoxft-1.0.so.0") # So we depend system gdk pixbufs and pango anyway. - ##self.path("libpixman-1.so.0") - self.end_prefix("lib64") - # Vivox runtimes and libs if self.prefix(src="vivox-runtime/i686-linux", dst="bin"): self.path("SLVoice") diff --git a/install.xml b/install.xml index 2b31c307a..fc920198b 100644 --- a/install.xml +++ b/install.xml @@ -374,39 +374,6 @@ - fmod - - copyright - FMOD Sound System, copyright (C) Firelight Technologies Pty, Ltd., 1994-2006. - description - Audio engine and mp3 stream decoder . - license - fmod - packages - - darwin - - md5sum - c7e317bec481b7efa2a0319e163dcc65 - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/fmod-3.75-darwin-20080818.tar.bz2 - - linux - - md5sum - abd2b4ba4ac993f19d82804af387eb7c - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/fmod-3.75-linux-20080818.tar.bz2 - - windows - - md5sum - 1a55dec2907821f5f785648a660126c3 - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/fmod-3.75-windows-20080611.tar.bz2 - - - fontconfig license @@ -1015,35 +982,6 @@ anguage Infrstructure (CLI) international standard - mysql - - license - gpl - packages - - darwin - - md5sum - df27f2db244ea2762759a06cd75ada4e - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/mysql-darwin-20080812.tar.bz2 - - linux - - md5sum - cc86b4cc858655e23704d1168325d7b9 - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/mysqlclient-linux-20090320.tar.bz2 - - windows - - md5sum - 98bac06680dca907e783d8dd4aa9edde - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/mysql-windows-20080804.tar.bz2 - - - ndofdev copyright @@ -1219,58 +1157,6 @@ anguage Infrstructure (CLI) international standard - quicktime - - copyright - Copyright (C) 1990-2007 by Apple Computer, Inc., all rights reserved. - description - Separate download. Used to play in-world video clips on a prim. - license - quicktime - packages - - windows - - md5sum - be45825cc14ede53790ac93c58307dcb - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/quicktime-sdk-windows-7.3-20091110.tar.bz2 - - - - smartheap - - copyright - Copyright (C) 1991-2000 Compuware Corporation. All Rights Reserved. - description - Memory Management Library - license - smartheap - packages - - darwin - - md5sum - f54131b5f228e805c64c2e4e6c96579a - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/smartheap-6.0.2-darwin-20080610.tar.bz2 - - linux - - md5sum - 499208522bf7d7843e1d014d64214e06 - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/smartheap-6.0.2-linux-20080610.tar.bz2 - - windows - - md5sum - 78fd47017f21d11eae43bca3e38a3e1e - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/smartheap-6.0.2-windows-20080611.tar.bz2 - - - tut copyright From ab5915c16cdef65f170edb855094ef1ccbd4832e Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 4 May 2011 17:54:57 +0200 Subject: [PATCH 11/16] LindenUserDir fixes. Patch from 2010-10-20/22. Didn't apply cleanly so I redid it manually and tested/checked it. There was only one difference with imprudence: for some reason Singularity tries to see if the "teleport history" floater is visible while initializing the menu's, something that imprudence doesn't do. For the rest the patch is basically the same. Nevertheless, I left all code exactly as it was in Singularity (the only thing that this commit changes is the intend of the original patch: in debug mode, fail with an assertion when LindenUserDir is called while it is not initialized; and then fix everything to make it work again. Original commit message: The LindenUserDir (~/.imprudence/first_last/) cannot be initialized before the user logged in. However, several singletons (that only can be initialized once) depend on this directory for initialization. Therefore we have to take care not to instantiate those singletons until after the user logged in. With regard to webit, this fixes the browser_profile (cache and cookies) directory that the builtin browser uses. --- indra/llui/lltexteditor.cpp | 11 +++- indra/llvfs/lldir.cpp | 3 +- indra/llvfs/lldir.h | 2 +- indra/llvfs/lldir_linux.cpp | 2 +- indra/llvfs/lldir_solaris.cpp | 2 +- indra/newview/llappviewer.cpp | 15 +++-- indra/newview/llimview.cpp | 2 +- indra/newview/llmutelist.cpp | 2 +- indra/newview/llstartup.cpp | 4 ++ indra/newview/llurlhistory.cpp | 2 +- indra/newview/llviewermenu.cpp | 2 +- indra/newview/llviewerwindow.cpp | 94 ++++++++++++++++++-------------- indra/newview/llviewerwindow.h | 1 + 13 files changed, 85 insertions(+), 57 deletions(-) diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 3e4860763..3326524cb 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -58,6 +58,7 @@ #include "llimagegl.h" #include "llwindow.h" #include "lltextparser.h" +#include "lldir.h" #include #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(); diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index d495176de..29b50d7bc 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -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; } diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h index 4111f4ffa..a90b8ab24 100644 --- a/indra/llvfs/lldir.h +++ b/indra/llvfs/lldir.h @@ -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 diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp index 6a5834fec..ce6b1885f 100644 --- a/indra/llvfs/lldir_linux.cpp +++ b/indra/llvfs/lldir_linux.cpp @@ -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 */ diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp index a39e13fcf..2ebd6e471 100644 --- a/indra/llvfs/lldir_solaris.cpp +++ b/indra/llvfs/lldir_solaris.cpp @@ -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 */ diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 10f52bf45..bd1521ba3 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3202,12 +3202,15 @@ void LLAppViewer::saveFinalSnapshot() gSavedSettings.setBOOL("ShowParcelOwners", FALSE); idle(); - std::string snap_filename = gDirUtilp->getLindenUserDir(); - snap_filename += gDirUtilp->getDirDelimiter(); - snap_filename += SCREEN_LAST_FILENAME; - // use full pixel dimensions of viewer window (not post-scale dimensions) - gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight(), FALSE, TRUE); - mSavedFinalSnapshot = TRUE; + std::string snap_filename = gDirUtilp->getLindenUserDir(true); + if (!snap_filename.empty()) + { + snap_filename += gDirUtilp->getDirDelimiter(); + snap_filename += SCREEN_LAST_FILENAME; + // use full pixel dimensions of viewer window (not post-scale dimensions) + gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight(), FALSE, TRUE); + mSavedFinalSnapshot = TRUE; + } } } diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index d96aa3bbc..31743deb3 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -1347,7 +1347,7 @@ void LLIMMgr::saveIgnoreGroup() { // llinfos << "saving ignore_groups.xml" << llendl; - std::string user_dir = gDirUtilp->getLindenUserDir(); + std::string user_dir = gDirUtilp->getLindenUserDir(true); if (!user_dir.empty()) { std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "ignore_groups.xml"); diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index 40b1c6414..dca58d5f4 100644 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -264,7 +264,7 @@ LLMuteList::~LLMuteList() // If we quit from the login screen we will not have an SL account // name. Don't try to save, otherwise we'll dump a file in // C:\Program Files\SecondLife\ JC - std::string user_dir = gDirUtilp->getLindenUserDir(); + std::string user_dir = gDirUtilp->getLindenUserDir(true); if (!user_dir.empty()) { std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "volume_settings.xml"); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index dd42f2eeb..519ce8d87 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1890,6 +1890,10 @@ bool idle_startup() gLLWindEnabled = gSavedSettings.getBOOL("WindEnabled"); set_startup_status(0.40f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD); + + // Initialize the rest of the world. + gViewerWindow->initWorldUI_postLogin(); + display_startup(); // We should have an agent id by this point. llassert(!(gAgentID == LLUUID::null)); diff --git a/indra/newview/llurlhistory.cpp b/indra/newview/llurlhistory.cpp index 6930d8ac2..a93cc2ff7 100644 --- a/indra/newview/llurlhistory.cpp +++ b/indra/newview/llurlhistory.cpp @@ -74,7 +74,7 @@ bool LLURLHistory::loadFile(const std::string& filename) // static bool LLURLHistory::saveFile(const std::string& filename) { - std::string temp_str = gDirUtilp->getLindenUserDir(); + std::string temp_str = gDirUtilp->getLindenUserDir(true); if( temp_str.empty() ) { llwarns << "Can't save. No user directory set." << llendl; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index b75c3345e..873e6d1ae 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -6643,7 +6643,7 @@ class LLFloaterVisible : public view_listener_t } else if (floater_name == "teleport history") { - new_value = gFloaterTeleportHistory->getVisible(); + new_value = (gFloaterTeleportHistory && gFloaterTeleportHistory->getVisible()); } else if (floater_name == "im") { diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index bcd34fd7d..a82fdb3d5 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1912,7 +1912,8 @@ void LLViewerWindow::initWorldUI() S32 width = mRootView->getRect().getWidth(); LLRect full_window(0, height, width, 0); - if ( gBottomPanel == NULL ) // Don't re-enter if objects are alreay created + // Don't re-enter if objects are alreay created + if (gBottomPanel == NULL) { // panel containing chatbar, toolbar, and overlay, over floaters gBottomPanel = new LLBottomPanel(mRootView->getRect()); @@ -1925,6 +1926,57 @@ void LLViewerWindow::initWorldUI() gIMMgr = LLIMMgr::getInstance(); + // + // Tools for building + // + + init_menus(); + + // Toolbox floater + gFloaterTools = new LLFloaterTools(); + gFloaterTools->setVisible(FALSE); + } + + if ( gHUDView == NULL ) + { + LLRect hud_rect = full_window; + hud_rect.mBottom += 50; + if (gMenuBarView) + { + hud_rect.mTop -= gMenuBarView->getRect().getHeight(); + } + gHUDView = new LLHUDView(hud_rect); + // put behind everything else in the UI + mRootView->addChildAtEnd(gHUDView); + } +} + +// initWorldUI that wasn't before logging in. Some of this may require the access the 'LindenUserDir'. +void LLViewerWindow::initWorldUI_postLogin() +{ + S32 height = mRootView->getRect().getHeight(); + S32 width = mRootView->getRect().getWidth(); + LLRect full_window(0, height, width, 0); + + // Don't re-enter if objects are alreay created. + if (!gStatusBar) + { + // Status bar + S32 menu_bar_height = gMenuBarView->getRect().getHeight(); + LLRect root_rect = getRootView()->getRect(); + LLRect status_rect(0, root_rect.getHeight(), root_rect.getWidth(), root_rect.getHeight() - menu_bar_height); + gStatusBar = new LLStatusBar(std::string("status"), status_rect); + gStatusBar->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP); + + gStatusBar->reshape(root_rect.getWidth(), gStatusBar->getRect().getHeight(), TRUE); + gStatusBar->translate(0, root_rect.getHeight() - gStatusBar->getRect().getHeight()); + // sync bg color with menu bar + gStatusBar->setBackgroundColor( gMenuBarView->getBackgroundColor() ); + getRootView()->addChild(gStatusBar); + + // Menu holder appears on top to get first pass at all mouse events + getRootView()->sendChildToFront(gMenuHolder); + if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) { LLFloaterChat::getInstance(LLSD())->loadHistory(); @@ -1950,47 +2002,7 @@ void LLViewerWindow::initWorldUI() gFloaterTeleportHistory = new LLFloaterTeleportHistory(); gFloaterTeleportHistory->setVisible(FALSE); - // - // Tools for building - // - - // Toolbox floater - init_menus(); - - gFloaterTools = new LLFloaterTools(); - gFloaterTools->setVisible(FALSE); - - // Status bar - S32 menu_bar_height = gMenuBarView->getRect().getHeight(); - LLRect root_rect = getRootView()->getRect(); - LLRect status_rect(0, root_rect.getHeight(), root_rect.getWidth(), root_rect.getHeight() - menu_bar_height); - gStatusBar = new LLStatusBar(std::string("status"), status_rect); - gStatusBar->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP); - - gStatusBar->reshape(root_rect.getWidth(), gStatusBar->getRect().getHeight(), TRUE); - gStatusBar->translate(0, root_rect.getHeight() - gStatusBar->getRect().getHeight()); - // sync bg color with menu bar - gStatusBar->setBackgroundColor( gMenuBarView->getBackgroundColor() ); - LLFloaterChatterBox::createInstance(LLSD()); - - getRootView()->addChild(gStatusBar); - - // menu holder appears on top to get first pass at all mouse events - getRootView()->sendChildToFront(gMenuHolder); - } - - if ( gHUDView == NULL ) - { - LLRect hud_rect = full_window; - hud_rect.mBottom += 50; - if (gMenuBarView) - { - hud_rect.mTop -= gMenuBarView->getRect().getHeight(); - } - gHUDView = new LLHUDView(hud_rect); - // put behind everything else in the UI - mRootView->addChildAtEnd(gHUDView); } } diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 538a6f188..21867f7eb 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -144,6 +144,7 @@ public: void adjustRectanglesForFirstUse(const LLRect& window); void adjustControlRectanglesForFirstUse(const LLRect& window); void initWorldUI(); + void initWorldUI_postLogin(); // // LLWindowCallback interface implementation From f2199a504b661b4b09572c2da5ba83c58694d7ac Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 4 May 2011 19:48:16 +0200 Subject: [PATCH 12/16] More various small, old patches. Updated source tree to include everything I did up till 2010-11-09. Still to add: IMP-590, IMP-701, IMP-734, IMP-735 and IMP-702. --- doc/contributions.txt | 8 +++++++- indra/cmake/LLCommon.cmake | 9 +-------- indra/llcommon/llstring.h | 4 ++-- indra/llui/llnotifications.cpp | 4 ++-- indra/llvfs/llvfs.cpp | 5 +++-- indra/newview/llfeaturemanager.cpp | 11 +--------- indra/newview/llnamelistctrl.cpp | 2 +- indra/newview/llnamelistctrl.h | 2 +- indra/newview/lltexturecache.cpp | 2 +- .../skins/default/textures/textures.xml | 1 + install.xml | 20 +++---------------- 11 files changed, 23 insertions(+), 45 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index b13dba64c..d957cc782 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -84,7 +84,7 @@ Aleric Inglewood SNOW-477 (IMP-577) SNOW-479 SNOW-626 - SNOW-713 + SNOW-713 (IMP-692) SNOW-744 (IMP-578) SNOW-752 SNOW-753 @@ -100,6 +100,12 @@ Aleric Inglewood IMP-566 IMP-567 IMP-573 + IMP-660 + IMP-661 + IMP-662 + IMP-663 + IMP-664 + IMP-670 Alissa Sabre VWR-81 VWR-83 diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake index d87d3c015..2862ba7f0 100644 --- a/indra/cmake/LLCommon.cmake +++ b/indra/cmake/LLCommon.cmake @@ -11,11 +11,4 @@ set(LLCOMMON_INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ) -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) +set(LLCOMMON_LIBRARIES llcommon) diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 4343a6385..171747921 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -213,7 +213,7 @@ public: ///////////////////////////////////////////////////////////////////////////////////////// // Static Utility functions that operate on std::strings - static std::basic_string null; + static std::basic_string const null; typedef std::map format_map_t; static S32 format(std::basic_string& s, const format_map_t& fmt_map); @@ -304,7 +304,7 @@ public: }; -template std::basic_string LLStringUtilBase::null; +template std::basic_string const LLStringUtilBase::null; typedef LLStringUtilBase LLStringUtil; typedef LLStringUtilBase LLWStringUtil; diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 7748df84f..6bd4e4f22 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -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; } } } diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp index 18c3951fd..b90d4b3c8 100644 --- a/indra/llvfs/llvfs.cpp +++ b/indra/llvfs/llvfs.cpp @@ -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; } diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index b3cff3315..9614f639d 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -252,12 +252,10 @@ BOOL LLFeatureManager::loadFeatureTables() mTableVersion = version; LLFeatureList *flp = NULL; - while (!file.eof() && file.good()) + while (file >> name) { char buffer[MAX_STRING]; /*Flawfinder: ignore*/ - file >> name; - if (name.substr(0,2) == "//") { // This is a comment. @@ -265,13 +263,6 @@ BOOL LLFeatureManager::loadFeatureTables() continue; } - if (name.empty()) - { - // This is a blank line - file.getline(buffer, MAX_STRING); - continue; - } - if (name == "list") { if (flp) diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index 453cf7fab..364fb1c44 100644 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -72,7 +72,7 @@ LLNameListCtrl::~LLNameListCtrl() // public BOOL LLNameListCtrl::addNameItem(const LLUUID& agent_id, EAddPosition pos, - BOOL enabled, std::string& suffix) + BOOL enabled, std::string const& suffix) { //llinfos << "LLNameListCtrl::addNameItem " << agent_id << llendl; diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h index 1b7795ddf..4485faedf 100644 --- a/indra/newview/llnamelistctrl.h +++ b/indra/newview/llnamelistctrl.h @@ -58,7 +58,7 @@ public: // Add a user to the list by name. It will be added, the name // requested from the cache, and updated as necessary. BOOL addNameItem(const LLUUID& agent_id, EAddPosition pos = ADD_BOTTOM, - BOOL enabled = TRUE, std::string& suffix = LLStringUtil::null); + BOOL enabled = TRUE, std::string const& suffix = LLStringUtil::null); BOOL addNameItem(LLScrollListItem* item, EAddPosition pos = ADD_BOTTOM); virtual LLScrollListItem* addElement(const LLSD& value, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL); diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 5c27e365a..5e08d7608 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -1426,7 +1426,7 @@ void LLTextureCache::readHeaderCache() { // Special case: cache size was reduced, need to remove entries // Note: After we prune entries, we will call this again and create the LRU - U32 entries_to_purge = (num_entries-empty_entries) - sCacheMaxEntries; + U32 entries_to_purge = (num_entries - empty_entries) - sCacheMaxEntries; llinfos << "Texture Cache Entries: " << num_entries << " Max: " << sCacheMaxEntries << " Empty: " << empty_entries << " Purging: " << entries_to_purge << llendl; // We can exit the following loop with the given condition, since if we'd reach the end of the lru set we'd have: // purge_list.size() = lru.size() = num_entries - empty_entries = entries_to_purge + sCacheMaxEntries >= entries_to_purge diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 0f5cc88ad..3f93a7ef8 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -389,5 +389,6 @@ + diff --git a/install.xml b/install.xml index fc920198b..fe1320c33 100644 --- a/install.xml +++ b/install.xml @@ -162,26 +162,12 @@ artwork packages - darwin + common md5sum - 5e047437d73d1017bf270a6c6e936f23 + a2cde4f24bdcc260b661e139846b8acd url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/artwork-common-20090415.tar.bz2 - - linux - - md5sum - 5e047437d73d1017bf270a6c6e936f23 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/artwork-common-20090415.tar.bz2 - - windows - - md5sum - 5e047437d73d1017bf270a6c6e936f23 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/artwork-common-20090415.tar.bz2 + http://imprudenceviewer.org/download/libs/imprudence-artwork-20101026.tar.bz2 From 5b085600478ca2779cc6ae42d154df13301500bd Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 4 May 2011 22:23:49 +0200 Subject: [PATCH 13/16] Update of doc/contributions.txt with patches from snowstorm already in Singularity. --- doc/contributions.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index d957cc782..bad74fb03 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -62,14 +62,18 @@ Aimee Trescothick Alejandro Rosenthal VWR-1184 Aleric Inglewood + VWR-10579 (IMP-552) VWR-10759 VWR-10837 - VWR-12838 (IMP-552) 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 From 4d932d5e2ded747fcfa16fc0aabb546bbbe688dd Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 5 May 2011 01:34:00 +0200 Subject: [PATCH 14/16] Added a thread-safe and robust wrapper for APR pools. See http://redmine.imprudenceviewer.org/issues/590 and https://jira.secondlife.com/browse/SNOW-596 --- doc/contributions.txt | 1 + indra/llcommon/CMakeLists.txt | 3 + indra/llcommon/aiaprpool.cpp | 198 ++++++++++++ indra/llcommon/aiaprpool.h | 238 ++++++++++++++ indra/llcommon/llapp.cpp | 5 - indra/llcommon/llapr.cpp | 298 +++--------------- indra/llcommon/llapr.h | 74 +---- indra/llcommon/llcommon.cpp | 13 - indra/llcommon/llcommon.h | 2 - indra/llcommon/llerror.cpp | 3 + indra/llcommon/llfixedbuffer.cpp | 3 +- indra/llcommon/llscopedvolatileaprpool.h | 58 ++++ indra/llcommon/llthread.cpp | 135 ++++---- indra/llcommon/llthread.h | 92 +++++- indra/llcommon/llworkerthread.cpp | 3 +- indra/llcommon/llworkerthread.h | 2 +- indra/llcrashlogger/llcrashlogger.cpp | 3 +- indra/llimage/llimage.cpp | 2 +- indra/llimage/llimagej2c.cpp | 15 +- indra/llimage/llimageworker.cpp | 13 +- indra/llimage/llimageworker.h | 4 +- indra/llmath/llvolumemgr.cpp | 4 +- indra/llmessage/llares.cpp | 17 +- indra/llmessage/llcurl.cpp | 2 +- indra/llmessage/lliohttpserver.cpp | 10 +- indra/llmessage/lliohttpserver.h | 2 +- indra/llmessage/lliosocket.cpp | 99 +++--- indra/llmessage/lliosocket.h | 33 +- indra/llmessage/llmail.cpp | 17 +- indra/llmessage/llmail.h | 4 +- indra/llmessage/llpumpio.cpp | 74 ++--- indra/llmessage/llpumpio.h | 31 +- indra/llmessage/llurlrequest.cpp | 25 +- indra/llmessage/message.cpp | 19 +- indra/llplugin/llplugininstance.cpp | 5 +- indra/llplugin/llpluginmessagepipe.cpp | 2 - indra/llplugin/llpluginprocesschild.cpp | 2 +- indra/llplugin/llpluginprocessparent.cpp | 55 ++-- indra/llplugin/llpluginprocessparent.h | 2 + indra/llplugin/llpluginsharedmemory.cpp | 9 +- indra/llplugin/llpluginsharedmemory.h | 3 + indra/llplugin/slplugin/slplugin.cpp | 4 - indra/llvfs/llvfs.cpp | 2 +- .../webkit/linux_volume_catcher.cpp | 14 +- indra/newview/llappviewer.cpp | 2 +- indra/newview/llappviewerlinux.cpp | 1 + indra/newview/llappviewermacosx.cpp | 1 + indra/newview/llconsole.cpp | 3 +- indra/newview/lltexturecache.cpp | 3 - indra/newview/lltexturecache.h | 3 - indra/newview/lltexturefetch.cpp | 5 +- indra/newview/llviewerprecompiledheaders.h | 2 +- indra/newview/llvoiceclient.cpp | 2 +- indra/newview/llwatchdog.cpp | 4 +- indra/test/lltemplatemessagebuilder_tut.cpp | 2 - indra/test/message_tut.cpp | 2 - indra/test/test.cpp | 16 +- 57 files changed, 895 insertions(+), 751 deletions(-) create mode 100644 indra/llcommon/aiaprpool.cpp create mode 100644 indra/llcommon/aiaprpool.h create mode 100644 indra/llcommon/llscopedvolatileaprpool.h diff --git a/doc/contributions.txt b/doc/contributions.txt index bad74fb03..849c95de4 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -104,6 +104,7 @@ Aleric Inglewood IMP-566 IMP-567 IMP-573 + IMP-590 IMP-660 IMP-661 IMP-662 diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 4bcfce5b0..cc6bffe3f 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -13,6 +13,7 @@ include_directories( ) set(llcommon_SOURCE_FILES + aiaprpool.cpp imageids.cpp indra_constants.cpp llapp.cpp @@ -78,6 +79,7 @@ set(llcommon_SOURCE_FILES set(llcommon_HEADER_FILES CMakeLists.txt + aiaprpool.h bitpack.h ctype_workaround.h doublelinkedlist.h @@ -155,6 +157,7 @@ set(llcommon_HEADER_FILES llqueuedthread.h llrand.h llrun.h + llscopedvolatileaprpool.h llsd.h llsdserialize.h llsdserialize_xml.h diff --git a/indra/llcommon/aiaprpool.cpp b/indra/llcommon/aiaprpool.cpp new file mode 100644 index 000000000..d3748e983 --- /dev/null +++ b/indra/llcommon/aiaprpool.cpp @@ -0,0 +1,198 @@ +/** + * @file aiaprpool.cpp + * + * Copyright (c) 2010, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 04/04/2010 + * - Initial version, written by Aleric Inglewood @ SL + * + * 10/11/2010 + * - Changed filename, class names and license to a more + * company-neutral format. + * - Added APR_HAS_THREADS #if's to allow creation and destruction + * of subpools by threads other than the parent pool owner. + */ + +#include "linden_common.h" + +#include "llerror.h" +#include "aiaprpool.h" +#include "llthread.h" + +// Create a subpool from parent. +void AIAPRPool::create(AIAPRPool& parent) +{ + llassert(!mPool); // Must be non-initialized. + mParent = &parent; + if (!mParent) // Using the default parameter? + { + // By default use the root pool of the current thread. + mParent = &AIThreadLocalData::tldata().mRootPool; + } + llassert(mParent->mPool); // Parent must be initialized. +#if APR_HAS_THREADS + // As per the documentation of APR (ie http://apr.apache.org/docs/apr/1.4/apr__pools_8h.html): + // + // Note that most operations on pools are not thread-safe: a single pool should only be + // accessed by a single thread at any given time. The one exception to this rule is creating + // a subpool of a given pool: one or more threads can safely create subpools at the same + // time that another thread accesses the parent pool. + // + // In other words, it's safe for any thread to create a (sub)pool, independent of who + // owns the parent pool. + mOwner = apr_os_thread_current(); +#else + mOwner = mParent->mOwner; + llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); +#endif + apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, mParent->mPool); + llassert_always(apr_pool_create_status == APR_SUCCESS); + llassert(mPool); // Initialized. + apr_pool_cleanup_register(mPool, this, &s_plain_cleanup, &apr_pool_cleanup_null); +} + +// Destroy the (sub)pool, if any. +void AIAPRPool::destroy(void) +{ + // Only do anything if we are not already (being) destroyed. + if (mPool) + { +#if !APR_HAS_THREADS + // If we are a root pool, then every thread may destruct us: in that case + // we have to assume that no other thread will use this pool concurrently, + // of course. Otherwise, if we are a subpool, only the thread that owns + // the parent may destruct us, since that is the pool that is still alive, + // possibly being used by others and being altered here. + llassert(!mParent || apr_os_thread_equal(mParent->mOwner, apr_os_thread_current())); +#endif + apr_pool_t* pool = mPool; + mPool = NULL; // Mark that we are BEING destructed. + apr_pool_cleanup_kill(pool, this, &s_plain_cleanup); + apr_pool_destroy(pool); + } +} + +bool AIAPRPool::parent_is_being_destructed(void) +{ + return mParent && (!mParent->mPool || mParent->parent_is_being_destructed()); +} + +AIAPRInitialization::AIAPRInitialization(void) +{ + static bool apr_initialized = false; + + if (!apr_initialized) + { + apr_initialize(); + } + + apr_initialized = true; +} + +bool AIAPRRootPool::sCountInitialized = false; +apr_uint32_t volatile AIAPRRootPool::sCount; + +extern apr_thread_mutex_t* gLogMutexp; +extern apr_thread_mutex_t* gCallStacksLogMutexp; + +AIAPRRootPool::AIAPRRootPool(void) : AIAPRInitialization(), AIAPRPool(0) +{ + // sCountInitialized don't need locking because when we get here there is still only a single thread. + if (!sCountInitialized) + { + // Initialize the logging mutex + apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, mPool); + apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, mPool); + + apr_status_t status = apr_atomic_init(mPool); + llassert_always(status == APR_SUCCESS); + apr_atomic_set32(&sCount, 1); // Set to 1 to account for the global root pool. + sCountInitialized = true; + + // Initialize thread-local APR pool support. + // Because this recursively calls AIAPRRootPool::AIAPRRootPool(void) + // it must be done last, so that sCount is already initialized. + AIThreadLocalData::init(); + } + apr_atomic_inc32(&sCount); +} + +AIAPRRootPool::~AIAPRRootPool() +{ + if (!apr_atomic_dec32(&sCount)) + { + // The last pool was destructed. Cleanup remainder of APR. + LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL; + + if (gLogMutexp) + { + // Clean up the logging mutex + + // All other threads NEED to be done before we clean up APR, so this is okay. + apr_thread_mutex_destroy(gLogMutexp); + gLogMutexp = NULL; + } + if (gCallStacksLogMutexp) + { + // Clean up the logging mutex + + // All other threads NEED to be done before we clean up APR, so this is okay. + apr_thread_mutex_destroy(gCallStacksLogMutexp); + gCallStacksLogMutexp = NULL; + } + + // Must destroy ALL, and therefore this last AIAPRRootPool, before terminating APR. + static_cast(this)->destroy(); + + apr_terminate(); + } +} + +//static +AIAPRRootPool& AIAPRRootPool::get(void) +{ + static AIAPRRootPool global_APRpool(0); // This is what used to be gAPRPoolp. + return global_APRpool; +} + +void AIVolatileAPRPool::clearVolatileAPRPool() +{ + llassert_always(mNumActiveRef > 0); + if (--mNumActiveRef == 0) + { + if (isOld()) + { + destroy(); + mNumTotalRef = 0 ; + } + else + { + // This does not actually free the memory, + // it just allows the pool to re-use this memory for the next allocation. + clear(); + } + } + + // Paranoia check if the pool is jammed. + llassert(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ; +} diff --git a/indra/llcommon/aiaprpool.h b/indra/llcommon/aiaprpool.h new file mode 100644 index 000000000..72e9ddbd4 --- /dev/null +++ b/indra/llcommon/aiaprpool.h @@ -0,0 +1,238 @@ +/** + * @file aiaprpool.h + * @brief Implementation of AIAPRPool. + * + * Copyright (c) 2010, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 04/04/2010 + * - Initial version, written by Aleric Inglewood @ SL + * + * 10/11/2010 + * - Changed filename, class names and license to a more + * company-neutral format. + * - Added APR_HAS_THREADS #if's to allow creation and destruction + * of subpools by threads other than the parent pool owner. + */ + +#ifndef AIAPRPOOL_H +#define AIAPRPOOL_H + +#ifdef LL_WINDOWS +#include // Needed before including apr_portable.h +#endif + +#include "apr_portable.h" +#include "apr_pools.h" +#include "llerror.h" + +extern void ll_init_apr(); + +/** + * @brief A wrapper around the APR memory pool API. + * + * Usage of this class should be restricted to passing it to libapr-1 function calls that need it. + * + */ +class LL_COMMON_API AIAPRPool +{ +protected: + apr_pool_t* mPool; //!< Pointer to the underlaying pool. NULL if not initialized. + AIAPRPool* mParent; //!< Pointer to the parent pool, if any. Only valid when mPool is non-zero. + apr_os_thread_t mOwner; //!< The thread that owns this memory pool. Only valid when mPool is non-zero. + +public: + //! Construct an uninitialized (destructed) pool. + AIAPRPool(void) : mPool(NULL) { } + + //! Construct a subpool from an existing pool. + // This is not a copy-constructor, this class doesn't have one! + AIAPRPool(AIAPRPool& parent) : mPool(NULL) { create(parent); } + + //! Destruct the memory pool (free all of it's subpools and allocated memory). + ~AIAPRPool() { destroy(); } + +protected: + // Create a pool that is allocated from the Operating System. Only used by AIAPRRootPool. + AIAPRPool(int) : mPool(NULL), mParent(NULL), mOwner(apr_os_thread_current()) + { + apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, NULL); + llassert_always(apr_pool_create_status == APR_SUCCESS); + llassert(mPool); + apr_pool_cleanup_register(mPool, this, &s_plain_cleanup, &apr_pool_cleanup_null); + } + +public: + //! Create a subpool from parent. May only be called for an uninitialized/destroyed pool. + // The default parameter causes the root pool of the current thread to be used. + void create(AIAPRPool& parent = *static_cast(NULL)); + + //! Destroy the (sub)pool, if any. + void destroy(void); + + // Use some safebool idiom (http://www.artima.com/cppsource/safebool.html) rather than operator bool. + typedef apr_pool_t* const AIAPRPool::* const bool_type; + //! Return true if the pool is initialized. + operator bool_type() const { return mPool ? &AIAPRPool::mPool : 0; } + + // Painful, but we have to either provide access to this, or wrap + // every APR function call that needs a apr_pool_t* to be passed. + // NEVER destroy a pool that is returned by this function! + apr_pool_t* operator()(void) const + { + llassert(mPool); + llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); + return mPool; + } + + // Free all memory without destructing the pool. + void clear(void) + { + llassert(mPool); + llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); + apr_pool_clear(mPool); + } + +// These methods would make this class 'complete' (as wrapper around the libapr +// pool functions), but we don't use memory pools in the viewer (only when +// we are forced to pass one to a libapr call), so don't define them in order +// not to encourage people to use them. +#if 0 + void* palloc(size_t size) + { + llassert(mPool); + llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); + return apr_palloc(mPool, size); + } + void* pcalloc(size_t size) + { + llassert(mPool); + llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); + return apr_pcalloc(mPool, size); + } +#endif + +private: + bool parent_is_being_destructed(void); + static apr_status_t s_plain_cleanup(void* userdata) { return static_cast(userdata)->plain_cleanup(); } + + apr_status_t plain_cleanup(void) + { + if (mPool && // We are not being destructed, + parent_is_being_destructed()) // but our parent is. + // This means the pool is being destructed recursively by libapr + // because one of it's parents is being destructed. + { + mPool = NULL; // Stop destroy() from destructing the pool again. + } + return APR_SUCCESS; + } +}; + +class AIAPRInitialization +{ +public: + AIAPRInitialization(void); +}; + +/** + * @brief Root memory pool (allocates memory from the operating system). + * + * This class should only be used by AIThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase + * (and LLMutexRootPool when APR_HAS_THREADS isn't defined). + */ +class LL_COMMON_API AIAPRRootPool : public AIAPRInitialization, public AIAPRPool +{ +private: + friend class AIThreadLocalData; + friend class AIThreadSafeSimpleDCRootPool_pbase; +#if !APR_HAS_THREADS + friend class LLMutexRootPool; +#endif + //! Construct a root memory pool. + // Should only be used by AIThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase. + AIAPRRootPool(void); + ~AIAPRRootPool(); + +private: + // Keep track of how many root pools exist and when the last one is destructed. + static bool sCountInitialized; + static apr_uint32_t volatile sCount; + +public: + // Return a global root pool that is independent of AIThreadLocalData. + // Normally you should not use this. Only use for early initialization + // (before main) and deinitialization (after main). + static AIAPRRootPool& get(void); + +#if APR_POOL_DEBUG + void grab_ownership(void) + { + // You need a patched libapr to use this. + // See http://web.archiveorange.com/archive/v/5XO9y2zoxUOMt6Gmi1OI + apr_pool_owner_set(mPool); + } +#endif + +private: + // Used for constructing the Special Global Root Pool (returned by AIAPRRootPool::get). + // It is the same as the default constructor but omits to increment sCount. As a result, + // we must be sure that at least one other AIAPRRootPool is created before termination + // of the application (which is the case: we create one AIAPRRootPool per thread). + AIAPRRootPool(int) : AIAPRInitialization(), AIAPRPool(0) { } +}; + +//! Volatile memory pool +// +// 'Volatile' APR memory pool which normally only clears memory, +// and does not destroy the pool (the same pool is reused) for +// greater efficiency. However, as a safe guard the apr pool +// is destructed every FULL_VOLATILE_APR_POOL uses to allow +// the system memory to be allocated more efficiently and not +// get scattered through RAM. +// +class LL_COMMON_API AIVolatileAPRPool : protected AIAPRPool +{ +public: + AIVolatileAPRPool(void) : mNumActiveRef(0), mNumTotalRef(0) { } + + apr_pool_t* getVolatileAPRPool(void) + { + if (!mPool) create(); + ++mNumActiveRef; + ++mNumTotalRef; + return AIAPRPool::operator()(); + } + void clearVolatileAPRPool(void); + + bool isOld(void) const { return mNumTotalRef > FULL_VOLATILE_APR_POOL; } + bool isUnused() const { return mNumActiveRef == 0; } + +private: + S32 mNumActiveRef; // Number of active uses of the pool. + S32 mNumTotalRef; // Number of total uses of the pool since last creation. + + // Maximum number of references to AIVolatileAPRPool until the pool is recreated. + static S32 const FULL_VOLATILE_APR_POOL = 1024; +}; + +#endif // AIAPRPOOL_H diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index fb2fdd814..d5e75c76f 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -123,13 +123,8 @@ void LLApp::commonCtor() mOptions.append(sd); } - // Make sure we clean up APR when we exit - // Don't need to do this if we're cleaning up APR in the destructor - //atexit(ll_cleanup_apr); - // Set the application to this instance. sApplication = this; - } LLApp::LLApp(LLErrorThread *error_thread) : diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 7210bd2b1..9595707cb 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -34,219 +34,7 @@ #include "linden_common.h" #include "llapr.h" - -apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool -apr_thread_mutex_t *gLogMutexp = NULL; -apr_thread_mutex_t *gCallStacksLogMutexp = NULL; - -const S32 FULL_VOLATILE_APR_POOL = 1024 ; //number of references to LLVolatileAPRPool - -void ll_init_apr() -{ - if (!gAPRPoolp) - { - // Initialize APR and create the global pool - apr_initialize(); - apr_pool_create(&gAPRPoolp, NULL); - - // Initialize the logging mutex - apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp); - apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp); - - // Initialize thread-local APR pool support. - LLVolatileAPRPool::initLocalAPRFilePool(); - } -} - - -void ll_cleanup_apr() -{ - LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL; - - if (gLogMutexp) - { - // Clean up the logging mutex - - // All other threads NEED to be done before we clean up APR, so this is okay. - apr_thread_mutex_destroy(gLogMutexp); - gLogMutexp = NULL; - } - if (gCallStacksLogMutexp) - { - // Clean up the logging mutex - - // All other threads NEED to be done before we clean up APR, so this is okay. - apr_thread_mutex_destroy(gCallStacksLogMutexp); - gCallStacksLogMutexp = NULL; - } - if (gAPRPoolp) - { - apr_pool_destroy(gAPRPoolp); - gAPRPoolp = NULL; - } - apr_terminate(); -} - -// -// -//LLAPRPool -// -LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) - : mParent(parent), - mReleasePoolFlag(releasePoolFlag), - mMaxSize(size), - mPool(NULL) -{ - createAPRPool() ; -} - -LLAPRPool::~LLAPRPool() -{ - releaseAPRPool() ; -} - -void LLAPRPool::createAPRPool() -{ - if(mPool) - { - return ; - } - - mStatus = apr_pool_create(&mPool, mParent); - ll_apr_warn_status(mStatus) ; - - if(mMaxSize > 0) //size is the number of blocks (which is usually 4K), NOT bytes. - { - apr_allocator_t *allocator = apr_pool_allocator_get(mPool); - if (allocator) - { - apr_allocator_max_free_set(allocator, mMaxSize) ; - } - } -} - -void LLAPRPool::releaseAPRPool() -{ - if(!mPool) - { - return ; - } - - if(!mParent || mReleasePoolFlag) - { - apr_pool_destroy(mPool) ; - mPool = NULL ; - } -} - -apr_pool_t* LLAPRPool::getAPRPool() -{ - if(!mPool) - { - createAPRPool() ; - } - - return mPool ; -} -LLVolatileAPRPool::LLVolatileAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) - : LLAPRPool(parent, size, releasePoolFlag) -{ - mNumActiveRef = 0 ; - mNumTotalRef = 0 ; -} - -apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool() -{ - mNumTotalRef++ ; - mNumActiveRef++ ; - return getAPRPool() ; -} - -void LLVolatileAPRPool::clearVolatileAPRPool() -{ - if(mNumActiveRef > 0) - { - mNumActiveRef--; - if(mNumActiveRef < 1) - { - if(isFull()) - { - mNumTotalRef = 0 ; - - //destroy the apr_pool. - releaseAPRPool() ; - } - else - { - //This does not actually free the memory, - //it just allows the pool to re-use this memory for the next allocation. - apr_pool_clear(mPool) ; - } - } - } - else - { - llassert_always(mNumActiveRef > 0) ; - } - - //paranoia check if the pool is jammed. - //will remove the check before going to release. - llassert_always(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ; -} - -BOOL LLVolatileAPRPool::isFull() -{ - return mNumTotalRef > FULL_VOLATILE_APR_POOL ; -} - -#ifdef SHOW_ASSERT -// This allows the use of llassert(is_main_thread()) to assure the current thread is the main thread. -static void* gIsMainThread; -bool is_main_thread() { return gIsMainThread == LLVolatileAPRPool::getLocalAPRFilePool(); } -#endif - -// The thread private handle to access the LocalAPRFilePool. -apr_threadkey_t* LLVolatileAPRPool::sLocalAPRFilePoolKey; - -// This should be called exactly once, before the first call to createLocalAPRFilePool. -// static -void LLVolatileAPRPool::initLocalAPRFilePool() -{ - apr_status_t status = apr_threadkey_private_create(&sLocalAPRFilePoolKey, &destroyLocalAPRFilePool, gAPRPoolp); - ll_apr_assert_status(status); // Or out of memory, or system-imposed limit on the - // total number of keys per process {PTHREAD_KEYS_MAX} - // has been exceeded. - // Create the thread-local pool for the main thread (this function is called by the main thread). - createLocalAPRFilePool(); -#ifdef SHOW_ASSERT - gIsMainThread = getLocalAPRFilePool(); -#endif -} - -// This should be called once for every thread, before it uses getLocalAPRFilePool. -// static -void LLVolatileAPRPool::createLocalAPRFilePool() -{ - void* thread_local_data = new LLVolatileAPRPool; - apr_status_t status = apr_threadkey_private_set(thread_local_data, sLocalAPRFilePoolKey); - llassert_always(status == APR_SUCCESS); -} - -// This is called once for every thread when the thread is destructed. -// static -void LLVolatileAPRPool::destroyLocalAPRFilePool(void* thread_local_data) -{ - delete reinterpret_cast(thread_local_data); -} - -// static -LLVolatileAPRPool* LLVolatileAPRPool::getLocalAPRFilePool() -{ - void* thread_local_data; - apr_status_t status = apr_threadkey_private_get(&thread_local_data, sLocalAPRFilePoolKey); - llassert_always(status == APR_SUCCESS); - return reinterpret_cast(thread_local_data); -} +#include "llscopedvolatileaprpool.h" //--------------------------------------------------------------------- // @@ -309,13 +97,15 @@ void ll_apr_assert_status(apr_status_t status) // LLAPRFile::LLAPRFile() : mFile(NULL), - mCurrentFilePoolp(NULL) + mVolatileFilePoolp(NULL), + mRegularFilePoolp(NULL) { } LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type) : mFile(NULL), - mCurrentFilePoolp(NULL) + mVolatileFilePoolp(NULL), + mRegularFilePoolp(NULL) { open(filename, flags, access_type); } @@ -334,10 +124,16 @@ apr_status_t LLAPRFile::close() mFile = NULL ; } - if(mCurrentFilePoolp) + if (mVolatileFilePoolp) { - mCurrentFilePoolp->clearVolatileAPRPool() ; - mCurrentFilePoolp = NULL ; + mVolatileFilePoolp->clearVolatileAPRPool() ; + mVolatileFilePoolp = NULL ; + } + + if (mRegularFilePoolp) + { + delete mRegularFilePoolp; + mRegularFilePoolp = NULL; } return ret ; @@ -346,25 +142,28 @@ apr_status_t LLAPRFile::close() apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, access_t access_type, S32* sizep) { llassert_always(!mFile); - llassert_always(!mCurrentFilePoolp); + llassert_always(!mVolatileFilePoolp && !mRegularFilePoolp); - // Access the pool and increment it's reference count. - // The reference count of LLVolatileAPRPool objects will be decremented - // again in LLAPRFile::close by calling mCurrentFilePoolp->clearVolatileAPRPool(). - apr_pool_t* pool; - if (access_type == local) + apr_status_t status; { - // Use a "volatile" thread-local pool. - mCurrentFilePoolp = LLVolatileAPRPool::getLocalAPRFilePool(); - pool = mCurrentFilePoolp->getVolatileAPRPool(); + apr_pool_t* apr_file_open_pool; + if (access_type == local) + { + // Use a "volatile" thread-local pool. + mVolatileFilePoolp = &AIThreadLocalData::tldata().mVolatileAPRPool; + // Access the pool and increment it's reference count. + // The reference count of AIVolatileAPRPool objects will be decremented + // again in LLAPRFile::close by calling mVolatileFilePoolp->clearVolatileAPRPool(). + apr_file_open_pool = mVolatileFilePoolp->getVolatileAPRPool(); + } + else + { + mRegularFilePoolp = new AIAPRPool(AIThreadLocalData::tldata().mRootPool); + apr_file_open_pool = (*mRegularFilePoolp)(); + } + status = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, apr_file_open_pool); } - else - { - llassert(is_main_thread()); - pool = gAPRPoolp; - } - apr_status_t s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, pool); - if (s != APR_SUCCESS || !mFile) + if (status != APR_SUCCESS || !mFile) { mFile = NULL ; close() ; @@ -372,7 +171,7 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc { *sizep = 0; } - return s; + return status; } if (sizep) @@ -389,7 +188,7 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc *sizep = file_size; } - return s; + return status; } // File I/O @@ -449,17 +248,6 @@ S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset) //static components of LLAPRFile // -// Used in the static functions below. -class LLScopedVolatileAPRFilePool { -private: - LLVolatileAPRPool* mPool; - apr_pool_t* apr_pool; -public: - LLScopedVolatileAPRFilePool() : mPool(LLVolatileAPRPool::getLocalAPRFilePool()), apr_pool(mPool->getVolatileAPRPool()) { } - ~LLScopedVolatileAPRFilePool() { mPool->clearVolatileAPRPool(); } - operator apr_pool_t*() const { return apr_pool; } -}; - //static S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset) { @@ -496,7 +284,7 @@ S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset) S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes) { apr_file_t* file_handle; - LLScopedVolatileAPRFilePool pool; + LLScopedVolatileAPRPool pool; apr_status_t s = apr_file_open(&file_handle, filename.c_str(), APR_READ|APR_BINARY, APR_OS_DEFAULT, pool); if (s != APR_SUCCESS || !file_handle) { @@ -548,7 +336,7 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n } apr_file_t* file_handle; - LLScopedVolatileAPRFilePool pool; + LLScopedVolatileAPRPool pool; apr_status_t s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool); if (s != APR_SUCCESS || !file_handle) { @@ -593,7 +381,7 @@ bool LLAPRFile::remove(const std::string& filename) { apr_status_t s; - LLScopedVolatileAPRFilePool pool; + LLScopedVolatileAPRPool pool; s = apr_file_remove(filename.c_str(), pool); if (s != APR_SUCCESS) @@ -613,7 +401,7 @@ bool LLAPRFile::rename(const std::string& filename, const std::string& newname) { apr_status_t s; - LLScopedVolatileAPRFilePool pool; + LLScopedVolatileAPRPool pool; s = apr_file_rename(filename.c_str(), newname.c_str(), pool); if (s != APR_SUCCESS) @@ -631,7 +419,7 @@ bool LLAPRFile::isExist(const std::string& filename, apr_int32_t flags) apr_file_t* file_handle; apr_status_t s; - LLScopedVolatileAPRFilePool pool; + LLScopedVolatileAPRPool pool; s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool); if (s != APR_SUCCESS || !file_handle) @@ -652,7 +440,7 @@ S32 LLAPRFile::size(const std::string& filename) apr_finfo_t info; apr_status_t s; - LLScopedVolatileAPRFilePool pool; + LLScopedVolatileAPRPool pool; s = apr_file_open(&file_handle, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool); if (s != APR_SUCCESS || !file_handle) @@ -681,7 +469,7 @@ bool LLAPRFile::makeDir(const std::string& dirname) { apr_status_t s; - LLScopedVolatileAPRFilePool pool; + LLScopedVolatileAPRPool pool; s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool); if (s != APR_SUCCESS) @@ -698,7 +486,7 @@ bool LLAPRFile::removeDir(const std::string& dirname) { apr_status_t s; - LLScopedVolatileAPRFilePool pool; + LLScopedVolatileAPRPool pool; s = apr_file_remove(dirname.c_str(), pool); if (s != APR_SUCCESS) diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 2aed51511..ded15f531 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -48,73 +48,8 @@ #include "apr_atomic.h" #include "llstring.h" -extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp; - -/** - * @brief initialize the common apr constructs -- apr itself, the - * global pool, and a mutex. - */ -void LL_COMMON_API ll_init_apr(); - -/** - * @brief Cleanup those common apr constructs. - */ -void LL_COMMON_API ll_cleanup_apr(); - -// -//LL apr_pool -//manage apr_pool_t, destroy allocated apr_pool in the destruction function. -// -class LL_COMMON_API LLAPRPool -{ -public: - LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ; - ~LLAPRPool() ; - - apr_pool_t* getAPRPool() ; - apr_status_t getStatus() {return mStatus ; } - -protected: - void releaseAPRPool() ; - void createAPRPool() ; - -protected: - apr_pool_t* mPool ; //pointing to an apr_pool - apr_pool_t* mParent ; //parent pool - apr_size_t mMaxSize ; //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work. - apr_status_t mStatus ; //status when creating the pool - BOOL mReleasePoolFlag ; //if set, mPool is destroyed when LLAPRPool is deleted. default value is true. -}; - -// -//volatile LL apr_pool -//which clears memory automatically. -//so it can not hold static data or data after memory is cleared -// -class LL_COMMON_API LLVolatileAPRPool : protected LLAPRPool -{ -public: - LLVolatileAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE); - ~LLVolatileAPRPool(){} - - apr_pool_t* getVolatileAPRPool() ; - - void clearVolatileAPRPool() ; - - BOOL isFull() ; - BOOL isEmpty() {return !mNumActiveRef ;} - - static void initLocalAPRFilePool(); - static void createLocalAPRFilePool(); - static void destroyLocalAPRFilePool(void* thread_local_data); - static LLVolatileAPRPool* getLocalAPRFilePool(); - -private: - S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool. - S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating. - - static apr_threadkey_t* sLocalAPRFilePoolKey; -} ; +class AIAPRPool; +class AIVolatileAPRPool; /** * @class LLScopedLock @@ -205,7 +140,8 @@ class LL_COMMON_API LLAPRFile : boost::noncopyable // make this non copyable since a copy closes the file private: apr_file_t* mFile ; - LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. + AIVolatileAPRPool* mVolatileFilePoolp; // (Thread local) APR pool currently in use. + AIAPRPool* mRegularFilePoolp; // ...or a regular pool. public: enum access_t { @@ -260,6 +196,4 @@ bool LL_COMMON_API ll_apr_warn_status(apr_status_t status); void LL_COMMON_API ll_apr_assert_status(apr_status_t status); -extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool - #endif // LL_LLAPR_H diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp index 2cbb71855..298dd4695 100644 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -34,18 +34,10 @@ #include "llcommon.h" #include "llthread.h" -//static -BOOL LLCommon::sAprInitialized = FALSE; - //static void LLCommon::initClass() { LLMemory::initClass(); - if (!sAprInitialized) - { - ll_init_apr(); - sAprInitialized = TRUE; - } LLTimer::initClass(); LLThreadSafeRefCount::initThreadSafeRefCount(); // LLWorkerThread::initClass(); @@ -59,10 +51,5 @@ void LLCommon::cleanupClass() // LLWorkerThread::cleanupClass(); LLThreadSafeRefCount::cleanupThreadSafeRefCount(); LLTimer::cleanupClass(); - if (sAprInitialized) - { - ll_cleanup_apr(); - sAprInitialized = FALSE; - } LLMemory::cleanupClass(); } diff --git a/indra/llcommon/llcommon.h b/indra/llcommon/llcommon.h index 851d4ac2d..300ebe2b2 100644 --- a/indra/llcommon/llcommon.h +++ b/indra/llcommon/llcommon.h @@ -43,8 +43,6 @@ class LL_COMMON_API LLCommon public: static void initClass(); static void cleanupClass(); -private: - static BOOL sAprInitialized; }; #endif diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index e549979f0..56495e666 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -877,6 +877,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) diff --git a/indra/llcommon/llfixedbuffer.cpp b/indra/llcommon/llfixedbuffer.cpp index 1f6a06c24..08be3e259 100644 --- a/indra/llcommon/llfixedbuffer.cpp +++ b/indra/llcommon/llfixedbuffer.cpp @@ -36,8 +36,7 @@ LLFixedBuffer::LLFixedBuffer(const U32 max_lines) : LLLineBuffer(), - mMaxLines(max_lines), - mMutex(NULL) + mMaxLines(max_lines) { mTimer.reset(); } diff --git a/indra/llcommon/llscopedvolatileaprpool.h b/indra/llcommon/llscopedvolatileaprpool.h new file mode 100644 index 000000000..724dc7f05 --- /dev/null +++ b/indra/llcommon/llscopedvolatileaprpool.h @@ -0,0 +1,58 @@ +/** + * @file llscopedvolatileaprpool.h + * @brief Implementation of LLScopedVolatileAPRPool + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSCOPEDVOLATILEAPRPOOL_H +#define LL_LLSCOPEDVOLATILEAPRPOOL_H + +#include "llthread.h" + +//! Scoped volatile memory pool. +// +// As the AIVolatileAPRPool should never keep allocations very +// long, it's most common use is for allocations with a lifetime +// equal to it's scope. +// +// This is a convenience class that makes just a little easier to type. +// +class LLScopedVolatileAPRPool +{ +private: + AIVolatileAPRPool& mPool; + apr_pool_t* mScopedAPRpool; +public: + LLScopedVolatileAPRPool() : mPool(AIThreadLocalData::tldata().mVolatileAPRPool), mScopedAPRpool(mPool.getVolatileAPRPool()) { } + ~LLScopedVolatileAPRPool() { mPool.clearVolatileAPRPool(); } + // Only use this to pass the pointer to a libapr-1 function that requires it. + operator apr_pool_t*() const { return mScopedAPRpool; } +}; + +#endif diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 9b74e1d1d..7ced30939 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -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(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(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; } } diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 399f0f741..8fa1b59ae 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -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,7 @@ public: mMutex->unlock(); } private: - LLMutex* mMutex; + LLMutexBase* mMutex; }; //============================================================================ diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp index c4be02818..65f27095b 100644 --- a/indra/llcommon/llworkerthread.cpp +++ b/indra/llcommon/llworkerthread.cpp @@ -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) diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h index 3d761dc87..117dc05cc 100644 --- a/indra/llcommon/llworkerthread.h +++ b/indra/llcommon/llworkerthread.h @@ -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; }; diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index 804c51274..3dc41e897 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -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 diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 546a16d16..3f3dbc87c 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -57,7 +57,7 @@ LLMutex* LLImage::sMutex = NULL; //static void LLImage::initClass() { - sMutex = new LLMutex(NULL); + sMutex = new LLMutex; LLImageJ2C::openDSO(); } diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 08bcde633..14917fadf 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -46,7 +46,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 @@ -81,13 +81,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 ) @@ -151,11 +150,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(); } } @@ -163,7 +158,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 diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index aceebf781..79353d55b 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -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; } diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h index 9a09f81bc..2703af497 100644 --- a/indra/llimage/llimageworker.h +++ b/indra/llimage/llimageworker.h @@ -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_list_t; creation_list_t mCreationList; - LLMutex* mCreationMutex; + LLMutex mCreationMutex; }; #endif diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index 53641fcea..8bfebcb42 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -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; } } diff --git a/indra/llmessage/llares.cpp b/indra/llmessage/llares.cpp index 7a2dc6cc3..93079f537 100644 --- a/indra/llmessage/llares.cpp +++ b/indra/llmessage/llares.cpp @@ -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) { diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index f43bafd45..38b2bea1b 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -1082,7 +1082,7 @@ void LLCurl::initClass() S32 mutex_count = CRYPTO_num_locks(); for (S32 i=0; i 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)); diff --git a/indra/llmessage/lliohttpserver.h b/indra/llmessage/lliohttpserver.h index e8e390f29..66e763444 100644 --- a/indra/llmessage/lliohttpserver.h +++ b/indra/llmessage/lliohttpserver.h @@ -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 diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp index 7ec577c7b..686c03742 100644 --- a/indra/llmessage/lliosocket.cpp +++ b/indra/llmessage/lliosocket.cpp @@ -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; diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h index ec09ad8ba..5ad75e909 100644 --- a/indra/llmessage/lliosocket.h +++ b/indra/llmessage/lliosocket.h @@ -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 - * accept() 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 create() 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 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: diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp index ce206d8d7..e55a1bb41 100644 --- a/indra/llmessage/llmail.cpp +++ b/indra/llmessage/llmail.cpp @@ -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); } } diff --git a/indra/llmessage/llmail.h b/indra/llmessage/llmail.h index 7effb847a..7026d93b3 100644 --- a/indra/llmessage/llmail.h +++ b/indra/llmessage/llmail.h @@ -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); diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp index b8c6b1652..7877b855a 100644 --- a/indra/llmessage/llpumpio.cpp +++ b/indra/llmessage/llpumpio.cpp @@ -43,6 +43,7 @@ #include "llmemtype.h" #include "llstl.h" #include "llstat.h" +#include "llthread.h" #include "llfasttimer.h" #include //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); diff --git a/indra/llmessage/llpumpio.h b/indra/llmessage/llpumpio.h index fc0bfabaa..2666be04a 100644 --- a/indra/llmessage/llpumpio.h +++ b/indra/llmessage/llpumpio.h @@ -36,11 +36,12 @@ #define LL_LLPUMPIO_H #include +#include #if LL_LINUX // needed for PATH_MAX in APR. #include #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; * pump() on a thread used for IO and call * respond() 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 prime() - * 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 pipe_conditional_t; typedef std::vector conditionals_t; conditionals_t mDescriptors; + boost::shared_ptr 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 diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 46e976fe3..87f011643 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -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); } diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 677052d65..d0572fb4a 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -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; diff --git a/indra/llplugin/llplugininstance.cpp b/indra/llplugin/llplugininstance.cpp index b822b9e94..3a1395cd2 100644 --- a/indra/llplugin/llplugininstance.cpp +++ b/indra/llplugin/llplugininstance.cpp @@ -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]; diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp index 8168b32c4..ebac3c52b 100644 --- a/indra/llplugin/llpluginmessagepipe.cpp +++ b/indra/llplugin/llpluginmessagepipe.cpp @@ -99,8 +99,6 @@ void LLPluginMessagePipeOwner::killMessagePipe(void) } LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket): - mInputMutex(gAPRPoolp), - mOutputMutex(gAPRPoolp), mOwner(owner), mSocket(socket) { diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp index 8dbf2b3e9..d2238236f 100644 --- a/indra/llplugin/llpluginprocesschild.cpp +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -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; diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 8fd18ef05..2cb6b2832 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -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::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::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 diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h index 95f5f70c5..bba3643d6 100644 --- a/indra/llplugin/llpluginprocessparent.h +++ b/indra/llplugin/llpluginprocessparent.h @@ -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 sInstances; diff --git a/indra/llplugin/llpluginsharedmemory.cpp b/indra/llplugin/llpluginsharedmemory.cpp index e8a411a53..883d7b634 100644 --- a/indra/llplugin/llpluginsharedmemory.cpp +++ b/indra/llplugin/llpluginsharedmemory.cpp @@ -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; } diff --git a/indra/llplugin/llpluginsharedmemory.h b/indra/llplugin/llpluginsharedmemory.h index 081d311b3..669a3e409 100644 --- a/indra/llplugin/llpluginsharedmemory.h +++ b/indra/llplugin/llpluginsharedmemory.h @@ -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; diff --git a/indra/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp index 64c087bec..cca8ead8f 100644 --- a/indra/llplugin/slplugin/slplugin.cpp +++ b/indra/llplugin/slplugin/slplugin.cpp @@ -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; } diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp index b90d4b3c8..1f4c991b2 100644 --- a/indra/llvfs/llvfs.cpp +++ b/indra/llvfs/llvfs.cpp @@ -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++) diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 085708640..321d1f91f 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -50,7 +50,7 @@ extern "C" { #include #include // 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) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index bd1521ba3..18715632e 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -857,7 +857,7 @@ bool LLAppViewer::mainLoop() //------------------------------------------- // Create IO Pump to use for HTTP Requests. - gServicePump = new LLPumpIO(gAPRPoolp); + gServicePump = new LLPumpIO; LLHTTPClient::setPump(*gServicePump); LLCurl::setCAFile(gDirUtilp->getCAFile()); diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index bb9d61394..a19ad5658 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -139,6 +139,7 @@ int main( int argc, char **argv ) } delete viewer_app_ptr; viewer_app_ptr = NULL; + return 0; } diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index 67fc17d28..b7bb39a74 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -119,6 +119,7 @@ int main( int argc, char **argv ) } delete viewer_app_ptr; viewer_app_ptr = NULL; + return 0; } diff --git a/indra/newview/llconsole.cpp b/indra/newview/llconsole.cpp index 4a0647b8b..937ccec24 100644 --- a/indra/newview/llconsole.cpp +++ b/indra/newview/llconsole.cpp @@ -68,8 +68,7 @@ LLConsole::LLConsole(const std::string& name, const LLRect &rect, mFadeTime(persist_time - FADE_DURATION), mFont(LLFontGL::getFontSansSerif()), mConsoleWidth(0), - mConsoleHeight(0), - mQueueMutex(NULL) + mConsoleHeight(0) { mTimer.reset(); diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 5e08d7608..c37add97a 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -743,9 +743,6 @@ void LLTextureCacheWorker::endWork(S32 param, bool aborted) LLTextureCache::LLTextureCache(bool threaded) : LLWorkerThread("TextureCache", threaded), - mWorkersMutex(NULL), - mHeaderMutex(NULL), - mListMutex(NULL), mHeaderAPRFile(NULL), mReadOnly(TRUE), //do not allow to change the texture cache until setReadOnly() is called. mTexturesSizeTotal(0), diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h index 45ec5e211..3a4b1f25e 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -143,9 +143,6 @@ protected: std::string getTextureFileName(const LLUUID& id); void addCompleted(Responder* responder, bool success); -protected: - //void setFileAPRPool(apr_pool_t* pool) { mFileAPRPool = pool ; } - private: void setDirNames(ELLPath location); void readHeaderCache(); diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 0655b509e..cd74d3d73 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -425,7 +425,7 @@ class SGHostBlackList{ static void lock() { if (!sMutex) - sMutex = new LLMutex(0); + sMutex = new LLMutex; sMutex->lock(); } @@ -767,7 +767,6 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, mRetryAttempt(0), mActiveCount(0), mGetStatus(0), - mWorkMutex(NULL), mFirstPacket(0), mLastPacket(-1), mTotalPackets(0), @@ -1943,8 +1942,6 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image mDebugPause(FALSE), mPacketCount(0), mBadPacketCount(0), - mQueueMutex(getAPRPool()), - mNetworkQueueMutex(getAPRPool()), mTextureCache(cache), mImageDecodeThread(imagedecodethread), mTextureBandwidth(0), diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h index 2921dd583..85eaabee9 100644 --- a/indra/newview/llviewerprecompiledheaders.h +++ b/indra/newview/llviewerprecompiledheaders.h @@ -164,7 +164,7 @@ #include "llinstantmessage.h" #include "llinvite.h" //#include "llloginflags.h" -#include "llmail.h" +//#include "llmail.h" #include "llmessagethrottle.h" #include "llnamevalue.h" #include "llpacketack.h" diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index eca5594a5..79e8fc535 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -1781,7 +1781,7 @@ void LLVoiceClient::stateMachine() if(!mSocket) { - mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); + mSocket = LLSocket::create(LLSocket::STREAM_TCP); } mConnected = mSocket->blockingConnect(mDaemonHost); diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp index 330bc8a39..9af050c4c 100644 --- a/indra/newview/llwatchdog.cpp +++ b/indra/newview/llwatchdog.cpp @@ -184,8 +184,8 @@ void LLWatchdog::init(killer_event_callback func) mKillerCallback = func; if(!mSuspectsAccessMutex && !mTimer) { - mSuspectsAccessMutex = new LLMutex(NULL); - mTimer = new LLWatchdogTimerThread(); + mSuspectsAccessMutex = new LLMutex; + mTimer = new LLWatchdogTimerThread; mTimer->setSleepTime(WATCHDOG_SLEEP_TIME_USEC / 1000); mLastClockCount = LLTimer::getTotalTime(); diff --git a/indra/test/lltemplatemessagebuilder_tut.cpp b/indra/test/lltemplatemessagebuilder_tut.cpp index 5b33d0272..9fecc2f90 100644 --- a/indra/test/lltemplatemessagebuilder_tut.cpp +++ b/indra/test/lltemplatemessagebuilder_tut.cpp @@ -35,7 +35,6 @@ #include "linden_common.h" #include "lltut.h" -#include "llapr.h" #include "llmessagetemplate.h" #include "llquaternion.h" #include "lltemplatemessagebuilder.h" @@ -59,7 +58,6 @@ namespace tut static bool init = false; if(! init) { - ll_init_apr(); const F32 circuit_heartbeat_interval=5; const F32 circuit_timeout=100; diff --git a/indra/test/message_tut.cpp b/indra/test/message_tut.cpp index 3fede2608..694db5213 100644 --- a/indra/test/message_tut.cpp +++ b/indra/test/message_tut.cpp @@ -35,7 +35,6 @@ #include "linden_common.h" #include "lltut.h" -#include "llapr.h" #include "llmessageconfig.h" #include "llsdserialize.h" #include "llversionserver.h" @@ -68,7 +67,6 @@ namespace tut static bool init = false; if(!init) { - ll_init_apr(); //init_prehash_data(); init = true; } diff --git a/indra/test/test.cpp b/indra/test/test.cpp index 8e1376ddc..d8f00c602 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -43,8 +43,8 @@ #include "linden_common.h" #include "llerrorcontrol.h" #include "lltut.h" +#include "aiaprpool.h" -#include "apr_pools.h" #include "apr_getopt.h" extern void ll_init_apr(); @@ -250,17 +250,12 @@ int main(int argc, char **argv) ctype_workaround(); #endif - ll_init_apr(); - apr_pool_t* pool = NULL; - if(APR_SUCCESS != apr_pool_create(&pool, NULL)) - { - std::cerr << "Unable to initialize pool" << std::endl; - return 1; - } + AIAPRPool pool; + pool.create(); apr_getopt_t* os = NULL; - if(APR_SUCCESS != apr_getopt_init(&os, pool, argc, argv)) + if(APR_SUCCESS != apr_getopt_init(&os, pool(), argc, argv)) { - std::cerr << "Unable to pool" << std::endl; + std::cerr << "Unable to initialize the arguments for parsing by apr_getopt()." << std::endl; return 1; } @@ -362,6 +357,5 @@ int main(int argc, char **argv) s.close(); } - apr_terminate(); return 0; } From 86a19e8e917e72b27c059a0da911539705834ea1 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 5 May 2011 02:54:38 +0200 Subject: [PATCH 15/16] IMP-701: An API to wrap objects for thread-safe access. See http://redmine.imprudenceviewer.org/issues/701 --- doc/contributions.txt | 1 + indra/llcommon/CMakeLists.txt | 1 + indra/llcommon/aithreadsafe.h | 482 ++++++++++++++++++++++++++++++++++ indra/llcommon/llthread.h | 96 ++++++- 4 files changed, 579 insertions(+), 1 deletion(-) create mode 100644 indra/llcommon/aithreadsafe.h diff --git a/doc/contributions.txt b/doc/contributions.txt index 849c95de4..b5b84a45d 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -111,6 +111,7 @@ Aleric Inglewood IMP-663 IMP-664 IMP-670 + IMP-701 Alissa Sabre VWR-81 VWR-83 diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index cc6bffe3f..7f352269b 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -80,6 +80,7 @@ set(llcommon_HEADER_FILES CMakeLists.txt aiaprpool.h + aithreadsafe.h bitpack.h ctype_workaround.h doublelinkedlist.h diff --git a/indra/llcommon/aithreadsafe.h b/indra/llcommon/aithreadsafe.h new file mode 100644 index 000000000..70cd2a3db --- /dev/null +++ b/indra/llcommon/aithreadsafe.h @@ -0,0 +1,482 @@ +/** + * @file aithreadsafe.h + * @brief Implementation of AIThreadSafe, AIReadAccessConst, AIReadAccess and AIWriteAccess. + * + * Copyright (c) 2010, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 31/03/2010 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AITHREADSAFE_H +#define AITHREADSAFE_H + +#include + +#include "llthread.h" +#include "llerror.h" + +template struct AIReadAccessConst; +template struct AIReadAccess; +template struct AIWriteAccess; +template struct AIAccess; + +template +class AIThreadSafeBits +{ +private: + // AIThreadSafe is a wrapper around an instance of T. + // Because T might not have a default constructor, it is constructed + // 'in place', with placement new, in the memory reserved here. + // + // Make sure that the memory that T will be placed in is properly + // aligned by using an array of long's. + long mMemory[(sizeof(T) + sizeof(long) - 1) / sizeof(long)]; + +public: + // The wrapped objects are constructed in-place with placement new *outside* + // of this object (by AITHREADSAFE macro(s) or derived classes). + // However, we are responsible for the destruction of the wrapped object. + ~AIThreadSafeBits() { ptr()->~T(); } + + // Only for use by AITHREADSAFE, see below. + void* memory() const { return const_cast(&mMemory[0]); } + +protected: + // Accessors. + T const* ptr() const { return reinterpret_cast(mMemory); } + T* ptr() { return reinterpret_cast(mMemory); } +}; + +/** + * @brief A wrapper class for objects that need to be accessed by more than one thread, allowing concurrent readers. + * + * Use AITHREADSAFE to define instances of any type, and use AIReadAccessConst, + * AIReadAccess and AIWriteAccess to get access to the instance. + * + * For example, + * + * + * class Foo { public: Foo(int, int); }; + * + * AITHREADSAFE(Foo, foo, (2, 3)); + * + * AIReadAccess foo_r(foo); + * // Use foo_r-> for read access. + * + * AIWriteAccess foo_w(foo); + * // Use foo_w-> for write access. + * + * + * If foo is constant, you have to use AIReadAccessConst. + * + * It is possible to pass access objects to a function that + * downgrades the access, for example: + * + * + * void readfunc(AIReadAccess const& access); + * + * AIWriteAccess foo_w(foo); + * readfunc(foo_w); // readfunc will perform read access to foo_w. + * + * + * If AIReadAccess is non-const, you can upgrade the access by creating + * an AIWriteAccess object from it. For example: + * + * + * AIWriteAccess foo_w(foo_r); + * + * + * This API is Robust(tm). If you try anything that could result in problems, + * it simply won't compile. The only mistake you can still easily make is + * to obtain write access to an object when it is not needed, or to unlock + * an object in between accesses while the state of the object should be + * preserved. For example: + * + * + * // This resets foo to point to the first file and then returns that. + * std::string filename = AIWriteAccess(foo)->get_first_filename(); + * + * // WRONG! The state between calling get_first_filename and get_next_filename should be preserved! + * + * AIWriteAccess foo_w(foo); // Wrong. The code below only needs read-access. + * while (!filename.empty()) + * { + * something(filename); + * filename = foo_w->next_filename(); + * } + * + * + * Correct would be + * + * + * AIReadAccess foo_r(foo); + * std::string filename = AIWriteAccess(foo_r)->get_first_filename(); + * while (!filename.empty()) + * { + * something(filename); + * filename = foo_r->next_filename(); + * } + * + * + */ +template +class AIThreadSafe : public AIThreadSafeBits +{ +protected: + // Only these may access the object (through ptr()). + friend struct AIReadAccessConst; + friend struct AIReadAccess; + friend struct AIWriteAccess; + + // Locking control. + AIRWLock mRWLock; + + // For use by AIThreadSafeDC + AIThreadSafe(void) { } + AIThreadSafe(AIAPRPool& parent) : mRWLock(parent) { } + +public: + // Only for use by AITHREADSAFE, see below. + AIThreadSafe(T* object) { llassert(object == AIThreadSafeBits::ptr()); } +}; + +/** + * @brief Instantiate an static, global or local object of a given type wrapped in AIThreadSafe, using an arbitrary constructor. + * + * For example, instead of doing + * + * + * Foo foo(x, y); + * static Bar bar; + * + * + * One can instantiate a thread-safe instance with + * + * + * AITHREADSAFE(Foo, foo, (x, y)); + * static AITHREADSAFE(Bar, bar, ); + * + * + * Note: This macro does not allow to allocate such object on the heap. + * If that is needed, have a look at AIThreadSafeDC. + */ +#define AITHREADSAFE(type, var, paramlist) AIThreadSafe var(new (var.memory()) type paramlist) + +/** + * @brief A wrapper class for objects that need to be accessed by more than one thread. + * + * This class is the same as an AIThreadSafe wrapper, except that it can only + * be used for default constructed objects. + * + * For example, instead of + * + * + * Foo foo; + * + * + * One would use + * + * + * AIThreadSafeDC foo; + * + * + * The advantage over AITHREADSAFE is that this object can be allocated with + * new on the heap. For example: + * + * + * AIThreadSafeDC* ptr = new AIThreadSafeDC; + * + * + * which is not possible with AITHREADSAFE. + */ +template +class AIThreadSafeDC : public AIThreadSafe +{ +public: + // Construct a wrapper around a default constructed object. + AIThreadSafeDC(void) { new (AIThreadSafe::ptr()) T; } +}; + +/** + * @brief Read lock object and provide read access. + */ +template +struct AIReadAccessConst +{ + //! Internal enum for the lock-type of the AI*Access object. + enum state_type + { + readlocked, //!< A AIReadAccessConst or AIReadAccess. + read2writelocked, //!< A AIWriteAccess constructed from a AIReadAccess. + writelocked, //!< A AIWriteAccess constructed from a AIThreadSafe. + write2writelocked //!< A AIWriteAccess constructed from (the AIReadAccess base class of) a AIWriteAccess. + }; + + //! Construct a AIReadAccessConst from a constant AIThreadSafe. + AIReadAccessConst(AIThreadSafe const& wrapper) + : mWrapper(const_cast&>(wrapper)), + mState(readlocked) + { + mWrapper.mRWLock.rdlock(); + } + + //! Destruct the AI*Access object. + // These should never be dynamically allocated, so there is no need to make this virtual. + ~AIReadAccessConst() + { + if (mState == readlocked) + mWrapper.mRWLock.rdunlock(); + else if (mState == writelocked) + mWrapper.mRWLock.wrunlock(); + else if (mState == read2writelocked) + mWrapper.mRWLock.wr2rdlock(); + } + + //! Access the underlaying object for read access. + T const* operator->() const { return mWrapper.ptr(); } + + //! Access the underlaying object for read access. + T const& operator*() const { return *mWrapper.ptr(); } + +protected: + //! Constructor used by AIReadAccess. + AIReadAccessConst(AIThreadSafe& wrapper, state_type state) + : mWrapper(wrapper), mState(state) { } + + AIThreadSafe& mWrapper; //!< Reference to the object that we provide access to. + state_type const mState; //!< The lock state that mWrapper is in. + +private: + // Disallow copy constructing directly. + AIReadAccessConst(AIReadAccessConst const&); +}; + +/** + * @brief Read lock object and provide read access, with possible promotion to write access. + */ +template +struct AIReadAccess : public AIReadAccessConst +{ + typedef typename AIReadAccessConst::state_type state_type; + using AIReadAccessConst::readlocked; + + //! Construct a AIReadAccess from a non-constant AIThreadSafe. + AIReadAccess(AIThreadSafe& wrapper) : AIReadAccessConst(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(); } + +protected: + //! Constructor used by AIWriteAccess. + AIReadAccess(AIThreadSafe& wrapper, state_type state) : AIReadAccessConst(wrapper, state) { } + + friend class AIWriteAccess; +}; + +/** + * @brief Write lock object and provide read/write access. + */ +template +struct AIWriteAccess : public AIReadAccess +{ + using AIReadAccessConst::readlocked; + using AIReadAccessConst::read2writelocked; + using AIReadAccessConst::writelocked; + using AIReadAccessConst::write2writelocked; + + //! Construct a AIWriteAccess from a non-constant AIThreadSafe. + AIWriteAccess(AIThreadSafe& wrapper) : AIReadAccess(wrapper, writelocked) { this->mWrapper.mRWLock.wrlock();} + + //! Promote read access to write access. + explicit AIWriteAccess(AIReadAccess& access) + : AIReadAccess(access.mWrapper, (access.mState == readlocked) ? read2writelocked : write2writelocked) + { + if (this->mState == read2writelocked) + { + this->mWrapper.mRWLock.rd2wrlock(); + } + } + + //! Access the underlaying object for (read and) write access. + T* operator->() const { return this->mWrapper.ptr(); } + + //! Access the underlaying object for (read and) write access. + T& operator*() const { return *this->mWrapper.ptr(); } +}; + +/** + * @brief A wrapper class for objects that need to be accessed by more than one thread. + * + * Use AITHREADSAFESIMPLE to define instances of any type, and use AIAccess + * to get access to the instance. + * + * For example, + * + * + * class Foo { public: Foo(int, int); }; + * + * AITHREADSAFESIMPLE(Foo, foo, (2, 3)); + * + * AIAccess foo_w(foo); + * // Use foo_w-> for read and write access. + * + * See also AIThreadSafe + */ +template +class AIThreadSafeSimple : public AIThreadSafeBits +{ +protected: + // Only this one may access the object (through ptr()). + friend struct AIAccess; + + // Locking control. + LLMutex mMutex; + + // For use by AIThreadSafeSimpleDC + AIThreadSafeSimple(void) { } + AIThreadSafeSimple(AIAPRPool& parent) : mMutex(parent) { } + +public: + // Only for use by AITHREADSAFESIMPLE, see below. + AIThreadSafeSimple(T* object) { llassert(object == AIThreadSafeBits::ptr()); } +}; + +/** + * @brief Instantiate an static, global or local object of a given type wrapped in AIThreadSafeSimple, using an arbitrary constructor. + * + * For example, instead of doing + * + * + * Foo foo(x, y); + * static Bar bar; + * + * + * One can instantiate a thread-safe instance with + * + * + * AITHREADSAFESIMPLE(Foo, foo, (x, y)); + * static AITHREADSAFESIMPLE(Bar, bar, ); + * + * + * Note: This macro does not allow to allocate such object on the heap. + * If that is needed, have a look at AIThreadSafeSimpleDC. + */ +#define AITHREADSAFESIMPLE(type, var, paramlist) AIThreadSafeSimple var(new (var.memory()) type paramlist) + +/** + * @brief A wrapper class for objects that need to be accessed by more than one thread. + * + * This class is the same as an AIThreadSafeSimple wrapper, except that it can only + * be used for default constructed objects. + * + * For example, instead of + * + * + * Foo foo; + * + * + * One would use + * + * + * AIThreadSafeSimpleDC foo; + * + * + * The advantage over AITHREADSAFESIMPLE is that this object can be allocated with + * new on the heap. For example: + * + * + * AIThreadSafeSimpleDC* ptr = new AIThreadSafeSimpleDC; + * + * + * which is not possible with AITHREADSAFESIMPLE. + */ +template +class AIThreadSafeSimpleDC : public AIThreadSafeSimple +{ +public: + // Construct a wrapper around a default constructed object. + AIThreadSafeSimpleDC(void) { new (AIThreadSafeSimple::ptr()) T; } + +protected: + // For use by AIThreadSafeSimpleDCRootPool + AIThreadSafeSimpleDC(AIAPRPool& parent) : AIThreadSafeSimple(parent) { new (AIThreadSafeSimple::ptr()) T; } +}; + +// Helper class for AIThreadSafeSimpleDCRootPool to assure initialization of +// the root pool before constructing AIThreadSafeSimpleDC. +class AIThreadSafeSimpleDCRootPool_pbase +{ +protected: + AIAPRRootPool mRootPool; + +private: + template friend class AIThreadSafeSimpleDCRootPool; + AIThreadSafeSimpleDCRootPool_pbase(void) { } +}; + +/** + * @brief A wrapper class for objects that need to be accessed by more than one thread. + * + * The same as AIThreadSafeSimpleDC except that this class creates its own AIAPRRootPool + * for the internally used mutexes and condition, instead of using the current threads + * root pool. The advantage of this is that it can be used for objects that need to + * be accessed from the destructors of global objects (after main). The disadvantage + * is that it's less efficient to use your own root pool, therefore it's use should be + * restricted to those cases where it is absolutely necessary. + */ +template +class AIThreadSafeSimpleDCRootPool : private AIThreadSafeSimpleDCRootPool_pbase, public AIThreadSafeSimpleDC +{ +public: + // Construct a wrapper around a default constructed object, using memory allocated + // from the operating system for the internal APR objects (mutexes and conditional), + // as opposed to allocated from the current threads root pool. + AIThreadSafeSimpleDCRootPool(void) : + AIThreadSafeSimpleDCRootPool_pbase(), + AIThreadSafeSimpleDC(mRootPool) { } +}; + +/** + * @brief Write lock object and provide read/write access. + */ +template +struct AIAccess +{ + //! Construct a AIAccess from a non-constant AIThreadSafeSimple. + AIAccess(AIThreadSafeSimple& wrapper) : mWrapper(wrapper) { this->mWrapper.mMutex.lock(); } + + //! Access the underlaying object for (read and) write access. + T* operator->() const { return this->mWrapper.ptr(); } + + //! Access the underlaying object for (read and) write access. + T& operator*() const { return *this->mWrapper.ptr(); } + + ~AIAccess() { this->mWrapper.mMutex.unlock(); } + +protected: + AIThreadSafeSimple& mWrapper; //!< Reference to the object that we provide access to. + +private: + // Disallow copy constructing directly. + AIAccess(AIAccess const&); +}; + +#endif diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 8fa1b59ae..2146216aa 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -239,6 +239,101 @@ private: 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. + } +}; + //============================================================================ void LLThread::lockData() @@ -251,7 +346,6 @@ void LLThread::unlockData() mRunCondition->unlock(); } - //============================================================================ // see llmemory.h for LLPointer<> definition From 92696623e075df567c1c38610a7c66a25d891369 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 5 May 2011 15:41:19 +0200 Subject: [PATCH 16/16] Start up crash of LLErrorThread due to corrupt map in CheckLevelMap Wrapped gSettings and the global objects returned by Settings::get() and Globals::get() in AIThreadSafe, forcing thread-safe access. This solves the problem of possible corruption of the various LevelMap's in LLError::Settings due to thread unsafe accesses. --- doc/contributions.txt | 1 + indra/llcommon/llapp.cpp | 1 - indra/llcommon/llapp.h | 7 +- indra/llcommon/llerror.cpp | 324 ++++++++++----------- indra/llcommon/llerrorcontrol.h | 6 +- indra/llxml/llcontrol.cpp | 50 +++- indra/llxml/llcontrol.h | 12 +- indra/llxml/llcontrolgroupreader.h | 2 +- indra/newview/llappviewer.cpp | 41 ++- indra/newview/llappviewer.h | 12 +- indra/newview/llfloatersettingsdebug.cpp | 8 +- indra/newview/llstartup.cpp | 2 +- indra/newview/llviewercontrol.cpp | 4 +- indra/newview/llviewercontrol.h | 4 +- indra/newview/tests/llagentaccess_test.cpp | 2 +- 15 files changed, 261 insertions(+), 215 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index b5b84a45d..258e139bc 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -112,6 +112,7 @@ Aleric Inglewood IMP-664 IMP-670 IMP-701 + IMP-734 Alissa Sabre VWR-81 VWR-83 diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index d5e75c76f..3bb833a94 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -95,7 +95,6 @@ LLAppChildCallback LLApp::sDefaultChildCallback = NULL; LLApp::LLApp() : mThreadErrorp(NULL) { commonCtor(); - startErrorThread(); } void LLApp::commonCtor() diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index 77cb17c1a..d5cf6ea93 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -256,9 +256,12 @@ protected: */ void stepFrame(); -private: + /** + * @ brief This method is called once as soon as logging is initialized. + */ void startErrorThread(); - + +private: void setupErrorHandling(); // Do platform-specific error-handling setup (signals, structured exceptions) static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred. static void runSyncErrorHandler(); // run IMMEDIATELY when we get an error, ran in the context of the faulting thread. diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 56495e666..4cdfe097d 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -55,6 +55,7 @@ #include "llsdserialize.h" #include "llstl.h" #include "lltimer.h" +#include "aithreadsafe.h" extern apr_thread_mutex_t* gCallStacksLogMutexp; @@ -357,12 +358,15 @@ namespace void addCallSite(LLError::CallSite&); void invalidateCallSites(); - static Globals& get(); + static AIThreadSafeSimple& get(); // return the one instance of the globals private: CallSiteVector callSites; + friend class AIThreadSafeSimpleDC; // Calls constructor. + friend class AIThreadSafeSimple; // Calls destructor. + Globals() : messageStreamInUse(false) { } @@ -386,7 +390,7 @@ namespace callSites.clear(); } - Globals& Globals::get() + AIThreadSafeSimple& Globals::get() { /* This pattern, of returning a reference to a static function variable, is to ensure that this global is constructed before @@ -394,8 +398,8 @@ namespace is. See C++ FAQ Lite, sections 10.12 through 10.14 */ - static Globals* globals = new Globals; - return *globals; + static AIThreadSafeSimpleDCRootPool* ts_globals_ptr = new AIThreadSafeSimpleDCRootPool; + return *ts_globals_ptr; } } @@ -424,13 +428,16 @@ namespace LLError int shouldLogCallCounter; - static Settings& get(); + static AIThreadSafeSimple& get(); static void reset(); - static Settings* saveAndReset(); - static void restore(Settings*); + static AIThreadSafeSimple* saveAndReset(); + static void restore(AIThreadSafeSimple*); private: + friend class AIThreadSafeBits; // Calls destructor. + friend class AIThreadSafeSimpleDC; // Calls constructor. + Settings() : printLocation(false), defaultLevel(LLError::LEVEL_DEBUG), @@ -446,53 +453,42 @@ namespace LLError for_each(recorders.begin(), recorders.end(), DeletePointer()); } - - static Settings*& getPtr(); + + static AIThreadSafeSimple* sSettings; }; + + // Pointer to current AIThreadSafeSimple object if any (NULL otherwise). + AIThreadSafeSimple* Settings::sSettings; - Settings& Settings::get() + AIThreadSafeSimple& Settings::get() { - Settings* p = getPtr(); - if (!p) + if (!sSettings) { reset(); - p = getPtr(); } - return *p; + return *sSettings; } void Settings::reset() { - Globals::get().invalidateCallSites(); - - Settings*& p = getPtr(); - delete p; - p = new Settings(); + AIAccess(Globals::get())->invalidateCallSites(); + delete sSettings; + sSettings = new AIThreadSafeSimpleDC; } - Settings* Settings::saveAndReset() + AIThreadSafeSimple* Settings::saveAndReset() { - Globals::get().invalidateCallSites(); - - Settings*& p = getPtr(); - Settings* originalSettings = p; - p = new Settings(); + AIAccess(Globals::get())->invalidateCallSites(); + AIThreadSafeSimple* originalSettings = sSettings; + sSettings = new AIThreadSafeSimpleDC; return originalSettings; } - void Settings::restore(Settings* originalSettings) + void Settings::restore(AIThreadSafeSimple* originalSettings) { - Globals::get().invalidateCallSites(); - - Settings*& p = getPtr(); - delete p; - p = originalSettings; - } - - Settings*& Settings::getPtr() - { - static Settings* currentSettings = NULL; - return currentSettings; + AIAccess(Globals::get())->invalidateCallSites(); + delete sSettings; + sSettings = originalSettings; } } @@ -596,68 +592,64 @@ namespace LLError commonInit(dir); } + void setPrintLocation(AIAccess const& settings_w, bool print) + { + settings_w->printLocation = print; + } + void setPrintLocation(bool print) { - Settings& s = Settings::get(); - s.printLocation = print; + setPrintLocation(AIAccess(Settings::get()), print); } void setFatalFunction(const FatalFunction& f) { - Settings& s = Settings::get(); - s.crashFunction = f; + AIAccess(Settings::get())->crashFunction = f; } FatalFunction getFatalFunction() { - Settings& s = Settings::get(); - return s.crashFunction; + return AIAccess(Settings::get())->crashFunction; } void setTimeFunction(TimeFunction f) { - Settings& s = Settings::get(); - s.timeFunction = f; + AIAccess(Settings::get())->timeFunction = f; + } + + void setDefaultLevel(AIAccess const& settings_w, ELevel level) + { + AIAccess(Globals::get())->invalidateCallSites(); + settings_w->defaultLevel = level; } void setDefaultLevel(ELevel level) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); - g.invalidateCallSites(); - s.defaultLevel = level; + setDefaultLevel(AIAccess(Settings::get()), level); } void setFunctionLevel(const std::string& function_name, ELevel level) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); - g.invalidateCallSites(); - s.functionLevelMap[function_name] = level; + AIAccess(Globals::get())->invalidateCallSites(); + AIAccess(Settings::get())->functionLevelMap[function_name] = level; } void setClassLevel(const std::string& class_name, ELevel level) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); - g.invalidateCallSites(); - s.classLevelMap[class_name] = level; + AIAccess(Globals::get())->invalidateCallSites(); + AIAccess(Settings::get())->classLevelMap[class_name] = level; } void setFileLevel(const std::string& file_name, ELevel level) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); - g.invalidateCallSites(); - s.fileLevelMap[file_name] = level; + AIAccess(Globals::get())->invalidateCallSites(); + AIAccess(Settings::get())->fileLevelMap[file_name] = level; } void setTagLevel(const std::string& tag_name, ELevel level) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); - g.invalidateCallSites(); - s.tagLevelMap[tag_name] = level; + AIAccess(Globals::get())->invalidateCallSites(); + AIAccess(Settings::get())->tagLevelMap[tag_name] = level; } } @@ -701,18 +693,16 @@ namespace LLError { void configure(const LLSD& config) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); + AIAccess settings_w(Settings::get()); + AIAccess(Globals::get())->invalidateCallSites(); + settings_w->functionLevelMap.clear(); + settings_w->classLevelMap.clear(); + settings_w->fileLevelMap.clear(); + settings_w->tagLevelMap.clear(); + settings_w->uniqueLogMessages.clear(); - g.invalidateCallSites(); - s.functionLevelMap.clear(); - s.classLevelMap.clear(); - s.fileLevelMap.clear(); - s.tagLevelMap.clear(); - s.uniqueLogMessages.clear(); - - setPrintLocation(config["print-location"]); - setDefaultLevel(decodeLevel(config["default-level"])); + setPrintLocation(settings_w, config["print-location"]); + setDefaultLevel(settings_w, decodeLevel(config["default-level"])); LLSD sets = config["settings"]; LLSD::array_const_iterator a, end; @@ -722,10 +712,10 @@ namespace LLError ELevel level = decodeLevel(entry["level"]); - setLevels(s.functionLevelMap, entry["functions"], level); - setLevels(s.classLevelMap, entry["classes"], level); - setLevels(s.fileLevelMap, entry["files"], level); - setLevels(s.tagLevelMap, entry["tags"], level); + setLevels(settings_w->functionLevelMap, entry["functions"], level); + setLevels(settings_w->classLevelMap, entry["classes"], level); + setLevels(settings_w->fileLevelMap, entry["files"], level); + setLevels(settings_w->tagLevelMap, entry["tags"], level); } } } @@ -742,26 +732,34 @@ namespace LLError - void addRecorder(Recorder* recorder) + void addRecorder(AIAccess const& settings_w, Recorder* recorder) { if (recorder == NULL) { return; } - Settings& s = Settings::get(); - s.recorders.push_back(recorder); + settings_w->recorders.push_back(recorder); + } + + void addRecorder(Recorder* recorder) + { + addRecorder(AIAccess(Settings::get()), recorder); + } + + void removeRecorder(AIAccess const& settings_w, Recorder* recorder) + { + if (recorder == NULL) + { + return; + } + settings_w->recorders.erase( + std::remove(settings_w->recorders.begin(), settings_w->recorders.end(), recorder), + settings_w->recorders.end()); } void removeRecorder(Recorder* recorder) { - if (recorder == NULL) - { - return; - } - Settings& s = Settings::get(); - s.recorders.erase( - std::remove(s.recorders.begin(), s.recorders.end(), recorder), - s.recorders.end()); + removeRecorder(AIAccess(Settings::get()), recorder); } } @@ -769,12 +767,12 @@ namespace LLError { void logToFile(const std::string& file_name) { - LLError::Settings& s = LLError::Settings::get(); + AIAccess settings_w(Settings::get()); - removeRecorder(s.fileRecorder); - delete s.fileRecorder; - s.fileRecorder = NULL; - s.fileRecorderFileName.clear(); + removeRecorder(settings_w, settings_w->fileRecorder); + delete settings_w->fileRecorder; + settings_w->fileRecorder = NULL; + settings_w->fileRecorderFileName.clear(); if (file_name.empty()) { @@ -788,54 +786,51 @@ namespace LLError return; } - s.fileRecorderFileName = file_name; - s.fileRecorder = f; - addRecorder(f); + settings_w->fileRecorderFileName = file_name; + settings_w->fileRecorder = f; + addRecorder(settings_w, f); } void logToFixedBuffer(LLLineBuffer* fixedBuffer) { - LLError::Settings& s = LLError::Settings::get(); + AIAccess settings_w(Settings::get()); - removeRecorder(s.fixedBufferRecorder); - delete s.fixedBufferRecorder; - s.fixedBufferRecorder = NULL; + removeRecorder(settings_w, settings_w->fixedBufferRecorder); + delete settings_w->fixedBufferRecorder; + settings_w->fixedBufferRecorder = NULL; if (!fixedBuffer) { return; } - s.fixedBufferRecorder = new RecordToFixedBuffer(fixedBuffer); - addRecorder(s.fixedBufferRecorder); + settings_w->fixedBufferRecorder = new RecordToFixedBuffer(fixedBuffer); + addRecorder(settings_w, settings_w->fixedBufferRecorder); } std::string logFileName() { - LLError::Settings& s = LLError::Settings::get(); - return s.fileRecorderFileName; + return AIAccess(Settings::get())->fileRecorderFileName; } } namespace { - void writeToRecorders(LLError::ELevel level, const std::string& message) + void writeToRecorders(AIAccess const& settings_w, LLError::ELevel level, const std::string& message) { - LLError::Settings& s = LLError::Settings::get(); - std::string messageWithTime; - - for (Recorders::const_iterator i = s.recorders.begin(); - i != s.recorders.end(); + + for (Recorders::const_iterator i = settings_w->recorders.begin(); + i != settings_w->recorders.end(); ++i) { LLError::Recorder* r = *i; - if (r->wantsTime() && s.timeFunction != NULL) + if (r->wantsTime() && settings_w->timeFunction != NULL) { if (messageWithTime.empty()) { - messageWithTime = s.timeFunction() + " " + message; + messageWithTime = settings_w->timeFunction() + " " + message; } r->recordMessage(level, messageWithTime); @@ -955,10 +950,9 @@ namespace LLError return false; } - Globals& g = Globals::get(); - Settings& s = Settings::get(); + AIAccess settings_w(Settings::get()); - s.shouldLogCallCounter += 1; + settings_w->shouldLogCallCounter += 1; std::string class_name = className(site.mClassInfo); std::string function_name = functionName(site.mFunction); @@ -967,20 +961,20 @@ namespace LLError function_name = class_name + "::" + function_name; } - ELevel compareLevel = s.defaultLevel; + ELevel compareLevel = settings_w->defaultLevel; // The most specific match found will be used as the log level, // since the computation short circuits. // So, in increasing order of importance: // Default < Broad Tag < File < Class < Function < Narrow Tag - ((site.mNarrowTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mNarrowTag, compareLevel) : false) - || checkLevelMap(s.functionLevelMap, function_name, compareLevel) - || checkLevelMap(s.classLevelMap, class_name, compareLevel) - || checkLevelMap(s.fileLevelMap, abbreviateFile(site.mFile), compareLevel) - || ((site.mBroadTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mBroadTag, compareLevel) : false); + ((site.mNarrowTag != NULL) ? checkLevelMap(settings_w->tagLevelMap, site.mNarrowTag, compareLevel) : false) + || checkLevelMap(settings_w->functionLevelMap, function_name, compareLevel) + || checkLevelMap(settings_w->classLevelMap, class_name, compareLevel) + || checkLevelMap(settings_w->fileLevelMap, abbreviateFile(site.mFile), compareLevel) + || ((site.mBroadTag != NULL) ? checkLevelMap(settings_w->tagLevelMap, site.mBroadTag, compareLevel) : false); site.mCached = true; - g.addCallSite(site); + AIAccess(Globals::get())->addCallSite(site); return site.mShouldLog = site.mLevel >= compareLevel; } @@ -990,16 +984,16 @@ namespace LLError LogLock lock; if (lock.ok()) { - Globals& g = Globals::get(); + AIAccess globals(Globals::get()); - if (!g.messageStreamInUse) + if (!globals->messageStreamInUse) { - g.messageStreamInUse = true; - return &g.messageStream; + globals->messageStreamInUse = true; + return &globals->messageStream; // Returns pointer to member of unlocked object, apparently "protected" by having set globals->messageStreamInUse. } } - return new std::ostringstream; + return new std::ostringstream; // Holy memory leak. } void Log::flush(std::ostringstream* out, char* message) @@ -1020,12 +1014,12 @@ namespace LLError message[127] = '\0' ; } - Globals& g = Globals::get(); - if (out == &g.messageStream) + AIAccess globals(Globals::get()); + if (out == &globals->messageStream) { - g.messageStream.clear(); - g.messageStream.str(""); - g.messageStreamInUse = false; + globals->messageStream.clear(); + globals->messageStream.str(""); + globals->messageStreamInUse = false; } else { @@ -1042,28 +1036,31 @@ namespace LLError return; } - Globals& g = Globals::get(); - Settings& s = Settings::get(); - std::string message = out->str(); - if (out == &g.messageStream) + { - g.messageStream.clear(); - g.messageStream.str(""); - g.messageStreamInUse = false; - } - else - { - delete out; + AIAccess globals(Globals::get()); + if (out == &globals->messageStream) + { + globals->messageStream.clear(); + globals->messageStream.str(""); + globals->messageStreamInUse = false; + } + else + { + delete out; + } } + AIAccess settings_w(Settings::get()); + if (site.mLevel == LEVEL_ERROR) { std::ostringstream fatalMessage; fatalMessage << abbreviateFile(site.mFile) << "(" << site.mLine << ") : error"; - writeToRecorders(site.mLevel, fatalMessage.str()); + writeToRecorders(settings_w, site.mLevel, fatalMessage.str()); } @@ -1078,7 +1075,7 @@ namespace LLError default: prefix << "XXX: "; break; }; - if (s.printLocation) + if (settings_w->printLocation) { prefix << abbreviateFile(site.mFile) << "(" << site.mLine << ") : "; @@ -1096,8 +1093,8 @@ namespace LLError if (site.mPrintOnce) { - std::map::iterator messageIter = s.uniqueLogMessages.find(message); - if (messageIter != s.uniqueLogMessages.end()) + std::map::iterator messageIter = settings_w->uniqueLogMessages.find(message); + if (messageIter != settings_w->uniqueLogMessages.end()) { messageIter->second++; unsigned int num_messages = messageIter->second; @@ -1113,14 +1110,14 @@ namespace LLError else { prefix << "ONCE: "; - s.uniqueLogMessages[message] = 1; + settings_w->uniqueLogMessages[message] = 1; } } if (site.mPrintOnce) { - std::map::iterator messageIter = s.uniqueLogMessages.find(message); - if (messageIter != s.uniqueLogMessages.end()) + std::map::iterator messageIter = settings_w->uniqueLogMessages.find(message); + if (messageIter != settings_w->uniqueLogMessages.end()) { messageIter->second++; unsigned int num_messages = messageIter->second; @@ -1136,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); } } } @@ -1157,14 +1154,16 @@ namespace LLError namespace LLError { - Settings* saveAndResetSettings() + class ThreadSafeSettings { }; + + ThreadSafeSettings* saveAndResetSettings() { - return Settings::saveAndReset(); + return reinterpret_cast(Settings::saveAndReset()); } - void restoreSettings(Settings* s) + void restoreSettings(ThreadSafeSettings* s) { - return Settings::restore(s); + Settings::restore(reinterpret_cast*>(s)); } std::string removePrefix(std::string& s, const std::string& p) @@ -1210,8 +1209,7 @@ namespace LLError int shouldLogCallCount() { - Settings& s = Settings::get(); - return s.shouldLogCallCounter; + return AIAccess(Settings::get())->shouldLogCallCounter; } #if LL_WINDOWS diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index 2a7c500db..c6eb39cae 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -167,9 +167,9 @@ namespace LLError Utilities for use by the unit tests of LLError itself. */ - class Settings; - LL_COMMON_API Settings* saveAndResetSettings(); - LL_COMMON_API void restoreSettings(Settings *); + class ThreadSafeSettings; + LL_COMMON_API ThreadSafeSettings* saveAndResetSettings(); + LL_COMMON_API void restoreSettings(ThreadSafeSettings *); LL_COMMON_API std::string abbreviateFile(const std::string& filePath); LL_COMMON_API int shouldLogCallCount(); diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index f57646b8e..3e6b1d0e4 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -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> gSettingsCallMap; -#endif //PROF_CTRL_CALLS -LLPointer 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>::iterator iter2 = gSettingsCallMap.begin(); @@ -302,13 +313,32 @@ LLPointer LLControlGroup::getControl(const std::string& name) if(iter2 == gSettingsCallMap.end()) gSettingsCallMap.push_back(std::pair(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(); + 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(); } diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index 38c0be773..e5cbf7354 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -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 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 diff --git a/indra/llxml/llcontrolgroupreader.h b/indra/llxml/llcontrolgroupreader.h index c4c04b98b..ef8ee18c9 100644 --- a/indra/llxml/llcontrolgroupreader.h +++ b/indra/llxml/llcontrolgroupreader.h @@ -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; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 18715632e..1e3e80644 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -568,7 +568,10 @@ bool LLAppViewer::init() gDirUtilp->setSkinFolder("default"); initLogging(); - + + // Logging is initialized. Now it's safe to start the error thread. + startErrorThread(); + // gDeleteScheduler = new LLDeleteScheduler(); gBuildNewViewsScheduler = new LLBuildNewViewsScheduler(); @@ -1578,8 +1581,9 @@ bool LLAppViewer::initLogging() return true; } -bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, - bool set_defaults) +bool LLAppViewer::loadSettingsFromDirectory(AIReadAccess const& settings_r, + std::string const& location_key, + bool set_defaults) { // Find and vet the location key. if(!mSettingsLocationList.has(location_key)) @@ -1606,11 +1610,13 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, LLSD files = location.get("Files"); for(LLSD::map_iterator itr = files.beginMap(); itr != files.endMap(); ++itr) { - std::string settings_group = (*itr).first; + std::string const settings_group = (*itr).first; + settings_map_type::const_iterator const settings_group_iter = settings_r->find(settings_group); + llinfos << "Attempting to load settings for the group " << settings_group << " - from location " << location_key << llendl; - if(gSettings.find(settings_group) == gSettings.end()) + if(settings_group_iter == settings_r->end()) { llwarns << "No matching settings group for name " << settings_group << llendl; continue; @@ -1624,11 +1630,10 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, std::string custom_name_setting = file.get("NameFromSetting"); // *NOTE: Regardless of the group currently being lodaed, // this setting is always read from the Global settings. - if(gSettings[sGlobalSettingsName]->controlExists(custom_name_setting)) + LLControlGroup const* control_group = settings_r->find(sGlobalSettingsName)->second; + if(control_group->controlExists(custom_name_setting)) { - std::string file_name = - gSettings[sGlobalSettingsName]->getString(custom_name_setting); - full_settings_path = file_name; + full_settings_path = control_group->getString(custom_name_setting); } } @@ -1644,7 +1649,7 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, requirement = file.get("Requirement").asInteger(); } - if(!gSettings[settings_group]->loadFromFile(full_settings_path, set_defaults)) + if(!settings_group_iter->second->loadFromFile(full_settings_path, set_defaults)) { if(requirement == 1) { @@ -1686,10 +1691,14 @@ std::string LLAppViewer::getSettingsFilename(const std::string& location_key, bool LLAppViewer::initConfiguration() { + // Grab and hold write locks for the entire duration of this function. + AIWriteAccess settings_w(gSettings); + settings_map_type& settings(*settings_w); + //Set up internal pointers - gSettings[sGlobalSettingsName] = &gSavedSettings; - gSettings[sPerAccountSettingsName] = &gSavedPerAccountSettings; - gSettings[sCrashSettingsName] = &gCrashSettings; + settings[sGlobalSettingsName] = &gSavedSettings; + settings[sPerAccountSettingsName] = &gSavedPerAccountSettings; + settings[sCrashSettingsName] = &gCrashSettings; //Load settings files list std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml"); @@ -1714,7 +1723,7 @@ bool LLAppViewer::initConfiguration() // - load defaults bool set_defaults = true; - if(!loadSettingsFromDirectory("Default", set_defaults)) + if(!loadSettingsFromDirectory(settings_w, "Default", set_defaults)) { std::ostringstream msg; msg << "Second Life could not load its default settings file. \n" @@ -1830,7 +1839,7 @@ bool LLAppViewer::initConfiguration() } // - load overrides from user_settings - loadSettingsFromDirectory("User"); + loadSettingsFromDirectory(settings_w, "User"); // - apply command line settings clp.notify(); @@ -1910,7 +1919,7 @@ bool LLAppViewer::initConfiguration() { const std::string& name = *itr; const std::string& value = *(++itr); - LLControlVariable* c = gSettings[sGlobalSettingsName]->getControl(name); + LLControlVariable* c = settings[sGlobalSettingsName]->getControl(name); if(c) { c->setValue(value, false); diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 14a39a6f9..933d4150a 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -33,7 +33,8 @@ #ifndef LL_LLAPPVIEWER_H #define LL_LLAPPVIEWER_H -#include "llsys.h" // LLOSInfo +#include "llsys.h" // LLOSInfo +#include "llviewercontrol.h" // settings_map_type class LLTextureCache; class LLImageDecodeThread; @@ -140,11 +141,12 @@ public: // Load settings from the location specified by loction_key. // Key availale and rules for loading, are specified in // 'app_settings/settings_files.xml' - bool loadSettingsFromDirectory(const std::string& location_key, - bool set_defaults = false); + bool loadSettingsFromDirectory(AIReadAccess const& settings_r, + std::string const& location_key, + bool set_defaults = false); - std::string getSettingsFilename(const std::string& location_key, - const std::string& file); + std::string getSettingsFilename(std::string const& location_key, + std::string const& file); // For thread debugging. // llstartup needs to control init. diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index 7e0557d17..2d7ce1da4 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -104,7 +104,7 @@ BOOL LLFloaterSettingsDebug::postBuild() void LLFloaterSettingsDebug::draw() { LLComboBox* settings_combo = getChild("settings_combo"); - LLControlVariable* controlp = (LLControlVariable*)settings_combo->getCurrentUserdata(); + LLControlVariable* controlp = static_cast(settings_combo->getCurrentUserdata()); updateControl(controlp ? controlp->getCOAActive() : NULL); LLFloater::draw(); @@ -127,8 +127,8 @@ void LLFloaterSettingsDebug::show(void*) void LLFloaterSettingsDebug::onSettingSelect(LLUICtrl* ctrl, void* user_data) { LLFloaterSettingsDebug* floaterp = (LLFloaterSettingsDebug*)user_data; - LLComboBox* combo_box = (LLComboBox*)ctrl; - LLControlVariable* controlp = (LLControlVariable*)combo_box->getCurrentUserdata(); + LLComboBox* combo_box = static_cast(ctrl); + LLControlVariable* controlp = static_cast(combo_box->getCurrentUserdata()); floaterp->updateControl(controlp ? controlp->getCOAActive() : NULL); } @@ -139,7 +139,7 @@ void LLFloaterSettingsDebug::onCommitSettings(LLUICtrl* ctrl, void* user_data) LLFloaterSettingsDebug* floaterp = (LLFloaterSettingsDebug*)user_data; LLComboBox* settings_combo = floaterp->getChild("settings_combo"); - LLControlVariable* controlp = (LLControlVariable*)settings_combo->getCurrentUserdata(); + LLControlVariable* controlp = static_cast(settings_combo->getCurrentUserdata()); controlp = controlp ? controlp->getCOAActive() : NULL; if(!controlp)//Uh oh! return; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 519ce8d87..e08bc301a 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -985,7 +985,7 @@ bool idle_startup() ); // Overwrite default user settings with user settings - LLAppViewer::instance()->loadSettingsFromDirectory("Account"); + LLAppViewer::instance()->loadSettingsFromDirectory(AIReadAccess(gSettings), "Account"); // Need to set the LastLogoff time here if we don't have one. LastLogoff is used for "Recent Items" calculation // and startup time is close enough if we don't have a real value. diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 22609c938..23c9535fa 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -75,6 +75,7 @@ #include "llnetmap.h" #include "llrender.h" #include "llfloaterchat.h" +#include "aithreadsafe.h" #include "llviewerobjectlist.h" #include "lldrawpoolbump.h" #include "emeraldboobutils.h" @@ -83,8 +84,7 @@ BOOL gHackGodmode = FALSE; #endif - -std::map gSettings; +AITHREADSAFE(settings_map_type, gSettings,); LLControlGroup gSavedSettings; // saved at end of session LLControlGroup gSavedPerAccountSettings; // saved at end of session LLControlGroup gColors; // read-only diff --git a/indra/newview/llviewercontrol.h b/indra/newview/llviewercontrol.h index 9c2e112c9..8835146ad 100644 --- a/indra/newview/llviewercontrol.h +++ b/indra/newview/llviewercontrol.h @@ -36,6 +36,7 @@ #include #include "llcontrol.h" #include "lluictrl.h" +#include "aithreadsafe.h" // Enabled this definition to compile a 'hacked' viewer that // allows a hacked godmode to be toggled on and off. @@ -48,7 +49,8 @@ extern BOOL gHackGodmode; //setting variables are declared in this function void settings_setup_listeners(); -extern std::map gSettings; +typedef std::map settings_map_type; +extern AIThreadSafe gSettings; // for the graphics settings void create_graphics_group(LLControlGroup& group); diff --git a/indra/newview/tests/llagentaccess_test.cpp b/indra/newview/tests/llagentaccess_test.cpp index 5c31afb64..750c9faa5 100644 --- a/indra/newview/tests/llagentaccess_test.cpp +++ b/indra/newview/tests/llagentaccess_test.cpp @@ -43,7 +43,7 @@ class LLControlGroupReader_Test : public LLControlGroupReader public: LLControlGroupReader_Test() : test_preferred_maturity(SIM_ACCESS_PG) {} - virtual std::string getString(const std::string& name) + virtual std::string getString(const std::string& name) const { return ""; }