summaryrefslogtreecommitdiff
path: root/indra/newview/llappviewer.cpp
diff options
context:
space:
mode:
authorOz Linden <oz@lindenlab.com>2016-10-18 15:38:33 -0400
committerOz Linden <oz@lindenlab.com>2016-10-18 15:38:33 -0400
commit8e30a2f06dd1ce407fcb2399823efed883b317d2 (patch)
treee5b22fb9fd2b5e99cf195d00338da57ecdade0d4 /indra/newview/llappviewer.cpp
parent7df153e352ce50ded382df020cc3696b8c1b9325 (diff)
parent086c1342152895da28d2e0130d09432152604ca8 (diff)
merge changes for 4.1.1-release
Diffstat (limited to 'indra/newview/llappviewer.cpp')
-rw-r--r--indra/newview/llappviewer.cpp508
1 files changed, 258 insertions, 250 deletions
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index b6d02ea2f8..76d0d46997 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -122,15 +122,20 @@
#include "llleap.h"
#include "stringize.h"
#include "llcoros.h"
+#include "llexception.h"
#if !LL_LINUX
#include "cef/llceflib.h"
-#endif
+#if LL_WINDOWS
+#include "vlc/libvlc_version.h"
+#endif // LL_WINDOWS
+#endif // LL_LINUX
// Third party library includes
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>
+#include <boost/throw_exception.hpp>
#if LL_WINDOWS
# include <share.h> // For _SH_DENYWR in processMarkerFiles
@@ -201,6 +206,7 @@
#include "llcommandlineparser.h"
#include "llfloatermemleak.h"
#include "llfloaterreg.h"
+#include "llfloateroutfitsnapshot.h"
#include "llfloatersnapshot.h"
#include "llfloaterinventory.h"
@@ -231,7 +237,6 @@
#include "llcoproceduremanager.h"
#include "llviewereventrecorder.h"
-
// *FIX: These extern globals should be cleaned up.
// The globals either represent state/config/resource-storage of either
// this app, or another 'component' of the viewer. App globals should be
@@ -769,9 +774,6 @@ bool LLAppViewer::init()
//
// Start of the application
//
-#ifdef LL_DARWIN
- mMainLoopInitialized = false;
-#endif
// initialize LLWearableType translation bridge.
// Memory will be cleaned up in ::cleanupClass()
@@ -925,7 +927,7 @@ bool LLAppViewer::init()
// Provide the text fields with callbacks for opening Urls
LLUrlAction::setOpenURLCallback(boost::bind(&LLWeb::loadURL, _1, LLStringUtil::null, LLStringUtil::null));
- LLUrlAction::setOpenURLInternalCallback(boost::bind(&LLWeb::loadURLInternal, _1, LLStringUtil::null, LLStringUtil::null));
+ LLUrlAction::setOpenURLInternalCallback(boost::bind(&LLWeb::loadURLInternal, _1, LLStringUtil::null, LLStringUtil::null, false));
LLUrlAction::setOpenURLExternalCallback(boost::bind(&LLWeb::loadURLExternal, _1, true, LLStringUtil::null));
LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor);
@@ -1220,6 +1222,23 @@ bool LLAppViewer::init()
boost::bind(&LLControlGroup::getU32, boost::ref(gSavedSettings), _1),
boost::bind(&LLControlGroup::declareU32, boost::ref(gSavedSettings), _1, _2, _3, LLControlVariable::PERSIST_ALWAYS));
+ /*----------------------------------------------------------------------*/
+ // nat 2016-06-29 moved the following here from the former mainLoop().
+ mMainloopTimeout = new LLWatchdogTimeout();
+
+ // Create IO Pump to use for HTTP Requests.
+ gServicePump = new LLPumpIO(gAPRPoolp);
+
+ // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated.
+
+ LLVoiceChannel::initClass();
+ LLVoiceClient::getInstance()->init(gServicePump);
+ LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLFloaterIMContainer::onCurrentChannelChanged, _1), true);
+
+ joystick = LLViewerJoystick::getInstance();
+ joystick->setNeedsReset(true);
+ /*----------------------------------------------------------------------*/
+
return true;
}
@@ -1294,299 +1313,266 @@ static LLTrace::BlockTimerStatHandle FTM_AGENT_UPDATE("Update");
// externally visible timers
LLTrace::BlockTimerStatHandle FTM_FRAME("Frame");
-bool LLAppViewer::mainLoop()
+bool LLAppViewer::frame()
{
-#ifdef LL_DARWIN
- if (!mMainLoopInitialized)
-#endif
- {
- LL_INFOS() << "Entering main_loop" << LL_ENDL;
- mMainloopTimeout = new LLWatchdogTimeout();
-
- //-------------------------------------------
- // Run main loop until time to quit
- //-------------------------------------------
-
- // Create IO Pump to use for HTTP Requests.
- gServicePump = new LLPumpIO(gAPRPoolp);
-
- // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated.
-
- LLVoiceChannel::initClass();
- LLVoiceClient::getInstance()->init(gServicePump);
- LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLFloaterIMContainer::onCurrentChannelChanged, _1), true);
-
- joystick = LLViewerJoystick::getInstance();
- joystick->setNeedsReset(true);
-
-#ifdef LL_DARWIN
- // Ensure that this section of code never gets called again on OS X.
- mMainLoopInitialized = true;
-#endif
- }
- // As we do not (yet) send data on the mainloop LLEventPump that varies
- // with each frame, no need to instantiate a new LLSD event object each
- // time. Obviously, if that changes, just instantiate the LLSD at the
- // point of posting.
-
LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
-
- LLSD newFrame;
-
+ LLSD newFrame;
+
LLTimer frameTimer,idleTimer;
LLTimer debugTime;
-
+
//LLPrivateMemoryPoolTester::getInstance()->run(false) ;
//LLPrivateMemoryPoolTester::getInstance()->run(true) ;
//LLPrivateMemoryPoolTester::destroy() ;
- // Handle messages
-#ifdef LL_DARWIN
- if (!LLApp::isExiting())
-#else
- while (!LLApp::isExiting())
-#endif
+ LL_RECORD_BLOCK_TIME(FTM_FRAME);
+ LLTrace::BlockTimer::processTimes();
+ LLTrace::get_frame_recording().nextPeriod();
+ LLTrace::BlockTimer::logStats();
+
+ LLTrace::get_thread_recorder()->pullFromChildren();
+
+ //clear call stack records
+ LL_CLEAR_CALLSTACKS();
+
+ //check memory availability information
+ checkMemory() ;
+
+ try
{
- LL_RECORD_BLOCK_TIME(FTM_FRAME);
- LLTrace::BlockTimer::processTimes();
- LLTrace::get_frame_recording().nextPeriod();
- LLTrace::BlockTimer::logStats();
+ pingMainloopTimeout("Main:MiscNativeWindowEvents");
- LLTrace::get_thread_recorder()->pullFromChildren();
+ if (gViewerWindow)
+ {
+ LL_RECORD_BLOCK_TIME(FTM_MESSAGES);
+ gViewerWindow->getWindow()->processMiscNativeEvents();
+ }
+
+ pingMainloopTimeout("Main:GatherInput");
+
+ if (gViewerWindow)
+ {
+ LL_RECORD_BLOCK_TIME(FTM_MESSAGES);
+ if (!restoreErrorTrap())
+ {
+ LL_WARNS() << " Someone took over my signal/exception handler (post messagehandling)!" << LL_ENDL;
+ }
- //clear call stack records
- LL_CLEAR_CALLSTACKS();
+ gViewerWindow->getWindow()->gatherInput();
+ }
- //check memory availability information
- checkMemory() ;
+#if 1 && !LL_RELEASE_FOR_DOWNLOAD
+ // once per second debug info
+ if (debugTime.getElapsedTimeF32() > 1.f)
+ {
+ debugTime.reset();
+ }
- try
+#endif
+ //memory leaking simulation
+ LLFloaterMemLeak* mem_leak_instance =
+ LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
+ if(mem_leak_instance)
{
- pingMainloopTimeout("Main:MiscNativeWindowEvents");
+ mem_leak_instance->idle() ;
+ }
+
+ // canonical per-frame event
+ mainloop.post(newFrame);
- if (gViewerWindow)
+ if (!LLApp::isExiting())
+ {
+ pingMainloopTimeout("Main:JoystickKeyboard");
+
+ // Scan keyboard for movement keys. Command keys and typing
+ // are handled by windows callbacks. Don't do this until we're
+ // done initializing. JC
+ if ((gHeadlessClient || gViewerWindow->getWindow()->getVisible())
+ && gViewerWindow->getActive()
+ && !gViewerWindow->getWindow()->getMinimized()
+ && LLStartUp::getStartupState() == STATE_STARTED
+ && (gHeadlessClient || !gViewerWindow->getShowProgress())
+ && !gFocusMgr.focusLocked())
{
- LL_RECORD_BLOCK_TIME(FTM_MESSAGES);
- gViewerWindow->getWindow()->processMiscNativeEvents();
+ joystick->scanJoystick();
+ gKeyboard->scanKeyboard();
}
-
- pingMainloopTimeout("Main:GatherInput");
-
- if (gViewerWindow)
+
+ // Update state based on messages, user input, object idle.
{
- LL_RECORD_BLOCK_TIME(FTM_MESSAGES);
- if (!restoreErrorTrap())
- {
- LL_WARNS() << " Someone took over my signal/exception handler (post messagehandling)!" << LL_ENDL;
- }
+ pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
+
+ LL_RECORD_BLOCK_TIME(FTM_IDLE);
+ idle();
- gViewerWindow->getWindow()->gatherInput();
+ resumeMainloopTimeout();
}
-#if 1 && !LL_RELEASE_FOR_DOWNLOAD
- // once per second debug info
- if (debugTime.getElapsedTimeF32() > 1.f)
+ if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
{
- debugTime.reset();
+ pauseMainloopTimeout();
+ saveFinalSnapshot();
+ disconnectViewer();
+ resumeMainloopTimeout();
}
-
-#endif
- //memory leaking simulation
- LLFloaterMemLeak* mem_leak_instance =
- LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
- if(mem_leak_instance)
- {
- mem_leak_instance->idle() ;
- }
-
- // canonical per-frame event
- mainloop.post(newFrame);
- if (!LLApp::isExiting())
+ // Render scene.
+ // *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18
+ if (!LLApp::isExiting() && !gHeadlessClient)
{
- pingMainloopTimeout("Main:JoystickKeyboard");
-
- // Scan keyboard for movement keys. Command keys and typing
- // are handled by windows callbacks. Don't do this until we're
- // done initializing. JC
- if ((gHeadlessClient || gViewerWindow->getWindow()->getVisible())
- && gViewerWindow->getActive()
- && !gViewerWindow->getWindow()->getMinimized()
- && LLStartUp::getStartupState() == STATE_STARTED
- && (gHeadlessClient || !gViewerWindow->getShowProgress())
- && !gFocusMgr.focusLocked())
- {
- joystick->scanJoystick();
- gKeyboard->scanKeyboard();
- }
+ pingMainloopTimeout("Main:Display");
+ gGLActive = TRUE;
+ display();
+ pingMainloopTimeout("Main:Snapshot");
+ LLFloaterSnapshot::update(); // take snapshots
+ LLFloaterOutfitSnapshot::update();
+ gGLActive = FALSE;
+ }
+ }
- // Update state based on messages, user input, object idle.
- {
- pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
-
- LL_RECORD_BLOCK_TIME(FTM_IDLE);
- idle();
+ pingMainloopTimeout("Main:Sleep");
- resumeMainloopTimeout();
- }
-
- if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
- {
- pauseMainloopTimeout();
- saveFinalSnapshot();
- disconnectViewer();
- resumeMainloopTimeout();
- }
+ pauseMainloopTimeout();
+
+ // Sleep and run background threads
+ {
+ LL_RECORD_BLOCK_TIME(FTM_SLEEP);
+
+ // yield some time to the os based on command line option
+ if(mYieldTime >= 0)
+ {
+ LL_RECORD_BLOCK_TIME(FTM_YIELD);
+ ms_sleep(mYieldTime);
+ }
- // Render scene.
- // *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18
- if (!LLApp::isExiting() && !gHeadlessClient)
+ // yield cooperatively when not running as foreground window
+ if ( (gViewerWindow && !gViewerWindow->getWindow()->getVisible())
+ || !gFocusMgr.getAppHasFocus())
+ {
+ // Sleep if we're not rendering, or the window is minimized.
+ S32 milliseconds_to_sleep = llclamp(gSavedSettings.getS32("BackgroundYieldTime"), 0, 1000);
+ // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads
+ // of equal priority on Windows
+ if (milliseconds_to_sleep > 0)
{
- pingMainloopTimeout("Main:Display");
- gGLActive = TRUE;
- display();
- pingMainloopTimeout("Main:Snapshot");
- LLFloaterSnapshot::update(); // take snapshots
- gGLActive = FALSE;
+ ms_sleep(milliseconds_to_sleep);
+ // also pause worker threads during this wait period
+ LLAppViewer::getTextureCache()->pause();
+ LLAppViewer::getImageDecodeThread()->pause();
}
}
-
- pingMainloopTimeout("Main:Sleep");
- pauseMainloopTimeout();
+ if (mRandomizeFramerate)
+ {
+ ms_sleep(rand() % 200);
+ }
- // Sleep and run background threads
+ if (mPeriodicSlowFrame
+ && (gFrameCount % 10 == 0))
{
- LL_RECORD_BLOCK_TIME(FTM_SLEEP);
-
- // yield some time to the os based on command line option
- if(mYieldTime >= 0)
- {
- LL_RECORD_BLOCK_TIME(FTM_YIELD);
- ms_sleep(mYieldTime);
- }
+ LL_INFOS() << "Periodic slow frame - sleeping 500 ms" << LL_ENDL;
+ ms_sleep(500);
+ }
+
+ const F64Milliseconds max_idle_time = llmin(.005f*10.f*(F32Milliseconds)gFrameTimeSeconds, F32Milliseconds(5)); // 5 ms a second
+ idleTimer.reset();
+ S32 total_work_pending = 0;
+ S32 total_io_pending = 0;
+ while(1)
+ {
+ S32 work_pending = 0;
+ S32 io_pending = 0;
+ F32 max_time = llmin(gFrameIntervalSeconds.value() *10.f, 1.f);
+
+ work_pending += updateTextureThreads(max_time);
- // yield cooperatively when not running as foreground window
- if ( (gViewerWindow && !gViewerWindow->getWindow()->getVisible())
- || !gFocusMgr.getAppHasFocus())
{
- // Sleep if we're not rendering, or the window is minimized.
- S32 milliseconds_to_sleep = llclamp(gSavedSettings.getS32("BackgroundYieldTime"), 0, 1000);
- // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads
- // of equal priority on Windows
- if (milliseconds_to_sleep > 0)
- {
- ms_sleep(milliseconds_to_sleep);
- // also pause worker threads during this wait period
- LLAppViewer::getTextureCache()->pause();
- LLAppViewer::getImageDecodeThread()->pause();
- }
+ LL_RECORD_BLOCK_TIME(FTM_VFS);
+ io_pending += LLVFSThread::updateClass(1);
}
-
- if (mRandomizeFramerate)
{
- ms_sleep(rand() % 200);
+ LL_RECORD_BLOCK_TIME(FTM_LFS);
+ io_pending += LLLFSThread::updateClass(1);
}
- if (mPeriodicSlowFrame
- && (gFrameCount % 10 == 0))
+ if (io_pending > 1000)
{
- LL_INFOS() << "Periodic slow frame - sleeping 500 ms" << LL_ENDL;
- ms_sleep(500);
+ ms_sleep(llmin(io_pending/100,100)); // give the vfs some time to catch up
}
- const F64Milliseconds max_idle_time = llmin(.005f*10.f*(F32Milliseconds)gFrameTimeSeconds, F32Milliseconds(5)); // 5 ms a second
- idleTimer.reset();
- S32 total_work_pending = 0;
- S32 total_io_pending = 0;
- while(1)
- {
- S32 work_pending = 0;
- S32 io_pending = 0;
- F32 max_time = llmin(gFrameIntervalSeconds.value() *10.f, 1.f);
-
- work_pending += updateTextureThreads(max_time);
-
- {
- LL_RECORD_BLOCK_TIME(FTM_VFS);
- io_pending += LLVFSThread::updateClass(1);
- }
- {
- LL_RECORD_BLOCK_TIME(FTM_LFS);
- io_pending += LLLFSThread::updateClass(1);
- }
-
- if (io_pending > 1000)
- {
- ms_sleep(llmin(io_pending/100,100)); // give the vfs some time to catch up
- }
-
- total_work_pending += work_pending ;
- total_io_pending += io_pending ;
-
- if (!work_pending || idleTimer.getElapsedTimeF64() >= max_idle_time)
- {
- break;
- }
- }
- gMeshRepo.update() ;
+ total_work_pending += work_pending ;
+ total_io_pending += io_pending ;
- if(!total_work_pending) //pause texture fetching threads if nothing to process.
+ if (!work_pending || idleTimer.getElapsedTimeF64() >= max_idle_time)
{
- LLAppViewer::getTextureCache()->pause();
- LLAppViewer::getImageDecodeThread()->pause();
- LLAppViewer::getTextureFetch()->pause();
+ break;
}
- if(!total_io_pending) //pause file threads if nothing to process.
- {
- LLVFSThread::sLocal->pause();
- LLLFSThread::sLocal->pause();
- }
+ }
+ gMeshRepo.update() ;
+
+ if(!total_work_pending) //pause texture fetching threads if nothing to process.
+ {
+ LLAppViewer::getTextureCache()->pause();
+ LLAppViewer::getImageDecodeThread()->pause();
+ LLAppViewer::getTextureFetch()->pause();
+ }
+ if(!total_io_pending) //pause file threads if nothing to process.
+ {
+ LLVFSThread::sLocal->pause();
+ LLLFSThread::sLocal->pause();
+ }
- //texture fetching debugger
- if(LLTextureFetchDebugger::isEnabled())
+ //texture fetching debugger
+ if(LLTextureFetchDebugger::isEnabled())
+ {
+ LLFloaterTextureFetchDebugger* tex_fetch_debugger_instance =
+ LLFloaterReg::findTypedInstance<LLFloaterTextureFetchDebugger>("tex_fetch_debugger");
+ if(tex_fetch_debugger_instance)
{
- LLFloaterTextureFetchDebugger* tex_fetch_debugger_instance =
- LLFloaterReg::findTypedInstance<LLFloaterTextureFetchDebugger>("tex_fetch_debugger");
- if(tex_fetch_debugger_instance)
- {
- tex_fetch_debugger_instance->idle() ;
- }
+ tex_fetch_debugger_instance->idle() ;
}
+ }
- if ((LLStartUp::getStartupState() >= STATE_CLEANUP) &&
- (frameTimer.getElapsedTimeF64() > FRAME_STALL_THRESHOLD))
- {
- gFrameStalls++;
- }
- frameTimer.reset();
+ if ((LLStartUp::getStartupState() >= STATE_CLEANUP) &&
+ (frameTimer.getElapsedTimeF64() > FRAME_STALL_THRESHOLD))
+ {
+ gFrameStalls++;
+ }
+ frameTimer.reset();
- resumeMainloopTimeout();
-
- pingMainloopTimeout("Main:End");
- }
+ resumeMainloopTimeout();
+
+ pingMainloopTimeout("Main:End");
}
- catch(std::bad_alloc)
- {
- LLMemory::logMemoryInfo(TRUE) ;
+ }
+ catch (const LLContinueError&)
+ {
+ LOG_UNHANDLED_EXCEPTION("");
+ }
+ catch(std::bad_alloc)
+ {
+ LLMemory::logMemoryInfo(TRUE) ;
- //stop memory leaking simulation
- LLFloaterMemLeak* mem_leak_instance =
- LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
- if(mem_leak_instance)
- {
- mem_leak_instance->stop() ;
- LL_WARNS() << "Bad memory allocation in LLAppViewer::mainLoop()!" << LL_ENDL ;
- }
- else
- {
- //output possible call stacks to log file.
- LLError::LLCallStacks::print() ;
+ //stop memory leaking simulation
+ LLFloaterMemLeak* mem_leak_instance =
+ LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
+ if(mem_leak_instance)
+ {
+ mem_leak_instance->stop() ;
+ LL_WARNS() << "Bad memory allocation in LLAppViewer::frame()!" << LL_ENDL ;
+ }
+ else
+ {
+ //output possible call stacks to log file.
+ LLError::LLCallStacks::print() ;
- LL_ERRS() << "Bad memory allocation in LLAppViewer::mainLoop()!" << LL_ENDL ;
- }
+ LL_ERRS() << "Bad memory allocation in LLAppViewer::frame()!" << LL_ENDL ;
}
}
+ catch (...)
+ {
+ CRASH_ON_UNHANDLED_EXCEPTION("");
+ }
if (LLApp::isExiting())
{
@@ -1600,7 +1586,7 @@ bool LLAppViewer::mainLoop()
catch(std::bad_alloc)
{
LL_WARNS() << "Bad memory allocation when saveFinalSnapshot() is called!" << LL_ENDL ;
-
+
//stop memory leaking simulation
LLFloaterMemLeak* mem_leak_instance =
LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
@@ -1609,16 +1595,20 @@ bool LLAppViewer::mainLoop()
mem_leak_instance->stop() ;
}
}
+ catch (...)
+ {
+ CRASH_ON_UNHANDLED_EXCEPTION("saveFinalSnapshot()");
+ }
}
-
+
delete gServicePump;
-
+
destroyMainloopTimeout();
-
+
LL_INFOS() << "Exiting main_loop" << LL_ENDL;
}
- return LLApp::isExiting();
+ return ! LLApp::isRunning();
}
S32 LLAppViewer::updateTextureThreads(F32 max_time)
@@ -3342,6 +3332,19 @@ LLSD LLAppViewer::getViewerInfo() const
info["LLCEFLIB_VERSION"] = LLCEFLIB_VERSION;
#else
info["LLCEFLIB_VERSION"] = "Undefined";
+
+#endif
+
+#if LL_WINDOWS
+ std::ostringstream ver_codec;
+ ver_codec << LIBVLC_VERSION_MAJOR;
+ ver_codec << ".";
+ ver_codec << LIBVLC_VERSION_MINOR;
+ ver_codec << ".";
+ ver_codec << LIBVLC_VERSION_REVISION;
+ info["LIBVLC_VERSION"] = ver_codec.str();
+#else
+ info["LIBVLC_VERSION"] = "Undefined";
#endif
S32 packets_in = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_IN);
@@ -3438,6 +3441,12 @@ std::string LLAppViewer::getViewerInfoString() const
{
support << '\n' << LLTrans::getString("AboutTraffic", args);
}
+
+ // SLT timestamp
+ LLSD substitution;
+ substitution["datetime"] = (S32)time(NULL);//(S32)time_corrected();
+ support << "\n" << LLTrans::getString("AboutTime", substitution);
+
return support.str();
}
@@ -5540,8 +5549,7 @@ void LLAppViewer::forceErrorInfiniteLoop()
void LLAppViewer::forceErrorSoftwareException()
{
LL_WARNS() << "Forcing a deliberate exception" << LL_ENDL;
- // *FIX: Any way to insure it won't be handled?
- throw;
+ LLTHROW(LLException("User selected Force Software Exception"));
}
void LLAppViewer::forceErrorDriverCrash()