summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt2
-rw-r--r--indra/llcommon/llassettype.cpp4
-rw-r--r--indra/llcommon/llerrorcontrol.h1
-rw-r--r--indra/llcommon/llfasttimer.h124
-rw-r--r--indra/llcommon/llmetrics.cpp2
-rw-r--r--indra/llcommon/llprocesslauncher.cpp344
-rw-r--r--indra/llcommon/llprocesslauncher.h85
-rw-r--r--indra/llcommon/llrefcount.h7
-rw-r--r--indra/llcommon/llsd.cpp10
-rw-r--r--indra/llcommon/llstring.cpp3
-rw-r--r--indra/llcommon/llstring.h124
11 files changed, 566 insertions, 140 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 7fe4491a8b..af573a7e6c 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -64,6 +64,7 @@ set(llcommon_SOURCE_FILES
llmetrics.cpp
llmortician.cpp
llptrto.cpp
+ llprocesslauncher.cpp
llprocessor.cpp
llqueuedthread.cpp
llrand.cpp
@@ -176,6 +177,7 @@ set(llcommon_HEADER_FILES
llpointer.h
llpreprocessor.h
llpriqueuemap.h
+ llprocesslauncher.h
llprocessor.h
llptrskiplist.h
llptrskipmap.h
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp
index 835cdbca04..e595cc1f8b 100644
--- a/indra/llcommon/llassettype.cpp
+++ b/indra/llcommon/llassettype.cpp
@@ -101,7 +101,7 @@ LLAssetDictionary::LLAssetDictionary()
addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", "Uncompressed Images", DAD_NONE, FALSE, TRUE));
addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", "Uncompressed Images", DAD_NONE, FALSE, TRUE));
addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", "Animations", DAD_ANIMATION, FALSE, TRUE));
- addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", "Gestures", DAD_GESTURE, FALSE, TRUE));
+ addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", "Gestures", DAD_GESTURE, TRUE, TRUE));
addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", "New Folder", DAD_NONE, FALSE, TRUE));
addEntry(LLAssetType::AT_FAVORITE, new AssetEntry("FAVORITE", "favorite", "favorite", "favorite", DAD_NONE, FALSE, TRUE));
@@ -116,7 +116,7 @@ LLAssetDictionary::LLAssetDictionary()
}
addEntry(LLAssetType::AT_CURRENT_OUTFIT, new AssetEntry("CURRENT", "current", "current outfit", "Current Outfit", DAD_CATEGORY, FALSE, TRUE));
- addEntry(LLAssetType::AT_OUTFIT, new AssetEntry("OUTFIT", "outfit", "outfit", "Outfit", DAD_CATEGORY, TRUE, FALSE));
+ addEntry(LLAssetType::AT_OUTFIT, new AssetEntry("OUTFIT", "outfit", "outfit", "New Outfit", DAD_CATEGORY, TRUE, FALSE));
addEntry(LLAssetType::AT_MY_OUTFITS, new AssetEntry("MY_OUTFITS", "my_otfts", "my outfits", "My Outfits", DAD_CATEGORY, FALSE, TRUE));
addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, "New Folder", DAD_NONE, FALSE, FALSE));
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index 1a559ed7e0..c84f5d0fd7 100644
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -73,6 +73,7 @@ namespace LLError
LL_COMMON_API void setFunctionLevel(const std::string& function_name, LLError::ELevel);
LL_COMMON_API void setClassLevel(const std::string& class_name, LLError::ELevel);
LL_COMMON_API void setFileLevel(const std::string& file_name, LLError::ELevel);
+ void setTagLevel(const std::string& file_name, LLError::ELevel);
LL_COMMON_API void configure(const LLSD&);
// the LLSD can configure all of the settings
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 0488585fd4..6ea9762546 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -69,13 +69,13 @@ public:
std::vector<NamedTimer*>& getChildren();
void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
- bool getCollapsed() { return mCollapsed; }
+ bool getCollapsed() const { return mCollapsed; }
- U64 getCountAverage() { return mCountAverage; }
- U64 getCallAverage() { return mCallAverage; }
+ U64 getCountAverage() const { return mCountAverage; }
+ U64 getCallAverage() const { return mCallAverage; }
- U64 getHistoricalCount(S32 history_index = 0);
- U64 getHistoricalCalls(S32 history_index = 0);
+ U64 getHistoricalCount(S32 history_index = 0) const;
+ U64 getHistoricalCalls(S32 history_index = 0) const;
static NamedTimer& getRootNamedTimer();
@@ -162,117 +162,6 @@ public:
NamedTimer& mNamedTimer;
};
- static DeclareTimer FTM_ARRANGE;
- static DeclareTimer FTM_ATTACHMENT_UPDATE;
- static DeclareTimer FTM_AUDIO_UPDATE;
- static DeclareTimer FTM_AUTO_SELECT;
- static DeclareTimer FTM_AVATAR_UPDATE;
- static DeclareTimer FTM_CLEANUP;
- static DeclareTimer FTM_CLIENT_COPY;
- static DeclareTimer FTM_CREATE_OBJECT;
- static DeclareTimer FTM_CULL;
- static DeclareTimer FTM_CULL_REBOUND;
- static DeclareTimer FTM_FILTER;
- static DeclareTimer FTM_FLEXIBLE_UPDATE;
- static DeclareTimer FTM_FRAME;
- static DeclareTimer FTM_FRUSTUM_CULL;
- static DeclareTimer FTM_GEN_FLEX;
- static DeclareTimer FTM_GEN_TRIANGLES;
- static DeclareTimer FTM_GEN_VOLUME;
- static DeclareTimer FTM_GEO_SKY;
- static DeclareTimer FTM_GEO_UPDATE;
- static DeclareTimer FTM_HUD_EFFECTS;
- static DeclareTimer FTM_HUD_UPDATE;
- static DeclareTimer FTM_IDLE;
- static DeclareTimer FTM_IDLE_CB;
- static DeclareTimer FTM_IDLE_NETWORK;
- static DeclareTimer FTM_IMAGE_CREATE;
- static DeclareTimer FTM_IMAGE_MARK_DIRTY;
- static DeclareTimer FTM_IMAGE_UPDATE;
- static DeclareTimer FTM_INVENTORY;
- static DeclareTimer FTM_JOINT_UPDATE;
- static DeclareTimer FTM_KEYHANDLER;
- static DeclareTimer FTM_LOAD_AVATAR;
- static DeclareTimer FTM_LOD_UPDATE;
- static DeclareTimer FTM_MESSAGES;
- static DeclareTimer FTM_MOUSEHANDLER;
- static DeclareTimer FTM_NETWORK;
- static DeclareTimer FTM_OBJECTLIST_UPDATE;
- static DeclareTimer FTM_OCCLUSION_READBACK;
- static DeclareTimer FTM_OCTREE_BALANCE;
- static DeclareTimer FTM_PICK;
- static DeclareTimer FTM_PIPELINE;
- static DeclareTimer FTM_POOLRENDER;
- static DeclareTimer FTM_POOLS;
- static DeclareTimer FTM_PROCESS_IMAGES;
- static DeclareTimer FTM_PROCESS_MESSAGES;
- static DeclareTimer FTM_PROCESS_OBJECTS;
- static DeclareTimer FTM_PUMP;
- static DeclareTimer FTM_REBUILD_GRASS_VB;
- static DeclareTimer FTM_REBUILD_PARTICLE_VB;
- static DeclareTimer FTM_REBUILD_TERRAIN_VB;
- static DeclareTimer FTM_REBUILD_VBO;
- static DeclareTimer FTM_REBUILD_VOLUME_VB;
- static DeclareTimer FTM_REFRESH;
- static DeclareTimer FTM_REGION_UPDATE;
- static DeclareTimer FTM_RENDER;
- static DeclareTimer FTM_RENDER_ALPHA;
- static DeclareTimer FTM_RENDER_BLOOM;
- static DeclareTimer FTM_RENDER_BLOOM_FBO;
- static DeclareTimer FTM_RENDER_BUMP;
- static DeclareTimer FTM_RENDER_CHARACTERS;
- static DeclareTimer FTM_RENDER_FAKE_VBO_UPDATE;
- static DeclareTimer FTM_RENDER_FONTS;
- static DeclareTimer FTM_RENDER_FULLBRIGHT;
- static DeclareTimer FTM_RENDER_GEOMETRY;
- static DeclareTimer FTM_RENDER_GLOW;
- static DeclareTimer FTM_RENDER_GRASS;
- static DeclareTimer FTM_RENDER_INVISIBLE;
- static DeclareTimer FTM_RENDER_OCCLUSION;
- static DeclareTimer FTM_RENDER_SHINY;
- static DeclareTimer FTM_RENDER_SIMPLE;
- static DeclareTimer FTM_RENDER_TERRAIN;
- static DeclareTimer FTM_RENDER_TREES;
- static DeclareTimer FTM_RENDER_UI;
- static DeclareTimer FTM_RENDER_WATER;
- static DeclareTimer FTM_RENDER_WL_SKY;
- static DeclareTimer FTM_RESET_DRAWORDER;
- static DeclareTimer FTM_SHADOW_ALPHA;
- static DeclareTimer FTM_SHADOW_AVATAR;
- static DeclareTimer FTM_SHADOW_RENDER;
- static DeclareTimer FTM_SHADOW_SIMPLE;
- static DeclareTimer FTM_SHADOW_TERRAIN;
- static DeclareTimer FTM_SHADOW_TREE;
- static DeclareTimer FTM_SIMULATE_PARTICLES;
- static DeclareTimer FTM_SLEEP;
- static DeclareTimer FTM_SORT;
- static DeclareTimer FTM_STATESORT;
- static DeclareTimer FTM_STATESORT_DRAWABLE;
- static DeclareTimer FTM_STATESORT_POSTSORT;
- static DeclareTimer FTM_SWAP;
- static DeclareTimer FTM_TEMP1;
- static DeclareTimer FTM_TEMP2;
- static DeclareTimer FTM_TEMP3;
- static DeclareTimer FTM_TEMP4;
- static DeclareTimer FTM_TEMP5;
- static DeclareTimer FTM_TEMP6;
- static DeclareTimer FTM_TEMP7;
- static DeclareTimer FTM_TEMP8;
- static DeclareTimer FTM_UPDATE_ANIMATION;
- static DeclareTimer FTM_UPDATE_AVATAR;
- static DeclareTimer FTM_UPDATE_CLOUDS;
- static DeclareTimer FTM_UPDATE_GRASS;
- static DeclareTimer FTM_UPDATE_MOVE;
- static DeclareTimer FTM_UPDATE_PARTICLES;
- static DeclareTimer FTM_UPDATE_PRIMITIVES;
- static DeclareTimer FTM_UPDATE_SKY;
- static DeclareTimer FTM_UPDATE_TERRAIN;
- static DeclareTimer FTM_UPDATE_TEXTURES;
- static DeclareTimer FTM_UPDATE_TREE;
- static DeclareTimer FTM_UPDATE_WATER;
- static DeclareTimer FTM_UPDATE_WLPARAM;
- static DeclareTimer FTM_VFILE_WAIT;
- static DeclareTimer FTM_WORLD_UPDATE;
public:
enum RootTimerMarker { ROOT };
@@ -287,6 +176,7 @@ public:
LLFastTimer(NamedTimer::FrameState& timer)
: mFrameState(&timer)
{
+#if FAST_TIMER_ON
NamedTimer::FrameState* frame_state = mFrameState;
frame_state->mLastStartTime = get_cpu_clock_count();
mStartSelfTime = frame_state->mLastStartTime;
@@ -298,6 +188,7 @@ public:
mLastTimer = sCurTimer;
sCurTimer = this;
+#endif
}
~LLFastTimer()
@@ -332,6 +223,7 @@ public:
static S32 getCurFrameIndex() { return sCurFrameIndex; }
static void writeLog(std::ostream& os);
+ static const NamedTimer* getTimerByName(const std::string& name);
public:
static bool sPauseHistory;
diff --git a/indra/llcommon/llmetrics.cpp b/indra/llcommon/llmetrics.cpp
index 8db3284c42..30e5d435ae 100644
--- a/indra/llcommon/llmetrics.cpp
+++ b/indra/llcommon/llmetrics.cpp
@@ -71,7 +71,7 @@ void LLMetricsImpl::recordEventDetails(const std::string& location,
metrics["location"] = location;
metrics["stats"] = stats;
- llinfos << "LLMETRICS: " << LLSDNotationStreamer(metrics) << llendl;
+ llinfos << "LLMETRICS: " << (LLSDNotationStreamer(metrics)) << llendl;
}
// Store this:
diff --git a/indra/llcommon/llprocesslauncher.cpp b/indra/llcommon/llprocesslauncher.cpp
new file mode 100644
index 0000000000..f0315e92eb
--- /dev/null
+++ b/indra/llcommon/llprocesslauncher.cpp
@@ -0,0 +1,344 @@
+/**
+ * @file llprocesslauncher.cpp
+ * @brief Utility class for launching, terminating, and tracking the state of processes.
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ *
+ * Copyright (c) 2008, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llprocesslauncher.h"
+
+#include <iostream>
+#if LL_DARWIN || LL_LINUX
+// not required or present on Win32
+#include <sys/wait.h>
+#endif
+
+LLProcessLauncher::LLProcessLauncher()
+{
+#if LL_WINDOWS
+ mProcessHandle = 0;
+#else
+ mProcessID = 0;
+#endif
+}
+
+LLProcessLauncher::~LLProcessLauncher()
+{
+ kill();
+}
+
+void LLProcessLauncher::setExecutable(const std::string &executable)
+{
+ mExecutable = executable;
+}
+
+void LLProcessLauncher::setWorkingDirectory(const std::string &dir)
+{
+ mWorkingDir = dir;
+}
+
+void LLProcessLauncher::clearArguments()
+{
+ mLaunchArguments.clear();
+}
+
+void LLProcessLauncher::addArgument(const std::string &arg)
+{
+ mLaunchArguments.push_back(arg);
+}
+
+void LLProcessLauncher::addArgument(const char *arg)
+{
+ mLaunchArguments.push_back(std::string(arg));
+}
+
+#if LL_WINDOWS
+
+int LLProcessLauncher::launch(void)
+{
+ // If there was already a process associated with this object, kill it.
+ kill();
+ orphan();
+
+ int result = 0;
+
+ PROCESS_INFORMATION pinfo;
+ STARTUPINFOA sinfo;
+ memset(&sinfo, 0, sizeof(sinfo));
+
+ std::string args = mExecutable;
+ for(int i = 0; i < (int)mLaunchArguments.size(); i++)
+ {
+ args += " ";
+ args += mLaunchArguments[i];
+ }
+
+ // So retarded. Windows requires that the second parameter to CreateProcessA be a writable (non-const) string...
+ char *args2 = new char[args.size() + 1];
+ strcpy(args2, args.c_str());
+
+ if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo ) )
+ {
+ // TODO: do better than returning the OS-specific error code on failure...
+ result = GetLastError();
+ if(result == 0)
+ {
+ // Make absolutely certain we return a non-zero value on failure.
+ result = -1;
+ }
+ }
+ else
+ {
+ // foo = pinfo.dwProcessId; // get your pid here if you want to use it later on
+ // CloseHandle(pinfo.hProcess); // stops leaks - nothing else
+ mProcessHandle = pinfo.hProcess;
+ CloseHandle(pinfo.hThread); // stops leaks - nothing else
+ }
+
+ delete[] args2;
+
+ return result;
+}
+
+bool LLProcessLauncher::isRunning(void)
+{
+ if(mProcessHandle != 0)
+ {
+ DWORD waitresult = WaitForSingleObject(mProcessHandle, 0);
+ if(waitresult == WAIT_OBJECT_0)
+ {
+ // the process has completed.
+ mProcessHandle = 0;
+ }
+ }
+
+ return (mProcessHandle != 0);
+}
+bool LLProcessLauncher::kill(void)
+{
+ bool result = true;
+
+ if(mProcessHandle != 0)
+ {
+ TerminateProcess(mProcessHandle,0);
+
+ if(isRunning())
+ {
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+void LLProcessLauncher::orphan(void)
+{
+ // Forget about the process
+ mProcessHandle = 0;
+}
+
+// static
+void LLProcessLauncher::reap(void)
+{
+ // No actions necessary on Windows.
+}
+
+#else // Mac and linux
+
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+
+static std::list<pid_t> sZombies;
+
+// Attempt to reap a process ID -- returns true if the process has exited and been reaped, false otherwise.
+static bool reap_pid(pid_t pid)
+{
+ bool result = false;
+
+ pid_t wait_result = ::waitpid(pid, NULL, WNOHANG);
+ if(wait_result == pid)
+ {
+ result = true;
+ }
+ else if(wait_result == -1)
+ {
+ if(errno == ECHILD)
+ {
+ // No such process -- this may mean we're ignoring SIGCHILD.
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+int LLProcessLauncher::launch(void)
+{
+ // If there was already a process associated with this object, kill it.
+ kill();
+ orphan();
+
+ int result = 0;
+ int current_wd = -1;
+
+ // create an argv vector for the child process
+ const char ** fake_argv = new const char *[mLaunchArguments.size() + 2]; // 1 for the executable path, 1 for the NULL terminator
+
+ int i = 0;
+
+ // add the executable path
+ fake_argv[i++] = mExecutable.c_str();
+
+ // and any arguments
+ for(int j=0; j < mLaunchArguments.size(); j++)
+ fake_argv[i++] = mLaunchArguments[j].c_str();
+
+ // terminate with a null pointer
+ fake_argv[i] = NULL;
+
+ if(!mWorkingDir.empty())
+ {
+ // save the current working directory
+ current_wd = ::open(".", O_RDONLY);
+
+ // and change to the one the child will be executed in
+ if (::chdir(mWorkingDir.c_str()))
+ {
+ // chdir failed
+ }
+ }
+
+ // flush all buffers before the child inherits them
+ ::fflush(NULL);
+
+ pid_t id = vfork();
+ if(id == 0)
+ {
+ // child process
+
+ ::execv(mExecutable.c_str(), (char * const *)fake_argv);
+
+ // If we reach this point, the exec failed.
+ // Use _exit() instead of exit() per the vfork man page.
+ _exit(0);
+ }
+
+ // parent process
+
+ if(current_wd >= 0)
+ {
+ // restore the previous working directory
+ if (::fchdir(current_wd))
+ {
+ // chdir failed
+ }
+ ::close(current_wd);
+ }
+
+ delete[] fake_argv;
+
+ mProcessID = id;
+
+ // At this point, the child process will have been created (since that's how vfork works -- the child borrowed our execution context until it forked)
+ // If the process doesn't exist at this point, the exec failed.
+ if(!isRunning())
+ {
+ result = -1;
+ }
+
+ return result;
+}
+
+bool LLProcessLauncher::isRunning(void)
+{
+ if(mProcessID != 0)
+ {
+ // Check whether the process has exited, and reap it if it has.
+ if(reap_pid(mProcessID))
+ {
+ // the process has exited.
+ mProcessID = 0;
+ }
+ }
+
+ return (mProcessID != 0);
+}
+
+bool LLProcessLauncher::kill(void)
+{
+ bool result = true;
+
+ if(mProcessID != 0)
+ {
+ // Try to kill the process. We'll do approximately the same thing whether the kill returns an error or not, so we ignore the result.
+ (void)::kill(mProcessID, SIGTERM);
+
+ // This will have the side-effect of reaping the zombie if the process has exited.
+ if(isRunning())
+ {
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+void LLProcessLauncher::orphan(void)
+{
+ // Disassociate the process from this object
+ if(mProcessID != 0)
+ {
+ // We may still need to reap the process's zombie eventually
+ sZombies.push_back(mProcessID);
+
+ mProcessID = 0;
+ }
+}
+
+// static
+void LLProcessLauncher::reap(void)
+{
+ // Attempt to real all saved process ID's.
+
+ std::list<pid_t>::iterator iter = sZombies.begin();
+ while(iter != sZombies.end())
+ {
+ if(reap_pid(*iter))
+ {
+ iter = sZombies.erase(iter);
+ }
+ else
+ {
+ iter++;
+ }
+ }
+}
+
+#endif
diff --git a/indra/llcommon/llprocesslauncher.h b/indra/llcommon/llprocesslauncher.h
new file mode 100644
index 0000000000..a1b8e22691
--- /dev/null
+++ b/indra/llcommon/llprocesslauncher.h
@@ -0,0 +1,85 @@
+/**
+ * @file llprocesslauncher.h
+ * @brief Utility class for launching, terminating, and tracking the state of processes.
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ *
+ * Copyright (c) 2008, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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_LLPROCESSLAUNCHER_H
+#define LL_LLPROCESSLAUNCHER_H
+
+#if LL_WINDOWS
+#include <windows.h>
+#endif
+
+
+/*
+ LLProcessLauncher handles launching external processes with specified command line arguments.
+ It also keeps track of whether the process is still running, and can kill it if required.
+*/
+
+class LLProcessLauncher
+{
+ LOG_CLASS(LLProcessLauncher);
+public:
+ LLProcessLauncher();
+ virtual ~LLProcessLauncher();
+
+ void setExecutable(const std::string &executable);
+ void setWorkingDirectory(const std::string &dir);
+
+ void clearArguments();
+ void addArgument(const std::string &arg);
+ void addArgument(const char *arg);
+
+ int launch(void);
+ bool isRunning(void);
+
+ // Attempt to kill the process -- returns true if the process is no longer running when it returns.
+ // Note that even if this returns false, the process may exit some time after it's called.
+ bool kill(void);
+
+ // Use this if you want the external process to continue execution after the LLProcessLauncher instance controlling it is deleted.
+ // Normally, the destructor will attempt to kill the process and wait for termination.
+ // This should only be used if the viewer is about to exit -- otherwise, the child process will become a zombie after it exits.
+ void orphan(void);
+
+ // This needs to be called periodically on Mac/Linux to clean up zombie processes.
+ static void reap(void);
+private:
+ std::string mExecutable;
+ std::string mWorkingDir;
+ std::vector<std::string> mLaunchArguments;
+
+#if LL_WINDOWS
+ HANDLE mProcessHandle;
+#else
+ pid_t mProcessID;
+#endif
+};
+
+#endif // LL_LLPROCESSLAUNCHER_H
diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h
index 5f102509fd..9ab844eb22 100644
--- a/indra/llcommon/llrefcount.h
+++ b/indra/llcommon/llrefcount.h
@@ -32,6 +32,8 @@
#ifndef LLREFCOUNT_H
#define LLREFCOUNT_H
+#include <boost/noncopyable.hpp>
+
//----------------------------------------------------------------------------
// RefCount objects should generally only be accessed by way of LLPointer<>'s
// see llthread.h for LLThreadSafeRefCount
@@ -40,10 +42,9 @@
class LL_COMMON_API LLRefCount
{
private:
- LLRefCount(const LLRefCount&); // not implemented
+ LLRefCount(const LLRefCount& other); // no implementation
private:
- LLRefCount&operator=(const LLRefCount&); // not implemented
-
+ LLRefCount& operator=(const LLRefCount&); // no implementation
protected:
virtual ~LLRefCount(); // use unref()
diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index ba0f798dbb..9140ebb3f3 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -819,9 +819,15 @@ static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat)
{
std::ostringstream out;
if (useXMLFormat)
- out << LLSDXMLStreamer(llsd);
+ {
+ LLSDXMLStreamer xml_streamer(llsd);
+ out << xml_streamer;
+ }
else
- out << LLSDNotationStreamer(llsd);
+ {
+ LLSDNotationStreamer notation_streamer(llsd);
+ out << notation_streamer;
+ }
out_string = out.str();
}
int len = out_string.length();
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index ec1718a8cb..d7da40d645 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -42,6 +42,9 @@
#include <winnls.h> // for WideCharToMultiByte
#endif
+LLFastTimer::DeclareTimer STRING_LOCALIZATION("String Localization");
+
+
std::string ll_safe_string(const char* in)
{
if(in) return std::string(in);
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 24a8d49a54..f5c6b297b9 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -38,6 +38,7 @@
#include <iomanip>
#include <boost/regex.hpp>
#include "llsd.h"
+#include "llfasttimer.h"
#if LL_LINUX || LL_SOLARIS
#include <wctype.h>
@@ -232,9 +233,10 @@ public:
typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t;
static void getTokens (std::basic_string<T> input, std::vector<std::basic_string<T> >& tokens);
static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals);
- static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, const LLSD& substitutions);
+ static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, S32 secFromEpoch);
+ static S32 format(std::basic_string<T>& s, const format_map_t& substitutions);
static S32 format(std::basic_string<T>& s, const LLSD& substitutions);
- static S32 format(std::basic_string<T>& s, const format_map_t& fmt_map);
+ static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const format_map_t& substitutions);
static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const LLSD& substitutions);
static void setLocale (std::string inLocale) {sLocale = inLocale;};
static std::string getLocale (void) {return sLocale;};
@@ -336,6 +338,9 @@ public:
// Copies src into dst at a given offset.
static void copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset);
+ static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); }
+
+
#ifdef _DEBUG
static void testHarness();
#endif
@@ -623,26 +628,89 @@ void LLStringUtilBase<T>::getTokens (std::basic_string<T> input, std::vector<std
}
}
+extern LLFastTimer::DeclareTimer STRING_LOCALIZATION;
+
// static
template<class T>
-S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const format_map_t& fmt_map)
+S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const format_map_t& substitutions)
{
- LLSD llsdMap;
+ LLFastTimer ft(STRING_LOCALIZATION);
+ S32 res = 0;
- for (format_map_t::const_iterator iter = fmt_map.begin();
- iter != fmt_map.end();
- ++iter)
+ std::basic_ostringstream<T> output;
+ // match strings like [NAME,number,3]
+ const boost::regex key("\\[((\\s)*([0-9_A-Za-z]+)((\\s)*,(\\s)*[0-9_A-Za-z\\s]*){0,2}(\\s)*)]");
+
+
+ typename std::basic_string<T>::const_iterator start = s.begin();
+ typename std::basic_string<T>::const_iterator end = s.end();
+ boost::smatch match;
+
+
+ while (boost::regex_search(start, end, match, key, boost::match_default))
{
- llsdMap[iter->first] = iter->second;
- }
+ bool found_replacement = false;
+ std::vector<std::basic_string<T> > tokens;
+ std::basic_string<T> replacement;
+
+ getTokens (std::basic_string<T>(match[1].first, match[1].second), tokens);
+
+ if (tokens.size() == 1)
+ {
+ found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
+ }
+ else if (tokens[1] == "number")
+ {
+ std::basic_string<T> param = "0";
+
+ if (tokens.size() > 2) param = tokens[2];
+ found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
+ if (found_replacement) formatNumber (replacement, param);
+ }
+ else if (tokens[1] == "datetime")
+ {
+ std::basic_string<T> param;
+ if (tokens.size() > 2) param = tokens[2];
+
+ format_map_t::const_iterator iter = substitutions.find("datetime");
+ if (iter != substitutions.end())
+ {
+ S32 secFromEpoch = 0;
+ BOOL r = LLStringUtil::convertToS32(iter->second, secFromEpoch);
+ if (r)
+ {
+ found_replacement = formatDatetime(replacement, tokens[0], param, secFromEpoch);
+ }
+ }
+ }
- return format (s, llsdMap);
+ if (found_replacement)
+ {
+ output << std::basic_string<T>(start, match[0].first) << replacement;
+ res++;
+ }
+ else
+ {
+ // we had no replacement, so leave the string we searched for so that it gets noticed by QA
+ // "hello [NAME_NOT_FOUND]" is output
+ output << std::basic_string<T>(start, match[0].second);
+ }
+
+ // update search position
+ start = match[0].second;
+ }
+ // send the remainder of the string (with no further matches for bracketed names)
+ output << std::basic_string<T>(start, end);
+ s = output.str();
+ return res;
}
//static
template<class T>
S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const LLSD& substitutions)
{
+ LLFastTimer ft(STRING_LOCALIZATION);
+
S32 res = 0;
if (!substitutions.isMap())
@@ -684,8 +752,9 @@ S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const LLSD& substitutio
{
std::basic_string<T> param;
if (tokens.size() > 2) param = tokens[2];
-
- found_replacement = formatDatetime (replacement, tokens[0], param, substitutions);
+
+ S32 secFromEpoch = (S32) substitutions["datetime"].asInteger();
+ found_replacement = formatDatetime (replacement, tokens[0], param, secFromEpoch);
}
if (found_replacement)
@@ -711,7 +780,32 @@ S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const LLSD& substitutio
// static
template<class T>
-bool LLStringUtilBase<T>::simpleReplacement(std::basic_string<T> &replacement, std::basic_string<T> token, const LLSD &substitutions)
+bool LLStringUtilBase<T>::simpleReplacement(std::basic_string<T> &replacement, std::basic_string<T> token, const format_map_t& substitutions)
+{
+ // see if we have a replacement for the bracketed string (without the brackets)
+ // test first using has() because if we just look up with operator[] we get back an
+ // empty string even if the value is missing. We want to distinguish between
+ // missing replacements and deliberately empty replacement strings.
+ format_map_t::const_iterator iter = substitutions.find(token);
+ if (iter != substitutions.end())
+ {
+ replacement = iter->second;
+ return true;
+ }
+ // if not, see if there's one WITH brackets
+ iter = substitutions.find(std::basic_string<T>("[" + token + "]"));
+ if (iter != substitutions.end())
+ {
+ replacement = iter->second;
+ return true;
+ }
+
+ return false;
+}
+
+// static
+template<class T>
+bool LLStringUtilBase<T>::simpleReplacement(std::basic_string<T> &replacement, std::basic_string<T> token, const LLSD& substitutions)
{
// see if we have a replacement for the bracketed string (without the brackets)
// test first using has() because if we just look up with operator[] we get back an
@@ -771,10 +865,8 @@ void LLStringUtilBase<T>::formatNumber(std::basic_string<T>& numStr, std::basic_
// static
template<class T>
bool LLStringUtilBase<T>::formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token,
- std::basic_string<T> param, const LLSD& substitutions)
+ std::basic_string<T> param, S32 secFromEpoch)
{
- S32 secFromEpoch = (long) substitutions["datetime"].asInteger();
-
if (param == "local") // local
{
secFromEpoch -= LLStringOps::getLocalTimeOffset();