From d3de134da047460c68ffd7cc732e592049a1e83d Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Wed, 18 May 2016 17:17:32 +0300 Subject: MAINT-6409 invisiprims should be preloaded --- indra/llcommon/indra_constants.cpp | 4 ++++ indra/llcommon/indra_constants.h | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'indra/llcommon') diff --git a/indra/llcommon/indra_constants.cpp b/indra/llcommon/indra_constants.cpp index f3989ee1d0..b45e3df1d8 100755 --- a/indra/llcommon/indra_constants.cpp +++ b/indra/llcommon/indra_constants.cpp @@ -60,6 +60,10 @@ const LLUUID IMG_SMOKE_POOF ("1e63e323-5fe0-452e-92f8-b98bd0f764e3"); // On d const LLUUID IMG_BIG_EXPLOSION_1 ("5e47a0dc-97bf-44e0-8b40-de06718cee9d"); // On dataserver const LLUUID IMG_BIG_EXPLOSION_2 ("9c8eca51-53d5-42a7-bb58-cef070395db8"); // On dataserver +const LLUUID IMG_ALPHA_GRAD ("e97cf410-8e61-7005-ec06-629eba4cd1fb"); // VIEWER +const LLUUID IMG_ALPHA_GRAD_2D ("38b86f85-2575-52a9-a531-23108d8da837"); // VIEWER +const LLUUID IMG_TRANSPARENT ("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"); // VIEWER + const LLUUID IMG_BLOOM1 ("3c59f7fe-9dc8-47f9-8aaf-a9dd1fbc3bef"); // VIEWER const LLUUID TERRAIN_DIRT_DETAIL ("0bc58228-74a0-7e83-89bc-5c23464bcec5"); // VIEWER const LLUUID TERRAIN_GRASS_DETAIL ("63338ede-0037-c4fd-855b-015d77112fc8"); // VIEWER diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 02f063f5e8..fda84aa5a8 100755 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -197,6 +197,10 @@ LL_COMMON_API extern const LLUUID IMG_SMOKE_POOF; LL_COMMON_API extern const LLUUID IMG_BIG_EXPLOSION_1; LL_COMMON_API extern const LLUUID IMG_BIG_EXPLOSION_2; +LL_COMMON_API extern const LLUUID IMG_ALPHA_GRAD; +LL_COMMON_API extern const LLUUID IMG_ALPHA_GRAD_2D; +LL_COMMON_API extern const LLUUID IMG_TRANSPARENT; + LL_COMMON_API extern const LLUUID IMG_BLOOM1; LL_COMMON_API extern const LLUUID TERRAIN_DIRT_DETAIL; LL_COMMON_API extern const LLUUID TERRAIN_GRASS_DETAIL; -- cgit v1.3 From 1adfaa081fd27d653619c84c520c16516c530ab1 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Wed, 1 Jun 2016 16:56:04 +0300 Subject: MAINT-6446 Correct password length handling --- indra/llcommon/llstring.cpp | 27 ++++++++++++++++++++++ indra/llcommon/llstring.h | 11 +++++++++ indra/llui/lllineeditor.cpp | 7 +----- indra/newview/skins/default/xui/en/panel_login.xml | 2 +- .../skins/default/xui/en/panel_login_first.xml | 2 +- 5 files changed, 41 insertions(+), 8 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index f3b8999883..c45db3b185 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -576,6 +576,33 @@ std::string utf8str_truncate(const std::string& utf8str, const S32 max_len) } } +std::string utf8str_symbol_truncate(const std::string& utf8str, const S32 symbol_len) +{ + if (0 == symbol_len) + { + return std::string(); + } + if ((S32)utf8str.length() <= symbol_len) + { + return utf8str; + } + else + { + int len = 0, byteIndex = 0; + const char* aStr = utf8str.c_str(); + size_t origSize = utf8str.size(); + + for (byteIndex = 0; len < symbol_len && byteIndex < origSize; byteIndex++) + { + if ((aStr[byteIndex] & 0xc0) != 0x80) + { + len += 1; + } + } + return utf8str.substr(0, byteIndex); + } +} + std::string utf8str_substChar( const std::string& utf8str, const llwchar target_char, diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 393f6d7a8c..a40db0f8cc 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -563,6 +563,17 @@ LL_COMMON_API S32 utf8str_compare_insensitive( const std::string& lhs, const std::string& rhs); +/** +* @brief Properly truncate a utf8 string to a maximum character count. +* +* If symbol_len is longer than the string passed in, the return +* value == utf8str. +* @param utf8str A valid utf8 string to truncate. +* @param symbol_len The maximum number of symbols in the return value. +* @return Returns a valid utf8 string with symbol count <= max_len. +*/ +LL_COMMON_API std::string utf8str_symbol_truncate(const std::string& utf8str, const S32 symbol_len); + /** * @brief Replace all occurences of target_char with replace_char * diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index a08cf91a69..492c9315d1 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -400,12 +400,7 @@ void LLLineEditor::setText(const LLStringExplicit &new_text) if (mMaxLengthChars) { - LLWString truncated_wstring = utf8str_to_wstring(truncated_utf8); - if (truncated_wstring.size() > (U32)mMaxLengthChars) - { - truncated_wstring = truncated_wstring.substr(0, mMaxLengthChars); - } - mText.assign(wstring_to_utf8str(truncated_wstring)); + mText.assign(utf8str_symbol_truncate(truncated_utf8, mMaxLengthChars)); } if (all_selected) diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index ae8e78a9d6..ded814bbeb 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -67,7 +67,7 @@ follows="left|top" height="32" left_pad="-11" - max_length_bytes="64" + max_length_chars="16" text_pad_left="8" name="password_edit" label="Password" diff --git a/indra/newview/skins/default/xui/en/panel_login_first.xml b/indra/newview/skins/default/xui/en/panel_login_first.xml index dc6e27a1ee..35b80c56ab 100644 --- a/indra/newview/skins/default/xui/en/panel_login_first.xml +++ b/indra/newview/skins/default/xui/en/panel_login_first.xml @@ -124,7 +124,7 @@ width="200" height="32" left="220" - max_length_bytes="64" + max_length_chars="16" name="password_edit" label="Password" text_pad_left="8" -- cgit v1.3 From 464a0df4c1d3e4073fe0bde506ac1d4aa194b02f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 30 Jun 2016 16:51:50 -0400 Subject: DRTVWR-418: Unify control flow through LLAppViewer across platforms. The LLApp API used to consist of init(), mainLoop(), cleanup() methods. This makes sense -- but on Mac that structure was being subverted. The method called mainLoop() was in fact being called once per frame. There was initialization code in the method, which (on Mac) needed to be skipped with an already-initialized bool. There was a 'while' loop which (on Mac) needed to be turned into an 'if' instead so the method would return after every frame. Rename LLApp::mainLoop() to frame(). Propagate through subclasses LLAppViewer and LLCrashLogger. Document the fact that frame() returns true to mean "done." (This was always the case, but had to be inferred from the code.) Rename the Mac Objective-C function mainLoop to oneFrame. Rename the C++ free function it calls from runMainLoop() to pumpMainLoop(). Add comments to llappdelegate-objc.mm explaining (inferred) control flow. Change the Linux viewer main() and the Windows viewer WINMAIN() from a single LLAppViewer::mainLoop() call to repeatedly call frame() until it returns true. Move initialization code from the top of LLAppViewer::frame() to the init() method, where it more properly belongs. Remove corresponding mMainLoopInitialized flag (and all references) from LLAppViewer. Remove 'while (! LLApp::isExiting())' (or on Mac, 'if (! LLApp::isExiting())') from LLAppViewer::frame() -- thus unindenting the whole body of the 'while' and causing many lines of apparent change. (Apologies to reviewers.) There are four LLApp states: APP_STATUS_RUNNING, APP_STATUS_QUITTING, APP_STATUS_STOPPED and APP_STATUS_ERROR. Change LLAppViewer::frame() return value from (isExiting()) (QUITTING or ERROR) to (! isRunning()). I do not know under what circumstances the state might transition to STOPPED during a frame() call, but I'm quite sure that if it does, we don't want to call frame() again. We only want a subsequent call if the state is RUNNING. Also rename mainLoop() method in LLCrashLogger subclasses LLCrashLoggerWindows, LLCrashLoggerMac, LLCrashLoggerLinux. Of course it's completely up to the frame() method whether to yield control; none of those in fact do. Honor protocol by returning true (frame() is done), even though each one's main() caller ignores the return value. In fact LLCrashLoggerWindows::mainLoop() wasn't using the return protocol correctly anyway, returning wParam or 0 or 1 -- possibly because the return protocol was never explicitly documented. It should always return true: "I'm done, don't call me again." --- indra/linux_crash_logger/linux_crash_logger.cpp | 2 +- indra/linux_crash_logger/llcrashloggerlinux.cpp | 2 +- indra/linux_crash_logger/llcrashloggerlinux.h | 2 +- indra/llcommon/llapp.h | 8 +- indra/llcrashlogger/llcrashlogger.h | 2 +- indra/llwindow/llappdelegate-objc.h | 2 +- indra/llwindow/llwindowmacosx-objc.h | 2 +- indra/mac_crash_logger/llcrashloggermac.cpp | 2 +- indra/mac_crash_logger/llcrashloggermac.h | 2 +- indra/mac_crash_logger/mac_crash_logger.cpp | 2 +- indra/newview/llappdelegate-objc.mm | 24 +- indra/newview/llappviewer.cpp | 456 +++++++++++------------- indra/newview/llappviewer.h | 3 +- indra/newview/llappviewerlinux.cpp | 6 +- indra/newview/llappviewermacosx.cpp | 9 +- indra/newview/llappviewerwin32.cpp | 6 +- indra/test/llapp_tut.cpp | 2 +- indra/win_crash_logger/llcrashloggerwindows.cpp | 8 +- indra/win_crash_logger/llcrashloggerwindows.h | 2 +- indra/win_crash_logger/win_crash_logger.cpp | 2 +- 20 files changed, 263 insertions(+), 281 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/linux_crash_logger/linux_crash_logger.cpp b/indra/linux_crash_logger/linux_crash_logger.cpp index 9d5ec33fed..63e5409876 100644 --- a/indra/linux_crash_logger/linux_crash_logger.cpp +++ b/indra/linux_crash_logger/linux_crash_logger.cpp @@ -51,7 +51,7 @@ int main(int argc, char **argv) return 1; } - app.mainLoop(); + app.frame(); app.cleanup(); LL_INFOS() << "Crash reporter finished normally." << LL_ENDL; return 0; diff --git a/indra/linux_crash_logger/llcrashloggerlinux.cpp b/indra/linux_crash_logger/llcrashloggerlinux.cpp index e2d2e7ff26..4092d43fc5 100644 --- a/indra/linux_crash_logger/llcrashloggerlinux.cpp +++ b/indra/linux_crash_logger/llcrashloggerlinux.cpp @@ -114,7 +114,7 @@ void LLCrashLoggerLinux::gatherPlatformSpecificFiles() { } -bool LLCrashLoggerLinux::mainLoop() +bool LLCrashLoggerLinux::frame() { bool send_logs = true; if(CRASH_BEHAVIOR_ASK == getCrashBehavior()) diff --git a/indra/linux_crash_logger/llcrashloggerlinux.h b/indra/linux_crash_logger/llcrashloggerlinux.h index dae6c46651..789f6f03f5 100644 --- a/indra/linux_crash_logger/llcrashloggerlinux.h +++ b/indra/linux_crash_logger/llcrashloggerlinux.h @@ -36,7 +36,7 @@ class LLCrashLoggerLinux : public LLCrashLogger public: LLCrashLoggerLinux(void); ~LLCrashLoggerLinux(void); - virtual bool mainLoop(); + virtual bool frame(); virtual void updateApplication(const std::string& = LLStringUtil::null); virtual void gatherPlatformSpecificFiles(); virtual bool cleanup(); diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index d9933b3d36..ff9a92b45f 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -172,12 +172,12 @@ public: virtual bool cleanup() = 0; // Override to do application cleanup // - // mainLoop() + // frame() // - // Runs the application main loop. It's assumed that when you exit - // this method, the application is in one of the cleanup states, either QUITTING or ERROR + // Pass control to the application for a single frame. Returns 'done' + // flag: if frame() returns false, it expects to be called again. // - virtual bool mainLoop() = 0; // Override for the application main loop. Needs to at least gracefully notice the QUITTING state and exit. + virtual bool frame() = 0; // Override for application body logic // // Crash logging diff --git a/indra/llcrashlogger/llcrashlogger.h b/indra/llcrashlogger/llcrashlogger.h index 8b4afae24a..56e26c23ba 100644 --- a/indra/llcrashlogger/llcrashlogger.h +++ b/indra/llcrashlogger/llcrashlogger.h @@ -57,7 +57,7 @@ public: LLSD constructPostData(); virtual void updateApplication(const std::string& message = LLStringUtil::null); virtual bool init(); - virtual bool mainLoop() = 0; + virtual bool frame() = 0; virtual bool cleanup() = 0; void commonCleanup(); void setUserText(const std::string& text) { mCrashInfo["UserNotes"] = text; } diff --git a/indra/llwindow/llappdelegate-objc.h b/indra/llwindow/llappdelegate-objc.h index faa5d3abb7..6daf1ac55b 100644 --- a/indra/llwindow/llappdelegate-objc.h +++ b/indra/llwindow/llappdelegate-objc.h @@ -41,7 +41,7 @@ @property (retain) NSString *currentInputLanguage; -- (void) mainLoop; +- (void) oneFrame; - (void) showInputWindow:(bool)show withEvent:(NSEvent*)textEvent; - (void) languageUpdated; - (bool) romanScript; diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index c22f3382fb..b06cd2c184 100644 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -69,7 +69,7 @@ typedef const NativeKeyEventData * NSKeyEventRef; // These are defined in llappviewermacosx.cpp. bool initViewer(); void handleQuit(); -bool runMainLoop(); +bool pumpMainLoop(); void initMainLoop(); void cleanupViewer(); void handleUrl(const char* url); diff --git a/indra/mac_crash_logger/llcrashloggermac.cpp b/indra/mac_crash_logger/llcrashloggermac.cpp index 3149fad6e8..ec3616e26a 100644 --- a/indra/mac_crash_logger/llcrashloggermac.cpp +++ b/indra/mac_crash_logger/llcrashloggermac.cpp @@ -64,7 +64,7 @@ void LLCrashLoggerMac::gatherPlatformSpecificFiles() { } -bool LLCrashLoggerMac::mainLoop() +bool LLCrashLoggerMac::frame() { if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND) diff --git a/indra/mac_crash_logger/llcrashloggermac.h b/indra/mac_crash_logger/llcrashloggermac.h index 6d8f63ecac..05ef8c9f53 100644 --- a/indra/mac_crash_logger/llcrashloggermac.h +++ b/indra/mac_crash_logger/llcrashloggermac.h @@ -37,7 +37,7 @@ public: LLCrashLoggerMac(void); ~LLCrashLoggerMac(void); virtual bool init(); - virtual bool mainLoop(); + virtual bool frame(); virtual bool cleanup(); virtual void gatherPlatformSpecificFiles(); }; diff --git a/indra/mac_crash_logger/mac_crash_logger.cpp b/indra/mac_crash_logger/mac_crash_logger.cpp index 95d4e65207..54e41a1954 100644 --- a/indra/mac_crash_logger/mac_crash_logger.cpp +++ b/indra/mac_crash_logger/mac_crash_logger.cpp @@ -49,7 +49,7 @@ int main(int argc, char **argv) { // return NSApplicationMain(argc, (const char **)argv); } - app.mainLoop(); + app.frame(); app.cleanup(); LL_INFOS() << "Crash reporter finished normally." << LL_ENDL; diff --git a/indra/newview/llappdelegate-objc.mm b/indra/newview/llappdelegate-objc.mm index 549df80fa1..be8877328d 100644 --- a/indra/newview/llappdelegate-objc.mm +++ b/indra/newview/llappdelegate-objc.mm @@ -48,16 +48,19 @@ - (void) applicationDidFinishLaunching:(NSNotification *)notification { frameTimer = nil; - + [self languageUpdated]; - + if (initViewer()) { - frameTimer = [NSTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(mainLoop) userInfo:nil repeats:YES]; + // Set up recurring calls to oneFrame (repeating timer with timeout 0) + // until applicationShouldTerminate. + frameTimer = [NSTimer scheduledTimerWithTimeInterval:0.0 target:self + selector:@selector(oneFrame) userInfo:nil repeats:YES]; } else { handleQuit(); } - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(languageUpdated) name:@"NSTextInputContextKeyboardSelectionDidChangeNotification" object:nil]; // [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(handleGetURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL]; @@ -96,22 +99,29 @@ - (NSApplicationDelegateReply) applicationShouldTerminate:(NSApplication *)sender { - if (!runMainLoop()) + // run one frame to assess state + if (!pumpMainLoop()) { + // pumpMainLoop() returns true when done, false if it wants to be + // called again. Since it returned false, do not yet cancel + // frameTimer. handleQuit(); return NSTerminateCancel; } else { + // pumpMainLoop() returned true: it's done. Okay, done with frameTimer. [frameTimer release]; cleanupViewer(); return NSTerminateNow; } } -- (void) mainLoop +- (void) oneFrame { - bool appExiting = runMainLoop(); + bool appExiting = pumpMainLoop(); if (appExiting) { + // Once pumpMainLoop() reports that we're done, cancel frameTimer: + // stop the repetitive calls. [frameTimer release]; [[NSApplication sharedApplication] terminate:self]; } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b6d02ea2f8..604e45f314 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -769,9 +769,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() @@ -1220,6 +1217,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,297 +1308,255 @@ 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"); + + if (gViewerWindow) + { + LL_RECORD_BLOCK_TIME(FTM_MESSAGES); + gViewerWindow->getWindow()->processMiscNativeEvents(); + } - LLTrace::get_thread_recorder()->pullFromChildren(); + pingMainloopTimeout("Main:GatherInput"); - //clear call stack records - LL_CLEAR_CALLSTACKS(); + if (gViewerWindow) + { + LL_RECORD_BLOCK_TIME(FTM_MESSAGES); + if (!restoreErrorTrap()) + { + LL_WARNS() << " Someone took over my signal/exception handler (post messagehandling)!" << LL_ENDL; + } - //check memory availability information - checkMemory() ; + gViewerWindow->getWindow()->gatherInput(); + } + +#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("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("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 + 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(); - // Render scene. - // *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18 - if (!LLApp::isExiting() && !gHeadlessClient) + // 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); + } + + // 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(); - } - if(!total_io_pending) //pause file threads if nothing to process. - { - LLVFSThread::sLocal->pause(); - LLLFSThread::sLocal->pause(); - } - - //texture fetching debugger - if(LLTextureFetchDebugger::isEnabled()) - { - LLFloaterTextureFetchDebugger* tex_fetch_debugger_instance = - LLFloaterReg::findTypedInstance("tex_fetch_debugger"); - if(tex_fetch_debugger_instance) - { - tex_fetch_debugger_instance->idle() ; - } + break; } + } + 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(); + } - if ((LLStartUp::getStartupState() >= STATE_CLEANUP) && - (frameTimer.getElapsedTimeF64() > FRAME_STALL_THRESHOLD)) + //texture fetching debugger + if(LLTextureFetchDebugger::isEnabled()) + { + LLFloaterTextureFetchDebugger* tex_fetch_debugger_instance = + LLFloaterReg::findTypedInstance("tex_fetch_debugger"); + if(tex_fetch_debugger_instance) { - gFrameStalls++; + tex_fetch_debugger_instance->idle() ; } - frameTimer.reset(); - - resumeMainloopTimeout(); - - pingMainloopTimeout("Main:End"); - } - } - catch(std::bad_alloc) - { - LLMemory::logMemoryInfo(TRUE) ; + } - //stop memory leaking simulation - LLFloaterMemLeak* mem_leak_instance = - LLFloaterReg::findTypedInstance("mem_leaking"); - if(mem_leak_instance) + if ((LLStartUp::getStartupState() >= STATE_CLEANUP) && + (frameTimer.getElapsedTimeF64() > FRAME_STALL_THRESHOLD)) { - mem_leak_instance->stop() ; - LL_WARNS() << "Bad memory allocation in LLAppViewer::mainLoop()!" << LL_ENDL ; + gFrameStalls++; } - else - { - //output possible call stacks to log file. - LLError::LLCallStacks::print() ; + frameTimer.reset(); - LL_ERRS() << "Bad memory allocation in LLAppViewer::mainLoop()!" << LL_ENDL ; - } + resumeMainloopTimeout(); + + pingMainloopTimeout("Main:End"); + } + } + catch(std::bad_alloc) + { + LLMemory::logMemoryInfo(TRUE) ; + + //stop memory leaking simulation + LLFloaterMemLeak* mem_leak_instance = + LLFloaterReg::findTypedInstance("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::frame()!" << LL_ENDL ; } } @@ -1618,7 +1590,7 @@ bool LLAppViewer::mainLoop() LL_INFOS() << "Exiting main_loop" << LL_ENDL; } - return LLApp::isExiting(); + return ! LLApp::isRunning(); } S32 LLAppViewer::updateTextureThreads(F32 max_time) diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index b5e674bd7b..f7c1bb58b4 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -79,7 +79,7 @@ public: // virtual bool init(); // Override to do application initialization virtual bool cleanup(); // Override to do application cleanup - virtual bool mainLoop(); // Override for the application main loop. Needs to at least gracefully notice the QUITTING state and exit. + virtual bool frame(); // Override for application body logic // Application control void flushVFSIO(); // waits for vfs transfers to complete @@ -283,7 +283,6 @@ private: std::string mSerialNumber; bool mPurgeCache; bool mPurgeOnExit; - bool mMainLoopInitialized; LLViewerJoystick* joystick; bool mSavedFinalSnapshot; diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index f5742b29cf..6f32aab851 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -95,10 +95,8 @@ int main( int argc, char **argv ) } // Run the application main loop - if(!LLApp::isQuitting()) - { - viewer_app_ptr->mainLoop(); - } + while (! viewer_app_ptr->frame()) + {} if (!LLApp::isError()) { diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index ca219fda59..4fe1e31668 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -117,12 +117,17 @@ void handleQuit() LLAppViewer::instance()->userQuit(); } -bool runMainLoop() +// This function is called pumpMainLoop() rather than runMainLoop() because +// it passes control to the viewer's main-loop logic for a single frame. Like +// LLAppViewer::frame(), it returns 'true' when it's done. Until then, it +// expects to be called again by the timer in LLAppDelegate +// (llappdelegate-objc.mm). +bool pumpMainLoop() { bool ret = LLApp::isQuitting(); if (!ret && gViewerAppPtr != NULL) { - ret = gViewerAppPtr->mainLoop(); + ret = gViewerAppPtr->frame(); } else { ret = true; } diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 4786f83bfd..a7f248ab5a 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -317,10 +317,8 @@ int APIENTRY WINMAIN(HINSTANCE hInstance, } // Run the application main loop - if(!LLApp::isQuitting()) - { - viewer_app_ptr->mainLoop(); - } + while (! viewer_app_ptr->frame()) + {} if (!LLApp::isError()) { diff --git a/indra/test/llapp_tut.cpp b/indra/test/llapp_tut.cpp index aa5c0672e6..98e714a497 100644 --- a/indra/test/llapp_tut.cpp +++ b/indra/test/llapp_tut.cpp @@ -41,7 +41,7 @@ namespace tut public: virtual bool init() { return true; } virtual bool cleanup() { return true; } - virtual bool mainLoop() { return true; } + virtual bool frame() { return true; } }; LLTestApp* mApp; application() diff --git a/indra/win_crash_logger/llcrashloggerwindows.cpp b/indra/win_crash_logger/llcrashloggerwindows.cpp index 23c29e6b18..167acf6ac7 100644 --- a/indra/win_crash_logger/llcrashloggerwindows.cpp +++ b/indra/win_crash_logger/llcrashloggerwindows.cpp @@ -454,7 +454,7 @@ void LLCrashLoggerWindows::gatherPlatformSpecificFiles() //mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo(); //Not initialized. } -bool LLCrashLoggerWindows::mainLoop() +bool LLCrashLoggerWindows::frame() { LL_INFOS() << "CrashSubmitBehavior is " << mCrashBehavior << LL_ENDL; @@ -503,14 +503,14 @@ bool LLCrashLoggerWindows::mainLoop() TranslateMessage(&msg); DispatchMessage(&msg); } - return msg.wParam; + return true; // msg.wParam; } else { LL_WARNS() << "Unknown crash behavior " << mCrashBehavior << LL_ENDL; - return 1; + return true; // 1; } - return 0; + return true; // 0; } void LLCrashLoggerWindows::updateApplication(const std::string& message) diff --git a/indra/win_crash_logger/llcrashloggerwindows.h b/indra/win_crash_logger/llcrashloggerwindows.h index 1812e2737e..f89b8708dc 100644 --- a/indra/win_crash_logger/llcrashloggerwindows.h +++ b/indra/win_crash_logger/llcrashloggerwindows.h @@ -46,7 +46,7 @@ public: static LLCrashLoggerWindows* sInstance; virtual bool init(); - virtual bool mainLoop(); + virtual bool frame(); virtual void updateApplication(const std::string& message = LLStringUtil::null); virtual bool cleanup(); virtual void gatherPlatformSpecificFiles(); diff --git a/indra/win_crash_logger/win_crash_logger.cpp b/indra/win_crash_logger/win_crash_logger.cpp index 366edd894b..7466dbb766 100644 --- a/indra/win_crash_logger/win_crash_logger.cpp +++ b/indra/win_crash_logger/win_crash_logger.cpp @@ -52,7 +52,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, } app.processingLoop(); - app.mainLoop(); + app.frame(); app.cleanup(); LL_INFOS() << "Crash reporter finished normally." << LL_ENDL; return 0; -- cgit v1.3 From 9c49a6c91dd9b5bbe811fcd91d8992ed6bac33e7 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 19 Jul 2016 16:25:25 -0400 Subject: MAINT-5011: Introduce LLException base class for viewer exceptions. This also introduces LLContinueError for exceptions which should interrupt some part of viewer processing (e.g. the current coroutine) but should attempt to let the viewer session proceed. Derive all existing viewer exception classes from LLException rather than from std::runtime_error or std::logic_error. Use BOOST_THROW_EXCEPTION() rather than plain 'throw' to enrich the thrown exception with source file, line number and containing function. --- indra/llcommon/CMakeLists.txt | 1 + indra/llcommon/lldependencies.cpp | 3 +- indra/llcommon/lldependencies.h | 6 +-- indra/llcommon/lleventcoro.cpp | 3 +- indra/llcommon/lleventcoro.h | 6 +-- indra/llcommon/llevents.cpp | 17 +++--- indra/llcommon/llevents.h | 14 ++--- indra/llcommon/llexception.h | 63 ++++++++++++++++++++++ indra/llcommon/llleap.cpp | 5 +- indra/llcommon/llleap.h | 6 +-- indra/llcommon/llprocess.cpp | 23 ++++---- indra/llcommon/llprocess.h | 6 +-- indra/llcommon/llthreadsafequeue.cpp | 13 ++--- indra/llcommon/llthreadsafequeue.h | 7 ++- indra/llcommon/lluuid.cpp | 2 +- indra/llcommon/tests/wrapllerrs.h | 9 ++-- indra/llimage/llpngwrapper.cpp | 15 +++--- indra/llkdu/llimagej2ckdu.cpp | 9 ++-- indra/llmessage/llhttpnode.cpp | 15 +++--- indra/llmessage/tests/commtest.h | 9 ++-- indra/llmessage/tests/networkio.h | 6 ++- indra/newview/llappviewer.cpp | 6 +-- indra/newview/llcommandlineparser.cpp | 25 +++++---- indra/newview/llsecapi.cpp | 3 +- indra/newview/llsecapi.h | 10 ++-- indra/newview/llsechandler_basic.cpp | 53 +++++++++--------- .../updater/llupdatedownloader.cpp | 17 +++--- .../updater/llupdateinstaller.cpp | 9 ++-- .../viewer_components/updater/llupdaterservice.cpp | 11 ++-- indra/viewer_components/updater/llupdaterservice.h | 5 +- 30 files changed, 234 insertions(+), 143 deletions(-) create mode 100644 indra/llcommon/llexception.h (limited to 'indra/llcommon') diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 907dbab8f8..44f45144e5 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -157,6 +157,7 @@ set(llcommon_HEADER_FILES lleventfilter.h llevents.h lleventemitter.h + llexception.h llfasttimer.h llfile.h llfindlocale.h diff --git a/indra/llcommon/lldependencies.cpp b/indra/llcommon/lldependencies.cpp index 0e72c175cb..87a699ff14 100644 --- a/indra/llcommon/lldependencies.cpp +++ b/indra/llcommon/lldependencies.cpp @@ -39,6 +39,7 @@ #include #include #include +#include // other Linden headers LLDependenciesBase::VertexList LLDependenciesBase::topo_sort(int vertices, const EdgeList& edges) const @@ -76,7 +77,7 @@ LLDependenciesBase::VertexList LLDependenciesBase::topo_sort(int vertices, const // Omit independent nodes: display only those that might contribute to // the cycle. describe(out, false); - throw Cycle(out.str()); + BOOST_THROW_EXCEPTION(Cycle(out.str())); } // A peculiarity of boost::topological_sort() is that it emits results in // REVERSE topological order: to get the result you want, you must diff --git a/indra/llcommon/lldependencies.h b/indra/llcommon/lldependencies.h index e0294e271b..125bd6a835 100644 --- a/indra/llcommon/lldependencies.h +++ b/indra/llcommon/lldependencies.h @@ -34,13 +34,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include "llexception.h" /***************************************************************************** * Utilities @@ -106,9 +106,9 @@ public: /** * Exception thrown by sort() if there's a cycle */ - struct Cycle: public std::runtime_error + struct Cycle: public LLException { - Cycle(const std::string& what): std::runtime_error(what) {} + Cycle(const std::string& what): LLException(what) {} }; /** diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp index 2d5f964deb..f444530a17 100644 --- a/indra/llcommon/lleventcoro.cpp +++ b/indra/llcommon/lleventcoro.cpp @@ -34,6 +34,7 @@ #include // std headers // external library headers +#include // other Linden headers #include "llsdserialize.h" #include "llerror.h" @@ -351,7 +352,7 @@ LLSD errorException(const LLEventWithID& result, const std::string& desc) // returning it, deliver it via exception. if (result.second) { - throw LLErrorEvent(desc, result.first); + BOOST_THROW_EXCEPTION(LLErrorEvent(desc, result.first)); } // That way, our caller knows a simple return must be from the reply // pump (pump 0). diff --git a/indra/llcommon/lleventcoro.h b/indra/llcommon/lleventcoro.h index 87926c692d..84827aab4a 100644 --- a/indra/llcommon/lleventcoro.h +++ b/indra/llcommon/lleventcoro.h @@ -31,10 +31,10 @@ #include #include -#include #include // std::pair #include "llevents.h" #include "llerror.h" +#include "llexception.h" /** * Like LLListenerOrPumpName, this is a class intended for parameter lists: @@ -234,11 +234,11 @@ LLSD errorException(const LLEventWithID& result, const std::string& desc); * because it's not an error in event processing: rather, this exception * announces an event that bears error information (for some other API). */ -class LL_COMMON_API LLErrorEvent: public std::runtime_error +class LL_COMMON_API LLErrorEvent: public LLException { public: LLErrorEvent(const std::string& what, const LLSD& data): - std::runtime_error(what), + LLException(what), mData(data) {} virtual ~LLErrorEvent() throw() {} diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 645c29d770..50919edb8e 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -45,6 +45,7 @@ #include // external library headers #include +#include #if LL_WINDOWS #pragma warning (push) #pragma warning (disable : 4701) // compiler thinks might use uninitialized var, but no @@ -174,7 +175,7 @@ std::string LLEventPumps::registerNew(const LLEventPump& pump, const std::string // Unless we're permitted to tweak it, that's Bad. if (! tweak) { - throw LLEventPump::DupPumpName(std::string("Duplicate LLEventPump name '") + name + "'"); + BOOST_THROW_EXCEPTION(LLEventPump::DupPumpName(std::string("Duplicate LLEventPump name '") + name + "'")); } // The passed name isn't unique, but we're permitted to tweak it. Find the // first decimal-integer suffix not already taken. The insert() attempt @@ -326,8 +327,9 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL // is only when the existing connection object is still connected. if (found != mConnections.end() && found->second.connected()) { - throw DupListenerName(std::string("Attempt to register duplicate listener name '") + name + - "' on " + typeid(*this).name() + " '" + getName() + "'"); + BOOST_THROW_EXCEPTION( + DupListenerName(std::string("Attempt to register duplicate listener name '") + name + + "' on " + typeid(*this).name() + " '" + getName() + "'")); } // Okay, name is unique, try to reconcile its dependencies. Specify a new // "node" value that we never use for an mSignal placement; we'll fix it @@ -353,8 +355,9 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL // unsortable. If we leave the new node in mDeps, it will continue // to screw up all future attempts to sort()! Pull it out. mDeps.remove(name); - throw Cycle(std::string("New listener '") + name + "' on " + typeid(*this).name() + - " '" + getName() + "' would cause cycle: " + e.what()); + BOOST_THROW_EXCEPTION( + Cycle(std::string("New listener '") + name + "' on " + typeid(*this).name() + + " '" + getName() + "' would cause cycle: " + e.what())); } // Walk the list to verify that we haven't changed the order. float previous = 0.0, myprev = 0.0; @@ -418,7 +421,7 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL // NOW remove the offending listener node. mDeps.remove(name); // Having constructed a description of the order change, inform caller. - throw OrderChange(out.str()); + BOOST_THROW_EXCEPTION(OrderChange(out.str())); } // This node becomes the previous one. previous = dmi->second; @@ -608,7 +611,7 @@ bool LLListenerOrPumpName::operator()(const LLSD& event) const { if (! mListener) { - throw Empty("attempting to call uninitialized"); + BOOST_THROW_EXCEPTION(Empty("attempting to call uninitialized")); } return (*mListener)(event); } diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index ba4fcd766e..8ff337911d 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -37,7 +37,6 @@ #include #include #include -#include #if LL_WINDOWS #pragma warning (push) #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch @@ -62,6 +61,7 @@ #include "llsingleton.h" #include "lldependencies.h" #include "llstl.h" +#include "llexception.h" /*==========================================================================*| // override this to allow binding free functions with more parameters @@ -188,10 +188,10 @@ public: bool operator()(const LLSD& event) const; /// exception if you try to call when empty - struct Empty: public std::runtime_error + struct Empty: public LLException { Empty(const std::string& what): - std::runtime_error(std::string("LLListenerOrPumpName::Empty: ") + what) {} + LLException(std::string("LLListenerOrPumpName::Empty: ") + what) {} }; private: @@ -371,10 +371,10 @@ public: * you didn't pass tweak=true to permit it to generate a unique * variant. */ - struct DupPumpName: public std::runtime_error + struct DupPumpName: public LLException { DupPumpName(const std::string& what): - std::runtime_error(std::string("DupPumpName: ") + what) {} + LLException(std::string("DupPumpName: ") + what) {} }; /** @@ -399,9 +399,9 @@ public: /// group exceptions thrown by listen(). We use exceptions because these /// particular errors are likely to be coding errors, found and fixed by /// the developer even before preliminary checkin. - struct ListenError: public std::runtime_error + struct ListenError: public LLException { - ListenError(const std::string& what): std::runtime_error(what) {} + ListenError(const std::string& what): LLException(what) {} }; /** * exception thrown by listen(). You are attempting to register a diff --git a/indra/llcommon/llexception.h b/indra/llcommon/llexception.h new file mode 100644 index 0000000000..3ac2f4762f --- /dev/null +++ b/indra/llcommon/llexception.h @@ -0,0 +1,63 @@ +/** + * @file llexception.h + * @author Nat Goodspeed + * @date 2016-06-29 + * @brief Types needed for generic exception handling + * + * $LicenseInfo:firstyear=2016&license=viewerlgpl$ + * Copyright (c) 2016, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLEXCEPTION_H) +#define LL_LLEXCEPTION_H + +#include +#include + +/** + * LLException is intended as the common base class from which all + * viewer-specific exceptions are derived. It is itself a subclass of + * boost::exception; use catch (const boost::exception& e) clause to log the + * string from boost::diagnostic_information(e). + * + * Since it is also derived from std::exception, a generic catch (const + * std::exception&) should also work, though what() is unlikely to be as + * informative as boost::diagnostic_information(). + * + * Please use BOOST_THROW_EXCEPTION() + * http://www.boost.org/doc/libs/release/libs/exception/doc/BOOST_THROW_EXCEPTION.html + * to throw viewer exceptions whenever possible. This enriches the exception's + * diagnostic_information() with the source file, line and containing function + * of the BOOST_THROW_EXCEPTION() macro. + * + * There may be circumstances in which it would be valuable to distinguish an + * exception explicitly thrown by viewer code from an exception thrown by + * (say) a third-party library. Catching (const LLException&) supports such + * usage. However, most of the value of this base class is in the + * diagnostic_information() available via Boost.Exception. + */ +struct LLException: + public std::runtime_error, + public boost::exception +{ + LLException(const std::string& what): + std::runtime_error(what) + {} +}; + +/** + * The point of LLContinueError is to distinguish exceptions that need not + * terminate the whole viewer session. In general, an uncaught exception will + * be logged and will crash the viewer. However, though an uncaught exception + * derived from LLContinueError will still be logged, the viewer will attempt + * to continue processing. + */ +struct LLContinueError: public LLException +{ + LLContinueError(const std::string& what): + LLException(what) + {} +}; + +#endif /* ! defined(LL_LLEXCEPTION_H) */ diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp index 84d2a12f65..a8bb9bc53a 100644 --- a/indra/llcommon/llleap.cpp +++ b/indra/llcommon/llleap.cpp @@ -21,6 +21,7 @@ #include #include #include +#include // other Linden headers #include "llerror.h" #include "llstring.h" @@ -69,7 +70,7 @@ public: // Rule out empty vector if (plugin.empty()) { - throw Error("no plugin command"); + BOOST_THROW_EXCEPTION(Error("no plugin command")); } // Don't leave desc empty either, but in this case, if we weren't @@ -112,7 +113,7 @@ public: // If that didn't work, no point in keeping this LLLeap object. if (! mChild) { - throw Error(STRINGIZE("failed to run " << mDesc)); + BOOST_THROW_EXCEPTION(Error(STRINGIZE("failed to run " << mDesc))); } // Okay, launch apparently worked. Change our mDonePump listener. diff --git a/indra/llcommon/llleap.h b/indra/llcommon/llleap.h index e33f25e530..8aac8a64c5 100644 --- a/indra/llcommon/llleap.h +++ b/indra/llcommon/llleap.h @@ -13,9 +13,9 @@ #define LL_LLLEAP_H #include "llinstancetracker.h" +#include "llexception.h" #include #include -#include /** * LLSD Event API Plugin class. Because instances are managed by @@ -67,9 +67,9 @@ public: * string(s) passed to create() might come from an external source. This * way the caller can catch LLLeap::Error and try to recover. */ - struct Error: public std::runtime_error + struct Error: public LLException { - Error(const std::string& what): std::runtime_error(what) {} + Error(const std::string& what): LLException(what) {} }; virtual ~LLLeap(); diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp index 44f56daf2d..ca19c94736 100644 --- a/indra/llcommon/llprocess.cpp +++ b/indra/llcommon/llprocess.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -472,9 +473,9 @@ private: *****************************************************************************/ /// Need an exception to avoid constructing an invalid LLProcess object, but /// internal use only -struct LLProcessError: public std::runtime_error +struct LLProcessError: public LLException { - LLProcessError(const std::string& msg): std::runtime_error(msg) {} + LLProcessError(const std::string& msg): LLException(msg) {} }; LLProcessPtr LLProcess::create(const LLSDOrParams& params) @@ -530,8 +531,9 @@ LLProcess::LLProcess(const LLSDOrParams& params): if (! params.validateBlock(true)) { - throw LLProcessError(STRINGIZE("not launched: failed parameter validation\n" - << LLSDNotationStreamer(params))); + BOOST_THROW_EXCEPTION( + LLProcessError(STRINGIZE("not launched: failed parameter validation\n" + << LLSDNotationStreamer(params)))); } mPostend = params.postend; @@ -596,10 +598,11 @@ LLProcess::LLProcess(const LLSDOrParams& params): } else { - throw LLProcessError(STRINGIZE("For " << params.executable() - << ": unsupported FileParam for " << which - << ": type='" << fparam.type() - << "', name='" << fparam.name() << "'")); + BOOST_THROW_EXCEPTION( + LLProcessError(STRINGIZE("For " << params.executable() + << ": unsupported FileParam for " << which + << ": type='" << fparam.type() + << "', name='" << fparam.name() << "'"))); } } // By default, pass APR_NO_PIPE for unspecified slots. @@ -678,7 +681,7 @@ LLProcess::LLProcess(const LLSDOrParams& params): if (ll_apr_warn_status(apr_proc_create(&mProcess, argv[0], &argv[0], NULL, procattr, gAPRPoolp))) { - throw LLProcessError(STRINGIZE(params << " failed")); + BOOST_THROW_EXCEPTION(LLProcessError(STRINGIZE(params << " failed"))); } // arrange to call status_callback() @@ -1063,7 +1066,7 @@ PIPETYPE& LLProcess::getPipe(FILESLOT slot) PIPETYPE* wp = getPipePtr(error, slot); if (! wp) { - throw NoPipe(error); + BOOST_THROW_EXCEPTION(NoPipe(error)); } return *wp; } diff --git a/indra/llcommon/llprocess.h b/indra/llcommon/llprocess.h index 43ccadc412..bfac4567a5 100644 --- a/indra/llcommon/llprocess.h +++ b/indra/llcommon/llprocess.h @@ -30,13 +30,13 @@ #include "llinitparam.h" #include "llsdparam.h" #include "llwin32headerslean.h" +#include "llexception.h" #include "apr_thread_proc.h" #include #include #include #include #include // std::ostream -#include #if LL_WINDOWS #include "llwin32headerslean.h" // for HANDLE @@ -479,9 +479,9 @@ public: /// Exception thrown by getWritePipe(), getReadPipe() if you didn't ask to /// create a pipe at the corresponding FILESLOT. - struct NoPipe: public std::runtime_error + struct NoPipe: public LLException { - NoPipe(const std::string& what): std::runtime_error(what) {} + NoPipe(const std::string& what): LLException(what) {} }; /** diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp index 185f0d63fb..a004618e96 100644 --- a/indra/llcommon/llthreadsafequeue.cpp +++ b/indra/llcommon/llthreadsafequeue.cpp @@ -26,6 +26,7 @@ #include "linden_common.h" #include #include +#include #include "llthreadsafequeue.h" @@ -41,13 +42,13 @@ LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * po { if(mOwnsPool) { apr_status_t status = apr_pool_create(&mPool, 0); - if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate pool"); + if(status != APR_SUCCESS) BOOST_THROW_EXCEPTION(LLThreadSafeQueueError("failed to allocate pool")); } else { ; // No op. } apr_status_t status = apr_queue_create(&mQueue, capacity, mPool); - if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate queue"); + if(status != APR_SUCCESS) BOOST_THROW_EXCEPTION(LLThreadSafeQueueError("failed to allocate queue")); } @@ -68,9 +69,9 @@ void LLThreadSafeQueueImplementation::pushFront(void * element) apr_status_t status = apr_queue_push(mQueue, element); if(status == APR_EINTR) { - throw LLThreadSafeQueueInterrupt(); + BOOST_THROW_EXCEPTION(LLThreadSafeQueueInterrupt()); } else if(status != APR_SUCCESS) { - throw LLThreadSafeQueueError("push failed"); + BOOST_THROW_EXCEPTION(LLThreadSafeQueueError("push failed")); } else { ; // Success. } @@ -88,9 +89,9 @@ void * LLThreadSafeQueueImplementation::popBack(void) apr_status_t status = apr_queue_pop(mQueue, &element); if(status == APR_EINTR) { - throw LLThreadSafeQueueInterrupt(); + BOOST_THROW_EXCEPTION(LLThreadSafeQueueInterrupt()); } else if(status != APR_SUCCESS) { - throw LLThreadSafeQueueError("pop failed"); + BOOST_THROW_EXCEPTION(LLThreadSafeQueueError("pop failed")); } else { return element; } diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h index 58cac38769..45289ef0b4 100644 --- a/indra/llcommon/llthreadsafequeue.h +++ b/indra/llcommon/llthreadsafequeue.h @@ -27,9 +27,8 @@ #ifndef LL_LLTHREADSAFEQUEUE_H #define LL_LLTHREADSAFEQUEUE_H - +#include "llexception.h" #include -#include struct apr_pool_t; // From apr_pools.h @@ -40,11 +39,11 @@ class LLThreadSafeQueueImplementation; // See below. // A general queue exception. // class LL_COMMON_API LLThreadSafeQueueError: -public std::runtime_error + public LLException { public: LLThreadSafeQueueError(std::string const & message): - std::runtime_error(message) + LLException(message) { ; // No op. } diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index e3671047b4..785cf47926 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -83,7 +83,7 @@ unsigned int decode( char const * fiveChars ) throw( bad_input_data ) unsigned int ret = 0; for( int ix = 0; ix < 5; ++ix ) { char * s = strchr( encodeTable, fiveChars[ ix ] ); -if( s == 0 ) throw bad_input_data(); +if( s == 0 ) BOOST_THROW_EXCEPTION(bad_input_data()); ret = ret * 85 + (s-encodeTable); } return ret; diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h index 785197ba11..fa16fd6915 100644 --- a/indra/llcommon/tests/wrapllerrs.h +++ b/indra/llcommon/tests/wrapllerrs.h @@ -35,13 +35,14 @@ #include #include "llerrorcontrol.h" +#include "llexception.h" #include "stringize.h" #include #include #include +#include #include #include -#include // statically reference the function in test.cpp... it's short, we could // replicate, but better to reuse @@ -67,9 +68,9 @@ struct WrapLLErrs LLError::restoreSettings(mPriorErrorSettings); } - struct FatalException: public std::runtime_error + struct FatalException: public LLException { - FatalException(const std::string& what): std::runtime_error(what) {} + FatalException(const std::string& what): LLException(what) {} }; void operator()(const std::string& message) @@ -78,7 +79,7 @@ struct WrapLLErrs error = message; // Also throw an appropriate exception since calling code is likely to // assume that control won't continue beyond LL_ERRS. - throw FatalException(message); + BOOST_THROW_EXCEPTION(FatalException(message)); } std::string error; diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp index 531859cbc9..0b7d4c717f 100644 --- a/indra/llimage/llpngwrapper.cpp +++ b/indra/llimage/llpngwrapper.cpp @@ -31,12 +31,13 @@ #include "llimage.h" #include "llpngwrapper.h" -#include +#include "llexception.h" +#include namespace { -struct PngError: public std::runtime_error +struct PngError: public LLException { - PngError(png_const_charp msg): std::runtime_error(msg) {} + PngError(png_const_charp msg): LLException(msg) {} }; } // anonymous namespace @@ -87,7 +88,7 @@ BOOL LLPngWrapper::isValidPng(U8* src) // occurs. We throw PngError and let our try/catch block clean up. void LLPngWrapper::errorHandler(png_structp png_ptr, png_const_charp msg) { - throw PngError(msg); + BOOST_THROW_EXCEPTION(PngError(msg)); } // Called by the libpng library when reading (decoding) the PNG file. We @@ -137,7 +138,7 @@ BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInf this, &errorHandler, NULL); if (mReadPngPtr == NULL) { - throw PngError("Problem creating png read structure"); + BOOST_THROW_EXCEPTION(PngError("Problem creating png read structure")); } // Allocate/initialize the memory for image information. @@ -296,14 +297,14 @@ BOOL LLPngWrapper::writePng(const LLImageRaw* rawImage, U8* dest) if (mColorType == -1) { - throw PngError("Unsupported image: unexpected number of channels"); + BOOST_THROW_EXCEPTION(PngError("Unsupported image: unexpected number of channels")); } mWritePngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, &errorHandler, NULL); if (!mWritePngPtr) { - throw PngError("Problem creating png write structure"); + BOOST_THROW_EXCEPTION(PngError("Problem creating png write structure")); } mWriteInfoPtr = png_create_info_struct(mWritePngPtr); diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index 2a5b24fbc1..fa58931407 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -34,12 +34,13 @@ #include "kdu_block_coding.h" -#include +#include "llexception.h" +#include namespace { -struct KDUError: public std::runtime_error +struct KDUError: public LLException { - KDUError(const std::string& msg): std::runtime_error(msg) {} + KDUError(const std::string& msg): LLException(msg) {} }; } // anonymous namespace @@ -180,7 +181,7 @@ void LLKDUMessageError::flush(bool end_of_message) { if (end_of_message) { - throw KDUError("LLKDUMessageError::flush()"); + BOOST_THROW_EXCEPTION(KDUError("LLKDUMessageError::flush()")); } } diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp index 08688ca48b..48ce258ba2 100644 --- a/indra/llmessage/llhttpnode.cpp +++ b/indra/llmessage/llhttpnode.cpp @@ -31,7 +31,8 @@ #include "llstl.h" #include "llhttpconstants.h" -#include +#include "llexception.h" +#include const std::string CONTEXT_HEADERS("headers"); const std::string CONTEXT_PATH("path"); @@ -93,28 +94,28 @@ LLHTTPNode::~LLHTTPNode() namespace { - struct NotImplemented: public std::runtime_error + struct NotImplemented: public LLException { - NotImplemented(): std::runtime_error("LLHTTPNode::NotImplemented") {} + NotImplemented(): LLException("LLHTTPNode::NotImplemented") {} }; } // virtual LLSD LLHTTPNode::simpleGet() const { - throw NotImplemented(); + BOOST_THROW_EXCEPTION(NotImplemented()); } // virtual LLSD LLHTTPNode::simplePut(const LLSD& input) const { - throw NotImplemented(); + BOOST_THROW_EXCEPTION(NotImplemented()); } // virtual LLSD LLHTTPNode::simplePost(const LLSD& input) const { - throw NotImplemented(); + BOOST_THROW_EXCEPTION(NotImplemented()); } @@ -174,7 +175,7 @@ void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) cons // virtual LLSD LLHTTPNode::simpleDel(const LLSD&) const { - throw NotImplemented(); + BOOST_THROW_EXCEPTION(NotImplemented()); } // virtual diff --git a/indra/llmessage/tests/commtest.h b/indra/llmessage/tests/commtest.h index 0d149b5258..5dff56b44f 100644 --- a/indra/llmessage/tests/commtest.h +++ b/indra/llmessage/tests/commtest.h @@ -33,15 +33,16 @@ #include "llevents.h" #include "llsd.h" #include "llhost.h" +#include "llexception.h" #include "stringize.h" #include #include -#include #include +#include -struct CommtestError: public std::runtime_error +struct CommtestError: public LLException { - CommtestError(const std::string& what): std::runtime_error(what) {} + CommtestError(const std::string& what): LLException(what) {} }; static bool query_verbose() @@ -68,7 +69,7 @@ static int query_port(const std::string& var) const char* cport = getenv(var.c_str()); if (! cport) { - throw CommtestError(STRINGIZE("missing environment variable" << var)); + BOOST_THROW_EXCEPTION(CommtestError(STRINGIZE("missing environment variable" << var))); } // This will throw, too, if the value of PORT isn't numeric. int port(boost::lexical_cast(cport)); diff --git a/indra/llmessage/tests/networkio.h b/indra/llmessage/tests/networkio.h index 2aff90ca1e..6aaecf9bac 100644 --- a/indra/llmessage/tests/networkio.h +++ b/indra/llmessage/tests/networkio.h @@ -34,6 +34,8 @@ #include "llares.h" #include "llpumpio.h" #include "llhttpclient.h" +#include "llexception.h" +#include /***************************************************************************** * NetworkIO @@ -51,7 +53,7 @@ public: ll_init_apr(); if (! gAPRPoolp) { - throw std::runtime_error("Can't initialize APR"); + BOOST_THROW_EXCEPTION(LLException("Can't initialize APR")); } // Create IO Pump to use for HTTP Requests. @@ -59,7 +61,7 @@ public: LLHTTPClient::setPump(*mServicePump); if (ll_init_ares() == NULL || !gAres->isInitialized()) { - throw std::runtime_error("Can't start DNS resolver"); + BOOST_THROW_EXCEPTION(LLException("Can't start DNS resolver")); } // You can interrupt pump() without waiting the full timeout duration diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index a812a5e518..fdef556589 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -122,6 +122,7 @@ #include "llleap.h" #include "stringize.h" #include "llcoros.h" +#include "llexception.h" #if !LL_LINUX #include "cef/llceflib.h" #endif @@ -131,6 +132,7 @@ #include #include #include +#include #if LL_WINDOWS # include // For _SH_DENYWR in processMarkerFiles @@ -231,8 +233,6 @@ #include "llcoproceduremanager.h" #include "llviewereventrecorder.h" -#include - // *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 @@ -5513,7 +5513,7 @@ void LLAppViewer::forceErrorInfiniteLoop() void LLAppViewer::forceErrorSoftwareException() { LL_WARNS() << "Forcing a deliberate exception" << LL_ENDL; - throw std::runtime_error("User selected Force Software Exception"); + BOOST_THROW_EXCEPTION(LLException("User selected Force Software Exception")); } void LLAppViewer::forceErrorDriverCrash() diff --git a/indra/newview/llcommandlineparser.cpp b/indra/newview/llcommandlineparser.cpp index 1819fc74ee..54f96b8872 100644 --- a/indra/newview/llcommandlineparser.cpp +++ b/indra/newview/llcommandlineparser.cpp @@ -26,6 +26,7 @@ #include "llviewerprecompiledheaders.h" #include "llcommandlineparser.h" +#include "llexception.h" // *NOTE: The boost::lexical_cast generates // the warning C4701(local used with out assignment) in VC7.1. @@ -42,6 +43,7 @@ #include #include #include +#include #if _MSC_VER # pragma warning(pop) @@ -98,14 +100,14 @@ namespace bool gPastLastOption = false; } -class LLCLPError : public std::logic_error { +class LLCLPError : public LLException { public: - LLCLPError(const std::string& what) : std::logic_error(what) {} + LLCLPError(const std::string& what) : LLException(what) {} }; -class LLCLPLastOption : public std::logic_error { +class LLCLPLastOption : public LLException { public: - LLCLPLastOption(const std::string& what) : std::logic_error(what) {} + LLCLPLastOption(const std::string& what) : LLException(what) {} }; class LLCLPValue : public po::value_semantic_codecvt_helper @@ -202,17 +204,17 @@ protected: { if(gPastLastOption) { - throw(LLCLPLastOption("Don't parse no more!")); + BOOST_THROW_EXCEPTION(LLCLPLastOption("Don't parse no more!")); } // Error checks. Needed? if (!value_store.empty() && !is_composing()) { - throw(LLCLPError("Non composing value with multiple occurences.")); + BOOST_THROW_EXCEPTION(LLCLPError("Non composing value with multiple occurences.")); } if (new_tokens.size() < min_tokens() || new_tokens.size() > max_tokens()) { - throw(LLCLPError("Illegal number of tokens specified.")); + BOOST_THROW_EXCEPTION(LLCLPError("Illegal number of tokens specified.")); } if(value_store.empty()) @@ -466,7 +468,7 @@ onevalue(const std::string& option, { // What does it mean when the user specifies a command-line switch // that requires a value, but omits the value? Complain. - throw LLCLPError(STRINGIZE("No value specified for --" << option << "!")); + BOOST_THROW_EXCEPTION(LLCLPError(STRINGIZE("No value specified for --" << option << "!"))); } else if (value.size() > 1) { @@ -484,9 +486,10 @@ void badvalue(const std::string& option, // If the user passes an unusable value for a command-line switch, it // seems like a really bad idea to just ignore it, even with a log // warning. - throw LLCLPError(STRINGIZE("Invalid value specified by command-line switch '" << option - << "' for variable '" << varname << "' of type " << type - << ": '" << value << "'")); + BOOST_THROW_EXCEPTION( + LLCLPError(STRINGIZE("Invalid value specified by command-line switch '" << option + << "' for variable '" << varname << "' of type " << type + << ": '" << value << "'"))); } template diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp index e871570786..bcb9417820 100644 --- a/indra/newview/llsecapi.cpp +++ b/indra/newview/llsecapi.cpp @@ -29,6 +29,7 @@ #include "llviewerprecompiledheaders.h" #include "llsecapi.h" #include "llsechandler_basic.h" +#include #include #include #include @@ -69,7 +70,7 @@ void initializeSecHandler() } if (!exception_msg.empty()) // an exception was thrown. { - throw LLProtectedDataException(exception_msg); + BOOST_THROW_EXCEPTION(LLProtectedDataException(exception_msg)); } } diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index 535a112638..6af5a28fa5 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -32,7 +32,7 @@ #include #include #include "llpointer.h" -#include +#include "llexception.h" #ifdef LL_WINDOWS #pragma warning(disable:4250) @@ -117,10 +117,10 @@ -struct LLProtectedDataException: public std::runtime_error +struct LLProtectedDataException: public LLException { LLProtectedDataException(const std::string& msg): - std::runtime_error(msg) + LLException(msg) { LL_WARNS("SECAPI") << "Protected Data Error: " << msg << LL_ENDL; } @@ -331,11 +331,11 @@ std::ostream& operator <<(std::ostream& s, const LLCredential& cred); // All error handling is via exceptions. -class LLCertException: public std::runtime_error +class LLCertException: public LLException { public: LLCertException(LLPointer cert, const std::string& msg): - std::runtime_error(msg) + LLException(msg) { mCert = cert; diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index 40516f9bbb..39ce64ad0e 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -35,6 +35,7 @@ #include "llfile.h" #include "lldir.h" #include "llviewercontrol.h" +#include #include #include #include @@ -72,14 +73,14 @@ LLBasicCertificate::LLBasicCertificate(const std::string& pem_cert) if(pem_bio == NULL) { LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL; - throw LLInvalidCertificate(this); + BOOST_THROW_EXCEPTION(LLInvalidCertificate(this)); } mCert = NULL; PEM_read_bio_X509(pem_bio, &mCert, 0, NULL); BIO_free(pem_bio); if (!mCert) { - throw LLInvalidCertificate(this); + BOOST_THROW_EXCEPTION(LLInvalidCertificate(this)); } } @@ -88,7 +89,7 @@ LLBasicCertificate::LLBasicCertificate(X509* pCert) { if (!pCert || !pCert->cert_info) { - throw LLInvalidCertificate(this); + BOOST_THROW_EXCEPTION(LLInvalidCertificate(this)); } mCert = X509_dup(pCert); } @@ -873,22 +874,22 @@ void _validateCert(int validation_policy, // check basic properties exist in the cert if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info.has(CERT_SUBJECT_NAME_STRING)) { - throw LLCertException(cert, "Cert doesn't have a Subject Name"); + BOOST_THROW_EXCEPTION(LLCertException(cert, "Cert doesn't have a Subject Name")); } if(!current_cert_info.has(CERT_ISSUER_NAME_STRING)) { - throw LLCertException(cert, "Cert doesn't have an Issuer Name"); + BOOST_THROW_EXCEPTION(LLCertException(cert, "Cert doesn't have an Issuer Name")); } // check basic properties exist in the cert if(!current_cert_info.has(CERT_VALID_FROM) || !current_cert_info.has(CERT_VALID_TO)) { - throw LLCertException(cert, "Cert doesn't have an expiration period"); + BOOST_THROW_EXCEPTION(LLCertException(cert, "Cert doesn't have an expiration period")); } if (!current_cert_info.has(CERT_SHA1_DIGEST)) { - throw LLCertException(cert, "No SHA1 digest"); + BOOST_THROW_EXCEPTION(LLCertException(cert, "No SHA1 digest")); } if (validation_policy & VALIDATION_POLICY_TIME) @@ -903,7 +904,7 @@ void _validateCert(int validation_policy, if((validation_date < current_cert_info[CERT_VALID_FROM].asDate()) || (validation_date > current_cert_info[CERT_VALID_TO].asDate())) { - throw LLCertValidationExpirationException(cert, validation_date); + BOOST_THROW_EXCEPTION(LLCertValidationExpirationException(cert, validation_date)); } } if (validation_policy & VALIDATION_POLICY_SSL_KU) @@ -914,14 +915,14 @@ void _validateCert(int validation_policy, !(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], LLSD((std::string)CERT_KU_KEY_ENCIPHERMENT))))) { - throw LLCertKeyUsageValidationException(cert); + BOOST_THROW_EXCEPTION(LLCertKeyUsageValidationException(cert)); } // only validate EKU if the cert has it if(current_cert_info.has(CERT_EXTENDED_KEY_USAGE) && current_cert_info[CERT_EXTENDED_KEY_USAGE].isArray() && (!_LLSDArrayIncludesValue(current_cert_info[CERT_EXTENDED_KEY_USAGE], LLSD((std::string)CERT_EKU_SERVER_AUTH)))) { - throw LLCertKeyUsageValidationException(cert); + BOOST_THROW_EXCEPTION(LLCertKeyUsageValidationException(cert)); } } if (validation_policy & VALIDATION_POLICY_CA_KU) @@ -930,7 +931,7 @@ void _validateCert(int validation_policy, (!_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], (std::string)CERT_KU_CERT_SIGN))) { - throw LLCertKeyUsageValidationException(cert); + BOOST_THROW_EXCEPTION(LLCertKeyUsageValidationException(cert)); } } @@ -942,13 +943,13 @@ void _validateCert(int validation_policy, if(!current_cert_info[CERT_BASIC_CONSTRAINTS].has(CERT_BASIC_CONSTRAINTS_CA) || !current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_CA]) { - throw LLCertBasicConstraintsValidationException(cert); + BOOST_THROW_EXCEPTION(LLCertBasicConstraintsValidationException(cert)); } if (current_cert_info[CERT_BASIC_CONSTRAINTS].has(CERT_BASIC_CONSTRAINTS_PATHLEN) && ((current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_PATHLEN].asInteger() != 0) && (depth > current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_PATHLEN].asInteger()))) { - throw LLCertBasicConstraintsValidationException(cert); + BOOST_THROW_EXCEPTION(LLCertBasicConstraintsValidationException(cert)); } } } @@ -1018,7 +1019,7 @@ void LLBasicCertificateStore::validate(int validation_policy, if(cert_chain->size() < 1) { - throw LLCertException(NULL, "No certs in chain"); + BOOST_THROW_EXCEPTION(LLCertException(NULL, "No certs in chain")); } iterator current_cert = cert_chain->begin(); LLSD current_cert_info; @@ -1033,11 +1034,11 @@ void LLBasicCertificateStore::validate(int validation_policy, (*current_cert)->getLLSD(current_cert_info); if(!validation_params.has(CERT_HOSTNAME)) { - throw LLCertException((*current_cert), "No hostname passed in for validation"); + BOOST_THROW_EXCEPTION(LLCertException((*current_cert), "No hostname passed in for validation")); } if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info[CERT_SUBJECT_NAME].has(CERT_NAME_CN)) { - throw LLInvalidCertificate((*current_cert)); + BOOST_THROW_EXCEPTION(LLInvalidCertificate((*current_cert))); } LL_DEBUGS("SECAPI") << "Validating the hostname " << validation_params[CERT_HOSTNAME].asString() << @@ -1054,7 +1055,7 @@ void LLBasicCertificateStore::validate(int validation_policy, X509* cert_x509 = (*current_cert)->getOpenSSLX509(); if(!cert_x509) { - throw LLInvalidCertificate((*current_cert)); + BOOST_THROW_EXCEPTION(LLInvalidCertificate((*current_cert))); } std::string sha1_hash((const char *)cert_x509->sha1_hash, SHA_DIGEST_LENGTH); X509_free( cert_x509 ); @@ -1075,7 +1076,7 @@ void LLBasicCertificateStore::validate(int validation_policy, if((validation_date < cache_entry->second.first) || (validation_date > cache_entry->second.second)) { - throw LLCertValidationExpirationException((*current_cert), validation_date); + BOOST_THROW_EXCEPTION(LLCertValidationExpirationException((*current_cert), validation_date)); } } // successfully found in cache @@ -1107,7 +1108,7 @@ void LLBasicCertificateStore::validate(int validation_policy, if(!_verify_signature((*current_cert), previous_cert)) { - throw LLCertValidationInvalidSignatureException(previous_cert); + BOOST_THROW_EXCEPTION(LLCertValidationInvalidSignatureException(previous_cert)); } } _validateCert(local_validation_policy, @@ -1156,7 +1157,7 @@ void LLBasicCertificateStore::validate(int validation_policy, if(!_verify_signature((*found_store_cert), (*current_cert))) { - throw LLCertValidationInvalidSignatureException(*current_cert); + BOOST_THROW_EXCEPTION(LLCertValidationInvalidSignatureException(*current_cert)); } // successfully validated. mTrustedCertCache[sha1_hash] = std::pair(from_time, to_time); @@ -1173,7 +1174,7 @@ void LLBasicCertificateStore::validate(int validation_policy, if (validation_policy & VALIDATION_POLICY_TRUSTED) { // we reached the end without finding a trusted cert. - throw LLCertValidationTrustException((*cert_chain)[cert_chain->size()-1]); + BOOST_THROW_EXCEPTION(LLCertValidationTrustException((*cert_chain)[cert_chain->size()-1])); } mTrustedCertCache[sha1_hash] = std::pair(from_time, to_time); @@ -1261,7 +1262,7 @@ void LLSecAPIBasicHandler::_readProtectedData() protected_data_stream.read((char *)salt, STORE_SALT_SIZE); if (protected_data_stream.gcount() < STORE_SALT_SIZE) { - throw LLProtectedDataException("Config file too short."); + BOOST_THROW_EXCEPTION(LLProtectedDataException("Config file too short.")); } cipher.decrypt(salt, STORE_SALT_SIZE); @@ -1301,7 +1302,7 @@ void LLSecAPIBasicHandler::_readProtectedData() if (parser->parse(parse_stream, mProtectedDataMap, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) { - throw LLProtectedDataException("Config file cannot be decrypted."); + BOOST_THROW_EXCEPTION(LLProtectedDataException("Config file cannot be decrypted.")); } } } @@ -1372,7 +1373,7 @@ void LLSecAPIBasicHandler::_writeProtectedData() // EXP-1825 crash in LLSecAPIBasicHandler::_writeProtectedData() // Decided throwing an exception here was overkill until we figure out why this happens - //throw LLProtectedDataException("Error writing Protected Data Store"); + //BOOST_THROW_EXCEPTION(LLProtectedDataException("Error writing Protected Data Store")); } try @@ -1387,7 +1388,7 @@ void LLSecAPIBasicHandler::_writeProtectedData() // EXP-1825 crash in LLSecAPIBasicHandler::_writeProtectedData() // Decided throwing an exception here was overkill until we figure out why this happens - //throw LLProtectedDataException("Could not overwrite protected data store"); + //BOOST_THROW_EXCEPTION(LLProtectedDataException("Could not overwrite protected data store")); } } catch (...) @@ -1401,7 +1402,7 @@ void LLSecAPIBasicHandler::_writeProtectedData() //crash in LLSecAPIBasicHandler::_writeProtectedData() // Decided throwing an exception here was overkill until we figure out why this happens - //throw LLProtectedDataException("Error writing Protected Data Store"); + //BOOST_THROW_EXCEPTION(LLProtectedDataException("Error writing Protected Data Store")); } } diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index 382689afa0..cd4b108c1a 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -27,9 +27,10 @@ #include "llupdatedownloader.h" #include "httpcommon.h" -#include +#include "llexception.h" #include #include +#include #include #include "lldir.h" #include "llevents.h" @@ -85,11 +86,11 @@ private: namespace { class DownloadError: - public std::runtime_error + public LLException { public: DownloadError(const char * message): - std::runtime_error(message) + LLException(message) { ; // No op. } @@ -467,7 +468,7 @@ void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & u if(!mCurl) { - throw DownloadError("failed to initialize curl"); + BOOST_THROW_EXCEPTION(DownloadError("failed to initialize curl")); } throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_NOSIGNAL, true)); throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_FOLLOWLOCATION, true)); @@ -508,7 +509,7 @@ void LLUpdateDownloader::Implementation::resumeDownloading(size_t startByte) mHeaderList = curl_slist_append(mHeaderList, rangeHeaderFormat.str().c_str()); if(mHeaderList == 0) { - throw DownloadError("cannot add Range header"); + BOOST_THROW_EXCEPTION(DownloadError("cannot add Range header")); } throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_HTTPHEADER, mHeaderList)); @@ -524,7 +525,7 @@ void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std mDownloadData["hash"] = hash; mDownloadData["current_version"] = ll_get_version(); LLSD path = uri.pathArray(); - if(path.size() == 0) throw DownloadError("no file path"); + if(path.size() == 0) BOOST_THROW_EXCEPTION(DownloadError("no file path")); std::string fileName = path[path.size() - 1].asString(); std::string filePath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, fileName); mDownloadData["path"] = filePath; @@ -547,9 +548,9 @@ void LLUpdateDownloader::Implementation::throwOnCurlError(CURLcode code) if(code != CURLE_OK) { const char * errorString = curl_easy_strerror(code); if(errorString != 0) { - throw DownloadError(curl_easy_strerror(code)); + BOOST_THROW_EXCEPTION(DownloadError(curl_easy_strerror(code))); } else { - throw DownloadError("unknown curl error"); + BOOST_THROW_EXCEPTION(DownloadError("unknown curl error")); } } else { ; // No op. diff --git a/indra/viewer_components/updater/llupdateinstaller.cpp b/indra/viewer_components/updater/llupdateinstaller.cpp index 4432c6574e..9f9a08f590 100644 --- a/indra/viewer_components/updater/llupdateinstaller.cpp +++ b/indra/viewer_components/updater/llupdateinstaller.cpp @@ -30,17 +30,18 @@ #include "llupdateinstaller.h" #include "lldir.h" #include "llsd.h" +#include "llexception.h" #if defined(LL_WINDOWS) #pragma warning(disable: 4702) // disable 'unreachable code' so we can use lexical_cast (really!). #endif #include -#include +#include namespace { - struct RelocateError: public std::runtime_error + struct RelocateError: public LLException { - RelocateError(): std::runtime_error("llupdateinstaller: RelocateError") {} + RelocateError(): LLException("llupdateinstaller: RelocateError") {} }; std::string copy_to_temp(std::string const & path) @@ -48,7 +49,7 @@ namespace { std::string scriptFile = gDirUtilp->getBaseFileName(path); std::string newPath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, scriptFile); apr_status_t status = apr_file_copy(path.c_str(), newPath.c_str(), APR_FILE_SOURCE_PERMS, gAPRPoolp); - if(status != APR_SUCCESS) throw RelocateError(); + if(status != APR_SUCCESS) BOOST_THROW_EXCEPTION(RelocateError()); return newPath; } diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp index 788955a1b2..0bdd1ede43 100644 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -35,6 +35,7 @@ #include #include +#include #include "lldir.h" #include "llsdserialize.h" #include "llfile.h" @@ -190,8 +191,9 @@ void LLUpdaterServiceImpl::initialize(const std::string& channel, { if(mIsChecking || mIsDownloading) { - throw LLUpdaterService::UsageError("LLUpdaterService::initialize call " - "while updater is running."); + BOOST_THROW_EXCEPTION( + LLUpdaterService::UsageError("LLUpdaterService::initialize call " + "while updater is running.")); } mChannel = channel; @@ -222,8 +224,9 @@ void LLUpdaterServiceImpl::startChecking(bool install_if_ready) { if(mChannel.empty() || mVersion.empty()) { - throw LLUpdaterService::UsageError("Set params before call to " - "LLUpdaterService::startCheck()."); + BOOST_THROW_EXCEPTION( + LLUpdaterService::UsageError("Set params before call to " + "LLUpdaterService::startCheck().")); } mIsChecking = true; diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h index 95bbe1695c..78e8c6b290 100644 --- a/indra/viewer_components/updater/llupdaterservice.h +++ b/indra/viewer_components/updater/llupdaterservice.h @@ -29,16 +29,17 @@ #include #include #include "llhasheduniqueid.h" +#include "llexception.h" class LLUpdaterServiceImpl; class LLUpdaterService { public: - class UsageError: public std::runtime_error + class UsageError: public LLException { public: - UsageError(const std::string& msg) : std::runtime_error(msg) {} + UsageError(const std::string& msg) : LLException(msg) {} }; // Name of the event pump through which update events will be delivered. -- cgit v1.3 From 0b4b1219459d123d62d4b6e332781416e73e6666 Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Wed, 20 Jul 2016 14:56:49 -0700 Subject: MAINT-6570: Changes for LLCheckedHandle plus some timeout issues from AndreyK regarding script compiles/resets. --- indra/llcommon/llhandle.h | 85 ++ indra/newview/app_settings/settings.xml | 11 + indra/newview/llcompilequeue.cpp | 900 ++++++++++++--------- indra/newview/llcompilequeue.h | 86 +- indra/newview/llviewermenu.cpp | 13 +- .../skins/default/xui/en/floater_script_queue.xml | 8 + 6 files changed, 648 insertions(+), 455 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llhandle.h b/indra/llcommon/llhandle.h index 401e4d759a..dfbfb91fc1 100644 --- a/indra/llcommon/llhandle.h +++ b/indra/llcommon/llhandle.h @@ -213,4 +213,89 @@ private: mutable LLRootHandle mHandle; }; +/* + * $TODO: Derive from LLException + */ +struct LLExeceptionStaleHandle : public std::runtime_error +{ +public: + LLExeceptionStaleHandle(): + std::runtime_error("Attempt to access stale handle.") + {} +}; + +/** + * This is a simple wrapper for Handles, allowing direct calls to the underlying + * pointer. The checked handle will throw a LLExeceptionStaleHandle if an attempt + * is made to access the object referenced by the handle and that object has + * been destroyed. + **/ +template +class LLCheckedHandle: private boost::noncopyable +{ +public: + LLCheckedHandle(LLHandle handle): + mHandle(handle) + { } + + /** + * Retrieve the underlying pointer by resolving the handle. If the handle + * returns NULL for the pointer throw an LLExeceptionStaleHandle exception. + */ + T* get() const + { + T* ptr = mHandle.get(); + if (!ptr) + BOOST_THROW_EXCEPTION(LLExeceptionStaleHandle()); + return ptr; + } + + /** + * Test the handle to see if it is still valid. Returns true if it is, + * false if it is not. Does not trow. + */ + bool test() const + { + return (mHandle.get() != NULL); + } + + /** + * Test the underlying handle. If it is no longer valid, throw a LLExeceptionStaleHandle. + */ + void check() const + { + get(); + } + + /** + * Get the contained handle. + */ + LLHandle getHandle() const + { + return mHandle; + } + + /** + * Converts the LLCheckedHandle to a bool. Allows for if (chkdHandle) {} + * Does not throw. + */ + operator bool() const + { + return test(); + } + + /** + * Attempt to call a method or access a member in the structure referenced + * by the handle. If the handle no longer points to a valid structure + * throw a LLExeceptionStaleHandle. + */ + T* operator ->() const + { + return get(); + } + +private: + LLHandle mHandle; +}; + #endif diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index a8d42be2a1..29bfc746d1 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3701,6 +3701,17 @@ Value 1 + QueueInventoryFetchTimeout + + Comment + Max time llcompilequeue will wait for inventory fetch to complete (in seconds) + Persist + 1 + Type + F32 + Value + 300.0 + FindLandArea Comment diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp index 219bcf0eb0..f16a89bd88 100644 --- a/indra/newview/llcompilequeue.cpp +++ b/indra/newview/llcompilequeue.cpp @@ -62,6 +62,59 @@ #include "llviewerassetupload.h" #include "llcorehttputil.h" +namespace +{ + + const std::string QUEUE_EVENTPUMP_NAME("ScriptActionQueue"); + + // ObjectIventoryFetcher is an adapter between the LLVOInventoryListener::inventoryChanged + // callback mechanism and the LLEventPump coroutine architecture allowing the + // coroutine to wait for the inventory event. + class ObjectInventoryFetcher: public LLVOInventoryListener + { + public: + typedef boost::shared_ptr ptr_t; + + ObjectInventoryFetcher(LLEventPump &pump, LLViewerObject* object, void* user_data) : + mPump(pump), + LLVOInventoryListener() + { + registerVOInventoryListener(object, this); + } + + virtual void inventoryChanged(LLViewerObject* object, + LLInventoryObject::object_list_t* inventory, + S32 serial_num, + void* user_data); + + void fetchInventory() + { + requestVOInventory(); + } + + const LLInventoryObject::object_list_t & getInventoryList() const { return mInventoryList; } + + private: + LLInventoryObject::object_list_t mInventoryList; + LLEventPump & mPump; + }; + + class HandleScriptUserData + { + public: + HandleScriptUserData(const std::string &pumpname) : + mPumpname(pumpname) + { } + + const std::string &getPumpName() const { return mPumpname; } + + private: + std::string mPumpname; + }; + + +} + // *NOTE$: A minor specialization of LLScriptAssetUpload, it does not require a buffer // (and does not save a buffer to the vFS) and it finds the compile queue window and // displays a compiling message. @@ -93,7 +146,7 @@ public: queue->getChild("queue output")->addSimpleElement(message, ADD_BOTTOM); } - return LLSD().with("success", LLSD::Boolean(true)); + return LLSDMap("success", LLSD::Boolean(true)); } @@ -149,47 +202,6 @@ BOOL LLFloaterScriptQueue::postBuild() return TRUE; } -// This is the callback method for the viewer object currently being -// worked on. -// NOT static, virtual! -void LLFloaterScriptQueue::inventoryChanged(LLViewerObject* viewer_object, - LLInventoryObject::object_list_t* inv, - S32, - void* q_id) -{ - LL_INFOS() << "LLFloaterScriptQueue::inventoryChanged() for object " - << viewer_object->getID() << LL_ENDL; - - //Remove this listener from the object since its - //listener callback is now being executed. - - //We remove the listener here because the function - //removeVOInventoryListener removes the listener from a ViewerObject - //which it internally stores. - - //If we call this further down in the function, calls to handleInventory - //and nextObject may update the internally stored viewer object causing - //the removal of the incorrect listener from an incorrect object. - - //Fixes SL-6119:Recompile scripts fails to complete - removeVOInventoryListener(); - - if (viewer_object && inv && (viewer_object->getID() == mCurrentObjectID) ) - { - handleInventory(viewer_object, inv); - } - else - { - // something went wrong... - // note that we're not working on this one, and move onto the - // next object in the list. - LL_WARNS() << "No inventory for " << mCurrentObjectID - << LL_ENDL; - nextObject(); - } -} - - // static void LLFloaterScriptQueue::onCloseBtn(void* user_data) { @@ -197,9 +209,10 @@ void LLFloaterScriptQueue::onCloseBtn(void* user_data) self->closeFloater(); } -void LLFloaterScriptQueue::addObject(const LLUUID& id) +void LLFloaterScriptQueue::addObject(const LLUUID& id, std::string name) { - mObjectIDs.push_back(id); + ObjectData obj = { id, name }; + mObjectList.push_back(obj); } BOOL LLFloaterScriptQueue::start() @@ -208,7 +221,7 @@ BOOL LLFloaterScriptQueue::start() LLStringUtil::format_map_t args; args["[START]"] = mStartString; - args["[COUNT]"] = llformat ("%d", mObjectIDs.size()); + args["[COUNT]"] = llformat ("%d", mObjectList.size()); buffer = getString ("Starting", args); getChild("queue output")->addSimpleElement(buffer, ADD_BOTTOM); @@ -216,74 +229,24 @@ BOOL LLFloaterScriptQueue::start() return startQueue(); } -BOOL LLFloaterScriptQueue::isDone() const +void LLFloaterScriptQueue::addProcessingMessage(const std::string &message, const LLSD &args) { - return (mCurrentObjectID.isNull() && (mObjectIDs.size() == 0)); -} + std::string buffer(LLTrans::getString(message, args)); -// go to the next object. If no objects left, it falls out silently -// and waits to be killed by the window being closed. -BOOL LLFloaterScriptQueue::nextObject() -{ - U32 count; - BOOL successful_start = FALSE; - do - { - count = mObjectIDs.size(); - LL_INFOS() << "LLFloaterScriptQueue::nextObject() - " << count - << " objects left to process." << LL_ENDL; - mCurrentObjectID.setNull(); - if(count > 0) - { - successful_start = popNext(); - } - LL_INFOS() << "LLFloaterScriptQueue::nextObject() " - << (successful_start ? "successful" : "unsuccessful") - << LL_ENDL; - } while((mObjectIDs.size() > 0) && !successful_start); - if(isDone() && !mDone) - { - mDone = true; - getChild("queue output")->addSimpleElement(getString("Done"), ADD_BOTTOM); - getChildView("close")->setEnabled(TRUE); - } - return successful_start; + getChild("queue output")->addSimpleElement(buffer, ADD_BOTTOM); } -// returns true if the queue has started, otherwise false. This -// method pops the top object off of the queue. -BOOL LLFloaterScriptQueue::popNext() +void LLFloaterScriptQueue::addStringMessage(const std::string &message) { - // get the first element off of the container, and attempt to get - // the inventory. - BOOL rv = FALSE; - S32 count = mObjectIDs.size(); - if(mCurrentObjectID.isNull() && (count > 0)) - { - mCurrentObjectID = mObjectIDs.at(0); - LL_INFOS() << "LLFloaterScriptQueue::popNext() - mCurrentID: " - << mCurrentObjectID << LL_ENDL; - mObjectIDs.erase(mObjectIDs.begin()); - LLViewerObject* obj = gObjectList.findObject(mCurrentObjectID); - if(obj) - { - LL_INFOS() << "LLFloaterScriptQueue::popNext() requesting inv for " - << mCurrentObjectID << LL_ENDL; - LLUUID* id = new LLUUID(getKey().asUUID()); - registerVOInventoryListener(obj,id); - requestVOInventory(); - rv = TRUE; - } - } - return rv; + getChild("queue output")->addSimpleElement(message, ADD_BOTTOM); } -BOOL LLFloaterScriptQueue::startQueue() + +BOOL LLFloaterScriptQueue::isDone() const { - return nextObject(); + return (mCurrentObjectID.isNull() && (mObjectList.size() == 0)); } - ///---------------------------------------------------------------------------- /// Class LLFloaterCompileQueue ///---------------------------------------------------------------------------- @@ -293,7 +256,6 @@ LLFloaterCompileQueue::LLFloaterCompileQueue(const LLSD& key) setTitle(LLTrans::getString("CompileQueueTitle")); setStartString(LLTrans::getString("CompileQueueStart")); -// mUploadQueue = new LLAssetUploadQueue(new LLCompileFloaterUploadQueueSupplier(key.asUUID())); } LLFloaterCompileQueue::~LLFloaterCompileQueue() @@ -306,7 +268,6 @@ void LLFloaterCompileQueue::experienceIdsReceived( const LLSD& content ) { mExperienceIds.insert(it->asUUID()); } - nextObject(); } BOOL LLFloaterCompileQueue::hasExperience( const LLUUID& id ) const @@ -314,188 +275,254 @@ BOOL LLFloaterCompileQueue::hasExperience( const LLUUID& id ) const return mExperienceIds.find(id) != mExperienceIds.end(); } +// //Attempt to record this asset ID. If it can not be inserted into the set +// //then it has already been processed so return false. -void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object, - LLInventoryObject::object_list_t* inv) +void LLFloaterCompileQueue::handleHTTPResponse(std::string pumpName, const LLSD &expresult) { - // find all of the lsl, leaving off duplicates. We'll remove - // all matching asset uuids on compilation success. + LLEventPumps::instance().post(pumpName, expresult); +} - typedef std::multimap > uuid_item_map; - uuid_item_map asset_item_map; +// *TODO: handleSCriptRetrieval is passed into the VFS via a legacy C function pointer +// future project would be to convert these to C++ callables (std::function<>) so that +// we can use bind and remove the userData parameter. +// +void LLFloaterCompileQueue::handleScriptRetrieval(LLVFS *vfs, const LLUUID& assetId, + LLAssetType::EType type, void* userData, S32 status, LLExtStat extStatus) +{ + LLSD result(LLSD::emptyMap()); - LLInventoryObject::object_list_t::const_iterator it = inv->begin(); - LLInventoryObject::object_list_t::const_iterator end = inv->end(); - for ( ; it != end; ++it) - { - if((*it)->getType() == LLAssetType::AT_LSL_TEXT) - { - LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); - // Check permissions before allowing the user to retrieve data. - if (item->getPermissions().allowModifyBy(gAgent.getID(), gAgent.getGroupID()) && - item->getPermissions().allowCopyBy(gAgent.getID(), gAgent.getGroupID()) ) - { - LLPointer script = new LLViewerInventoryItem(item); - mCurrentScripts.push_back(script); - asset_item_map.insert(std::make_pair(item->getAssetUUID(), item)); - } - } - } + result["asset_id"] = assetId; + if (status) + { + result["error"] = status; + + if (status == LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE) + { + result["message"] = LLTrans::getString("CompileQueueProblemDownloading") + (":"); + result["alert"] = LLTrans::getString("CompileQueueScriptNotFound"); + } + else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) + { + result["message"] = LLTrans::getString("CompileQueueInsufficientPermFor") + (":"); + result["alert"] = LLTrans::getString("CompileQueueInsufficientPermDownload"); + } + else + { + result["message"] = LLTrans::getString("CompileQueueUnknownFailure"); + } + } - if (asset_item_map.empty()) - { - // There are no scripts in this object. move on. - nextObject(); - } - else - { - // request all of the assets. - uuid_item_map::iterator iter; - for(iter = asset_item_map.begin(); iter != asset_item_map.end(); iter++) - { - LLInventoryItem *itemp = iter->second; - LLScriptQueueData* datap = new LLScriptQueueData(getKey().asUUID(), - viewer_object->getID(), itemp); - - LLExperienceCache::instance().fetchAssociatedExperience(itemp->getParentUUID(), itemp->getUUID(), - boost::bind(&LLFloaterCompileQueue::requestAsset, datap, _1)); - } - } -} + LLEventPumps::instance().post(((HandleScriptUserData *)userData)->getPumpName(), result); +} -void LLFloaterCompileQueue::requestAsset( LLScriptQueueData* datap, const LLSD& experience ) +/*static*/ +void LLFloaterCompileQueue::processExperienceIdResults(LLSD result, LLUUID parent) { - LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance("compile_queue", datap->mQueueID); - if(!queue) - { - delete datap; - return; - } - if(experience.has(LLExperienceCache::EXPERIENCE_ID)) - { - datap->mExperienceId=experience[LLExperienceCache::EXPERIENCE_ID].asUUID(); - if(!queue->hasExperience(datap->mExperienceId)) - { - std::string buffer = LLTrans::getString("CompileNoExperiencePerm", LLSD::emptyMap() - .with("SCRIPT", datap->mItem->getName()) - .with("EXPERIENCE", experience[LLExperienceCache::NAME].asString())); - - queue->getChild("queue output")->addSimpleElement(buffer, ADD_BOTTOM); - queue->removeItemByItemID(datap->mItem->getUUID()); - delete datap; - return; - } - } - //LL_INFOS() << "ITEM NAME 2: " << names.get(i) << LL_ENDL; - gAssetStorage->getInvItemAsset(datap->mHost, - gAgent.getID(), - gAgent.getSessionID(), - datap->mItem->getPermissions().getOwner(), - datap->mTaskId, - datap->mItem->getUUID(), - datap->mItem->getAssetUUID(), - datap->mItem->getType(), - LLFloaterCompileQueue::scriptArrived, - (void*)datap); + LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance("compile_queue", parent); + if (!queue) + return; + + queue->experienceIdsReceived(result["experience_ids"]); + + // getDerived handle gets a handle that can be resolved to a parent class of the derived object. + LLHandle hFloater(queue->getDerivedHandle()); + + // note subtle difference here: getDerivedHandle in this case is for an LLFloaterCompileQueue + fnQueueAction_t fn = boost::bind(LLFloaterCompileQueue::processScript, + queue->getDerivedHandle(), _1, _2, _3); + + + LLCoros::instance().launch("ScriptQueueCompile", boost::bind(LLFloaterScriptQueue::objectScriptProcessingQueueCoro, + queue->mStartString, + hFloater, + queue->mObjectList, + fn)); + } -/*static*/ -void LLFloaterCompileQueue::finishLSLUpload(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, std::string scriptName, LLUUID queueId) +bool LLFloaterCompileQueue::processScript(LLHandle hfloater, + const LLPointer &object, LLInventoryObject* inventory, LLEventPump &pump) { + LLSD result; + LLCheckedHandle floater(hfloater); + // Calls to floater may fail. If they do they throw LLExeceptionStaleHandle. + // which is caught in objectScriptProcessingQueueCoro + bool monocompile = floater->mMono; + F32 fetch_timeout = gSavedSettings.getF32("QueueInventoryFetchTimeout"); + - LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance("compile_queue", LLSD(queueId)); - if (queue) + // Initial test to see if we can (or should) attempt to compile the script. + LLInventoryItem *item = dynamic_cast(inventory); + + if (!item) { - // Bytecode save completed - if (response["compiled"]) - { - std::string message = std::string("Compilation of \"") + scriptName + std::string("\" succeeded"); + LL_WARNS("SCRIPTQ") << "item retrieved is not an LLInventoryItem." << LL_ENDL; + return true; + } - queue->getChild("queue output")->addSimpleElement(message, ADD_BOTTOM); - LL_INFOS() << message << LL_ENDL; + if (!item->getPermissions().allowModifyBy(gAgent.getID(), gAgent.getGroupID()) || + !item->getPermissions().allowCopyBy(gAgent.getID(), gAgent.getGroupID())) + { + std::string buffer = "Skipping: " + item->getName() + "(Permissions)"; + floater->addStringMessage(buffer); + return true; + } + + // Attempt to retrieve the experience + LLUUID experienceId; + { + LLExperienceCache::instance().fetchAssociatedExperience(inventory->getParentUUID(), inventory->getUUID(), + boost::bind(&LLFloaterCompileQueue::handleHTTPResponse, pump.getName(), _1)); + + result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, + LLSDMap("timeout", LLSD::Boolean(true))); + + if (result.has("timeout")) + { // A timeout filed in the result will always be true if present. + LLStringUtil::format_map_t args; + args["[OBJECT_NAME]"] = inventory->getName(); + std::string buffer = floater->getString("Timeout", args); + floater->addStringMessage(buffer); + return true; } - else + + if (result.has(LLExperienceCache::EXPERIENCE_ID)) { - LLSD compile_errors = response["errors"]; - for (LLSD::array_const_iterator line = compile_errors.beginArray(); - line < compile_errors.endArray(); line++) + experienceId = result[LLExperienceCache::EXPERIENCE_ID].asUUID(); + if (!floater->hasExperience(experienceId)) { - std::string str = line->asString(); - str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); - - queue->getChild("queue output")->addSimpleElement(str, ADD_BOTTOM); + floater->addProcessingMessage("CompileNoExperiencePerm", + LLSDMap("SCRIPT", inventory->getName()) + ("EXPERIENCE", result[LLExperienceCache::NAME].asString())); + return true; } - LL_INFOS() << response["errors"] << LL_ENDL; } } + + { + HandleScriptUserData userData(pump.getName()); + + + // request the asset + gAssetStorage->getInvItemAsset(LLHost(), + gAgent.getID(), + gAgent.getSessionID(), + item->getPermissions().getOwner(), + object->getID(), + item->getUUID(), + item->getAssetUUID(), + item->getType(), + &LLFloaterCompileQueue::handleScriptRetrieval, + &userData); + + result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, + LLSDMap("timeout", LLSD::Boolean(true))); + } + + if (result.has("timeout")) + { // A timeout filed in the result will always be true if present. + LLStringUtil::format_map_t args; + args["[OBJECT_NAME]"] = inventory->getName(); + std::string buffer = floater->getString("Timeout", args); + floater->addStringMessage(buffer); + return true; + } + + if (result.has("error")) + { + LL_WARNS("SCRIPTQ") << "Inventory fetch returned with error. Code: " << result["error"].asString() << LL_ENDL; + std::string buffer = result["message"].asString() + " " + inventory->getName(); + floater->addStringMessage(buffer); + + if (result.has("alert")) + { + LLSD args; + args["MESSAGE"] = result["alert"].asString(); + LLNotificationsUtil::add("SystemMessage", args); + } + return true; + } + + LLUUID assetId = result["asset_id"]; + + std::string url = object->getRegion()->getCapability("UpdateScriptTask"); + + { + LLResourceUploadInfo::ptr_t uploadInfo(new LLQueuedScriptAssetUpload(object->getID(), + inventory->getUUID(), + assetId, + monocompile ? LLScriptAssetUpload::MONO : LLScriptAssetUpload::LSL2, + true, + inventory->getName(), + LLUUID(), + experienceId, + boost::bind(&LLFloaterCompileQueue::handleHTTPResponse, pump.getName(), _4))); + + LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); + } + + result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, LLSDMap("timeout", LLSD::Boolean(true))); + + if (result.has("timeout")) + { // A timeout filed in the result will always be true if present. + LLStringUtil::format_map_t args; + args["[OBJECT_NAME]"] = inventory->getName(); + std::string buffer = floater->getString("Timeout", args); + floater->addStringMessage(buffer); + return true; + } + + // Bytecode save completed + if (result["compiled"]) + { + std::string buffer = std::string("Compilation of \"") + inventory->getName() + std::string("\" succeeded"); + + floater->addStringMessage(buffer); + LL_INFOS() << buffer << LL_ENDL; + } + else + { + LLSD compile_errors = result["errors"]; + std::string buffer = std::string("Compilation of \"") + inventory->getName() + std::string("\" failed:"); + floater->addStringMessage(buffer); + for (LLSD::array_const_iterator line = compile_errors.beginArray(); + line < compile_errors.endArray(); line++) + { + std::string str = line->asString(); + str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); + + floater->addStringMessage(str); + } + LL_INFOS() << result["errors"] << LL_ENDL; + } + + return true; } -// This is the callback for when each script arrives -// static -void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status) +bool LLFloaterCompileQueue::startQueue() { - LL_INFOS() << "LLFloaterCompileQueue::scriptArrived()" << LL_ENDL; - LLScriptQueueData* data = (LLScriptQueueData*)user_data; - if(!data) - { - return; - } - LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance("compile_queue", data->mQueueID); - - std::string buffer; - if(queue && (0 == status)) - { - LLViewerObject* object = gObjectList.findObject(data->mTaskId); - if (object) + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + std::string lookup_url = region->getCapability("GetCreatorExperiences"); + if (!lookup_url.empty()) { - std::string url = object->getRegion()->getCapability("UpdateScriptTask"); - std::string scriptName = data->mItem->getName(); - - LLBufferedAssetUploadInfo::taskUploadFinish_f proc = boost::bind(&LLFloaterCompileQueue::finishLSLUpload, _1, _2, _3, _4, - scriptName, data->mQueueID); + LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t success = + boost::bind(&LLFloaterCompileQueue::processExperienceIdResults, _1, getKey().asUUID()); - LLResourceUploadInfo::ptr_t uploadInfo(new LLQueuedScriptAssetUpload(data->mTaskId, data->mItem->getUUID(), asset_id, - (queue->mMono) ? LLScriptAssetUpload::MONO : LLScriptAssetUpload::LSL2, - true, scriptName, data->mQueueID, data->mExperienceId, proc)); + LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t failure = + boost::bind(&LLFloaterCompileQueue::processExperienceIdResults, LLSD(), getKey().asUUID()); - LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(lookup_url, + success, failure); + return TRUE; } - } - else - { - if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ) - { - LLSD args; - args["MESSAGE"] = LLTrans::getString("CompileQueueScriptNotFound"); - LLNotificationsUtil::add("SystemMessage", args); - - buffer = LLTrans::getString("CompileQueueProblemDownloading") + (": ") + data->mItem->getName(); - } - else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) - { - LLSD args; - args["MESSAGE"] = LLTrans::getString("CompileQueueInsufficientPermDownload"); - LLNotificationsUtil::add("SystemMessage", args); - - buffer = LLTrans::getString("CompileQueueInsufficientPermFor") + (": ") + data->mItem->getName(); - } - else - { - buffer = LLTrans::getString("CompileQueueUnknownFailure") + (" ") + data->mItem->getName(); - } - - LL_WARNS() << "Problem downloading script asset." << LL_ENDL; - if(queue) queue->removeItemByItemID(data->mItem->getUUID()); - } - if(queue && (buffer.size() > 0)) - { - queue->getChild("queue output")->addSimpleElement(buffer, ADD_BOTTOM); - } - delete data; + } + + return true; } @@ -514,40 +541,44 @@ LLFloaterResetQueue::~LLFloaterResetQueue() { } -void LLFloaterResetQueue::handleInventory(LLViewerObject* viewer_obj, - LLInventoryObject::object_list_t* inv) +bool LLFloaterResetQueue::resetObjectScripts(LLHandle hfloater, + const LLPointer &object, LLInventoryObject* inventory, LLEventPump &pump) { - // find all of the lsl, leaving off duplicates. We'll remove - // all matching asset uuids on compilation success. - - LLInventoryObject::object_list_t::const_iterator it = inv->begin(); - LLInventoryObject::object_list_t::const_iterator end = inv->end(); - for ( ; it != end; ++it) - { - if((*it)->getType() == LLAssetType::AT_LSL_TEXT) - { - LLViewerObject* object = gObjectList.findObject(viewer_obj->getID()); - - if (object) - { - LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); - std::string buffer; - buffer = getString("Resetting") + (": ") + item->getName(); - getChild("queue output")->addSimpleElement(buffer, ADD_BOTTOM); - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ScriptReset); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Script); - msg->addUUIDFast(_PREHASH_ObjectID, viewer_obj->getID()); - msg->addUUIDFast(_PREHASH_ItemID, (*it)->getUUID()); - msg->sendReliable(object->getRegion()->getHost()); - } - } - } + LLCheckedHandle floater(hfloater); + // Calls to floater may fail. If they do they throw LLExeceptionStaleHandle. + // which is caught in objectScriptProcessingQueueCoro + + std::string buffer; + buffer = floater->getString("Resetting") + (": ") + inventory->getName(); + floater->addStringMessage(buffer); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ScriptReset); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_Script); + msg->addUUIDFast(_PREHASH_ObjectID, object->getID()); + msg->addUUIDFast(_PREHASH_ItemID, inventory->getUUID()); + msg->sendReliable(object->getRegion()->getHost()); + + return true; +} - nextObject(); +bool LLFloaterResetQueue::startQueue() +{ + // Bind the resetObjectScripts method into a QueueAction function and pass it + // into the object queue processing coroutine. + fnQueueAction_t fn = boost::bind(LLFloaterResetQueue::resetObjectScripts, + getDerivedHandle(), _1, _2, _3); + + LLCoros::instance().launch("ScriptResetQueue", boost::bind(LLFloaterScriptQueue::objectScriptProcessingQueueCoro, + mStartString, + getDerivedHandle(), + mObjectList, + fn)); + + return true; } ///---------------------------------------------------------------------------- @@ -565,44 +596,46 @@ LLFloaterRunQueue::~LLFloaterRunQueue() { } -void LLFloaterRunQueue::handleInventory(LLViewerObject* viewer_obj, - LLInventoryObject::object_list_t* inv) +bool LLFloaterRunQueue::runObjectScripts(LLHandle hfloater, + const LLPointer &object, LLInventoryObject* inventory, LLEventPump &pump) { - // find all of the lsl, leaving off duplicates. We'll remove - // all matching asset uuids on compilation success. - LLInventoryObject::object_list_t::const_iterator it = inv->begin(); - LLInventoryObject::object_list_t::const_iterator end = inv->end(); - for ( ; it != end; ++it) - { - if((*it)->getType() == LLAssetType::AT_LSL_TEXT) - { - LLViewerObject* object = gObjectList.findObject(viewer_obj->getID()); - - if (object) - { - LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); - LLScrollListCtrl* list = getChild("queue output"); - std::string buffer; - buffer = getString("Running") + (": ") + item->getName(); - list->addSimpleElement(buffer, ADD_BOTTOM); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_SetScriptRunning); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Script); - msg->addUUIDFast(_PREHASH_ObjectID, viewer_obj->getID()); - msg->addUUIDFast(_PREHASH_ItemID, (*it)->getUUID()); - msg->addBOOLFast(_PREHASH_Running, TRUE); - msg->sendReliable(object->getRegion()->getHost()); - } - } - } + LLCheckedHandle floater(hfloater); + // Calls to floater may fail. If they do they throw LLExeceptionStaleHandle. + // which is caught in objectScriptProcessingQueueCoro + + std::string buffer; + buffer = floater->getString("Running") + (": ") + inventory->getName(); + floater->addStringMessage(buffer); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_SetScriptRunning); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_Script); + msg->addUUIDFast(_PREHASH_ObjectID, object->getID()); + msg->addUUIDFast(_PREHASH_ItemID, inventory->getUUID()); + msg->addBOOLFast(_PREHASH_Running, TRUE); + msg->sendReliable(object->getRegion()->getHost()); + + return true; +} - nextObject(); +bool LLFloaterRunQueue::startQueue() +{ + LLHandle hFloater(getDerivedHandle()); + fnQueueAction_t fn = boost::bind(LLFloaterRunQueue::runObjectScripts, hFloater, _1, _2, _3); + + LLCoros::instance().launch("ScriptRunQueue", boost::bind(LLFloaterScriptQueue::objectScriptProcessingQueueCoro, + mStartString, + hFloater, + mObjectList, + fn)); + + return true; } + ///---------------------------------------------------------------------------- /// Class LLFloaterNotRunQueue ///---------------------------------------------------------------------------- @@ -618,96 +651,157 @@ LLFloaterNotRunQueue::~LLFloaterNotRunQueue() { } -void LLFloaterCompileQueue::removeItemByItemID(const LLUUID& asset_id) +bool LLFloaterNotRunQueue::stopObjectScripts(LLHandle hfloater, + const LLPointer &object, LLInventoryObject* inventory, LLEventPump &pump) { - LL_INFOS() << "LLFloaterCompileQueue::removeItemByAssetID()" << LL_ENDL; - for(S32 i = 0; i < mCurrentScripts.size(); ) - { - if(asset_id == mCurrentScripts.at(i)->getUUID()) - { - vector_replace_with_last(mCurrentScripts, mCurrentScripts.begin() + i); - } - else - { - ++i; - } - } - if(mCurrentScripts.empty()) - { - nextObject(); - } + LLCheckedHandle floater(hfloater); + // Calls to floater may fail. If they do they throw LLExeceptionStaleHandle. + // which is caught in objectScriptProcessingQueueCoro + + std::string buffer; + buffer = floater->getString("NotRunning") + (": ") + inventory->getName(); + floater->addStringMessage(buffer); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_SetScriptRunning); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_Script); + msg->addUUIDFast(_PREHASH_ObjectID, object->getID()); + msg->addUUIDFast(_PREHASH_ItemID, inventory->getUUID()); + msg->addBOOLFast(_PREHASH_Running, FALSE); + msg->sendReliable(object->getRegion()->getHost()); + + return true; } -BOOL LLFloaterCompileQueue::startQueue() +bool LLFloaterNotRunQueue::startQueue() { - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - std::string lookup_url=region->getCapability("GetCreatorExperiences"); - if(!lookup_url.empty()) - { - LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t success = - boost::bind(&LLFloaterCompileQueue::processExperienceIdResults, _1, getKey().asUUID()); + LLHandle hFloater(getDerivedHandle()); - LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t failure = - boost::bind(&LLFloaterCompileQueue::processExperienceIdResults, LLSD(), getKey().asUUID()); + fnQueueAction_t fn = boost::bind(&LLFloaterNotRunQueue::stopObjectScripts, hFloater, _1, _2, _3); + LLCoros::instance().launch("ScriptQueueNotRun", boost::bind(LLFloaterScriptQueue::objectScriptProcessingQueueCoro, + mStartString, + hFloater, + mObjectList, + fn)); - LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(lookup_url, - success, failure); - return TRUE; - } - } - return nextObject(); + return true; } -/*static*/ -void LLFloaterCompileQueue::processExperienceIdResults(LLSD result, LLUUID parent) +///---------------------------------------------------------------------------- +/// Local function definitions +///---------------------------------------------------------------------------- +void ObjectInventoryFetcher::inventoryChanged(LLViewerObject* object, + LLInventoryObject::object_list_t* inventory, S32 serial_num, void* user_data) { - LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance("compile_queue", parent); - if (!queue) - return; + mInventoryList.clear(); + mInventoryList.assign(inventory->begin(), inventory->end()); + + mPump.post(LLSDMap("changed", LLSD::Boolean(true))); - queue->experienceIdsReceived(result["experience_ids"]); } -void LLFloaterNotRunQueue::handleInventory(LLViewerObject* viewer_obj, - LLInventoryObject::object_list_t* inv) +void LLFloaterScriptQueue::objectScriptProcessingQueueCoro(std::string action, LLHandle hfloater, + object_data_list_t objectList, fnQueueAction_t func) { - // find all of the lsl, leaving off duplicates. We'll remove - // all matching asset uuids on compilation success. - LLInventoryObject::object_list_t::const_iterator it = inv->begin(); - LLInventoryObject::object_list_t::const_iterator end = inv->end(); - for ( ; it != end; ++it) - { - if((*it)->getType() == LLAssetType::AT_LSL_TEXT) - { - LLViewerObject* object = gObjectList.findObject(viewer_obj->getID()); - - if (object) - { - LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); - LLScrollListCtrl* list = getChild("queue output"); - std::string buffer; - buffer = getString("NotRunning") + (": ") +item->getName(); - list->addSimpleElement(buffer, ADD_BOTTOM); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_SetScriptRunning); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Script); - msg->addUUIDFast(_PREHASH_ObjectID, viewer_obj->getID()); - msg->addUUIDFast(_PREHASH_ItemID, (*it)->getUUID()); - msg->addBOOLFast(_PREHASH_Running, FALSE); - msg->sendReliable(object->getRegion()->getHost()); - } - } - } + LLCoros::set_consuming(true); + LLCheckedHandle floater(hfloater); + // Calls to floater may fail. If they do they throw LLExeceptionStaleHandle. This is expected if the dialog closes. + LLEventMailDrop maildrop(QUEUE_EVENTPUMP_NAME, true); + F32 fetch_timeout = gSavedSettings.getF32("QueueInventoryFetchTimeout"); - nextObject(); -} -///---------------------------------------------------------------------------- -/// Local function definitions -///---------------------------------------------------------------------------- + try + { + for (object_data_list_t::iterator itObj(objectList.begin()); (itObj != objectList.end()); ++itObj) + { + bool firstForObject = true; + LLUUID object_id = (*itObj).mObjectId; + LL_INFOS("SCRIPTQ") << "Next object in queue with ID=" << object_id.asString() << LL_ENDL; + + LLPointer obj = gObjectList.findObject(object_id); + LLInventoryObject::object_list_t inventory; + if (obj) + { + ObjectInventoryFetcher::ptr_t fetcher(new ObjectInventoryFetcher(maildrop, obj, NULL)); + + fetcher->fetchInventory(); + + LLStringUtil::format_map_t args; + args["[OBJECT_NAME]"] = (*itObj).mObjectName; + floater->addStringMessage(floater->getString("LoadingObjInv", args)); + + LLSD result = llcoro::suspendUntilEventOnWithTimeout(maildrop, fetch_timeout, + LLSDMap("timeout", LLSD::Boolean(true))); + + if (result.has("timeout")) + { // A timeout filed in the result will always be true if present. + LL_WARNS("SCRIPTQ") << "Unable to retrieve inventory for object " << object_id.asString() << + ". Skipping to next object." << LL_ENDL; + + LLStringUtil::format_map_t args; + args["[OBJECT_NAME]"] = (*itObj).mObjectName; + floater->addStringMessage(floater->getString("Timeout", args)); + + continue; + } + + inventory.assign(fetcher->getInventoryList().begin(), fetcher->getInventoryList().end()); + } + else + { + LL_WARNS("SCRIPTQ") << "Unable to retrieve object with ID of " << object_id << + ". Skipping to next." << LL_ENDL; + continue; + } + + // TODO: Get the name of the object we are looking at here so that we can display it below. + //std::string objName = (dynamic_cast(obj.get()))->getName(); + LL_DEBUGS("SCRIPTQ") << "Object has " << inventory.size() << " items." << LL_ENDL; + + for (LLInventoryObject::object_list_t::iterator itInv = inventory.begin(); + itInv != inventory.end(); ++itInv) + { + floater.check(); + + // note, we have a smart pointer to the obj above... but if we didn't we'd check that + // it still exists here. + + if (((*itInv)->getType() == LLAssetType::AT_LSL_TEXT)) + { + LL_DEBUGS("SCRIPTQ") << "Inventory item " << (*itInv)->getUUID().asString() << "\"" << (*itInv)->getName() << "\"" << LL_ENDL; + if (firstForObject) + { + //floater->addStringMessage(objName + ":"); + firstForObject = false; + } + + if (!func(obj, (*itInv), maildrop)) + { + continue; + } + } + + // no other explicit suspension point in this loop. func(...) MIGHT suspend + // but offers no guarantee of doing so. + llcoro::suspend(); + } + } + + floater->addStringMessage("Done"); + floater->getChildView("close")->setEnabled(TRUE); + } + catch (LLExeceptionStaleHandle &) + { + // This is expected. It means that floater has been closed before + // processing was completed. + LL_WARNS("SCRIPTQ") << "LLExeceptionStaleHandle caught! Floater has most likely been closed." << LL_ENDL; + } + catch (...) + { + // Rethrow the caught exception. + throw; + } +} diff --git a/indra/newview/llcompilequeue.h b/indra/newview/llcompilequeue.h index 46bcb9746b..1b3d8f83a0 100644 --- a/indra/newview/llcompilequeue.h +++ b/indra/newview/llcompilequeue.h @@ -37,6 +37,8 @@ #include "llviewerinventory.h" +#include "llevents.h" + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLFloaterScriptQueue // @@ -48,7 +50,7 @@ // scripts manipulated. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLFloaterScriptQueue : public LLFloater, public LLVOInventoryListener +class LLFloaterScriptQueue : public LLFloater/*, public LLVOInventoryListener*/ { public: LLFloaterScriptQueue(const LLSD& key); @@ -59,34 +61,23 @@ public: void setMono(bool mono) { mMono = mono; } // addObject() accepts an object id. - void addObject(const LLUUID& id); + void addObject(const LLUUID& id, std::string name); // start() returns TRUE if the queue has started, otherwise FALSE. BOOL start(); -protected: - // This is the callback method for the viewer object currently - // being worked on. - /*virtual*/ void inventoryChanged(LLViewerObject* obj, - LLInventoryObject::object_list_t* inv, - S32 serial_num, - void* queue); - - // This is called by inventoryChanged - virtual void handleInventory(LLViewerObject* viewer_obj, - LLInventoryObject::object_list_t* inv) = 0; + void addProcessingMessage(const std::string &message, const LLSD &args); + void addStringMessage(const std::string &message); + std::string getStartString() const { return mStartString; } + +protected: static void onCloseBtn(void* user_data); // returns true if this is done BOOL isDone() const; - virtual BOOL startQueue(); - - // go to the next object. If no objects left, it falls out - // silently and waits to be killed by the deleteIfDone() callback. - BOOL nextObject(); - BOOL popNext(); + virtual bool startQueue() = 0; void setStartString(const std::string& s) { mStartString = s; } @@ -96,12 +87,23 @@ protected: LLButton* mCloseBtn; // Object Queue - std::vector mObjectIDs; + struct ObjectData + { + LLUUID mObjectId; + std::string mObjectName; + }; + typedef std::vector object_data_list_t; + + object_data_list_t mObjectList; LLUUID mCurrentObjectID; bool mDone; std::string mStartString; bool mMono; + + typedef boost::function &, LLInventoryObject*, LLEventPump &)> fnQueueAction_t; + static void objectScriptProcessingQueueCoro(std::string action, LLHandle hfloater, object_data_list_t objectList, fnQueueAction_t func); + }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -122,8 +124,6 @@ class LLFloaterCompileQueue : public LLFloaterScriptQueue { friend class LLFloaterReg; public: - // remove any object in mScriptScripts with the matching uuid. - void removeItemByItemID(const LLUUID& item_id); void experienceIdsReceived( const LLSD& content ); BOOL hasExperience(const LLUUID& id)const; @@ -132,27 +132,17 @@ protected: LLFloaterCompileQueue(const LLSD& key); virtual ~LLFloaterCompileQueue(); - // This is called by inventoryChanged - virtual void handleInventory(LLViewerObject* viewer_obj, - LLInventoryObject::object_list_t* inv); - - static void requestAsset(struct LLScriptQueueData* datap, const LLSD& experience); + virtual bool startQueue(); + static bool processScript(LLHandle hfloater, const LLPointer &object, LLInventoryObject* inventory, LLEventPump &pump); - static void finishLSLUpload(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, std::string scriptName, LLUUID queueId); - - // This is the callback for when each script arrives - static void scriptArrived(LLVFS *vfs, const LLUUID& asset_id, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status); - - virtual BOOL startQueue(); -protected: - LLViewerInventoryItem::item_array_t mCurrentScripts; + //bool checkAssetId(const LLUUID &assetId); + static void handleHTTPResponse(std::string pumpName, const LLSD &expresult); + static void handleScriptRetrieval(LLVFS *vfs, const LLUUID& assetId, LLAssetType::EType type, void* userData, S32 status, LLExtStat extStatus); private: static void processExperienceIdResults(LLSD result, LLUUID parent); - + //uuid_list_t mAssetIds; // list of asset IDs processed. uuid_list_t mExperienceIds; }; @@ -169,9 +159,9 @@ protected: LLFloaterResetQueue(const LLSD& key); virtual ~LLFloaterResetQueue(); - // This is called by inventoryChanged - virtual void handleInventory(LLViewerObject* viewer_obj, - LLInventoryObject::object_list_t* inv); + static bool resetObjectScripts(LLHandle hfloater, const LLPointer &object, LLInventoryObject* inventory, LLEventPump &pump); + + virtual bool startQueue(); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -186,10 +176,10 @@ class LLFloaterRunQueue : public LLFloaterScriptQueue protected: LLFloaterRunQueue(const LLSD& key); virtual ~LLFloaterRunQueue(); - - // This is called by inventoryChanged - virtual void handleInventory(LLViewerObject* viewer_obj, - LLInventoryObject::object_list_t* inv); + + static bool runObjectScripts(LLHandle hfloater, const LLPointer &object, LLInventoryObject* inventory, LLEventPump &pump); + + virtual bool startQueue(); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -205,9 +195,9 @@ protected: LLFloaterNotRunQueue(const LLSD& key); virtual ~LLFloaterNotRunQueue(); - // This is called by inventoryChanged - virtual void handleInventory(LLViewerObject* viewer_obj, - LLInventoryObject::object_list_t* inv); + static bool stopObjectScripts(LLHandle hfloater, const LLPointer &object, LLInventoryObject* inventory, LLEventPump &pump); + + virtual bool startQueue(); }; #endif // LL_LLCOMPILEQUEUE_H diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 99a9ed1d75..f5b06fbd19 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -6986,20 +6986,25 @@ class LLAvatarCall : public view_listener_t namespace { - struct QueueObjects : public LLSelectedObjectFunctor + struct QueueObjects : public LLSelectedNodeFunctor { BOOL scripted; BOOL modifiable; LLFloaterScriptQueue* mQueue; QueueObjects(LLFloaterScriptQueue* q) : mQueue(q), scripted(FALSE), modifiable(FALSE) {} - virtual bool apply(LLViewerObject* obj) + virtual bool apply(LLSelectNode* node) { + LLViewerObject* obj = node->getObject(); + if (!obj) + { + return true; + } scripted = obj->flagScripted(); modifiable = obj->permModify(); if( scripted && modifiable ) { - mQueue->addObject(obj->getID()); + mQueue->addObject(obj->getID(), node->mName); return false; } else @@ -7015,7 +7020,7 @@ void queue_actions(LLFloaterScriptQueue* q, const std::string& msg) QueueObjects func(q); LLSelectMgr *mgr = LLSelectMgr::getInstance(); LLObjectSelectionHandle selectHandle = mgr->getSelection(); - bool fail = selectHandle->applyToObjects(&func); + bool fail = selectHandle->applyToNodes(&func); if(fail) { if ( !func.scripted ) diff --git a/indra/newview/skins/default/xui/en/floater_script_queue.xml b/indra/newview/skins/default/xui/en/floater_script_queue.xml index f4aca7bb3d..0982683a7f 100644 --- a/indra/newview/skins/default/xui/en/floater_script_queue.xml +++ b/indra/newview/skins/default/xui/en/floater_script_queue.xml @@ -29,6 +29,14 @@ name="NotRunning"> Not running + + Timeout: [OBJECT_NAME] + + + Loading inventory for: [OBJECT_NAME] +