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') 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.2.3 From b031b1a6255af0813698bd40586f30f7b0a76f58 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 13 Jul 2016 10:43:36 -0400 Subject: MAINT-5011: Derive remaining exception classes from std::exception. In particular: NotImplemented in llhttpnode.cpp RelocateError in llupdateinstaller.cpp LLProtectedDataException, LLCertException and subclasses in llsecapi.h Had to add no-throw destructor overrides to LLCertException and subclasses because otherwise clang complains that the implicitly-generated destructor's exception specification is more lax than the base class's. --- indra/llmessage/llhttpnode.cpp | 4 ++- indra/newview/llsecapi.cpp | 2 +- indra/newview/llsecapi.h | 34 ++++++++++++---------- .../updater/llupdateinstaller.cpp | 10 ++++--- 4 files changed, 29 insertions(+), 21 deletions(-) (limited to 'indra') diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp index f235965879..08688ca48b 100644 --- a/indra/llmessage/llhttpnode.cpp +++ b/indra/llmessage/llhttpnode.cpp @@ -31,6 +31,7 @@ #include "llstl.h" #include "llhttpconstants.h" +#include const std::string CONTEXT_HEADERS("headers"); const std::string CONTEXT_PATH("path"); @@ -92,8 +93,9 @@ LLHTTPNode::~LLHTTPNode() namespace { - class NotImplemented + struct NotImplemented: public std::runtime_error { + NotImplemented(): std::runtime_error("LLHTTPNode::NotImplemented") {} }; } diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp index 4f9f83b6f2..c27709a57b 100644 --- a/indra/newview/llsecapi.cpp +++ b/indra/newview/llsecapi.cpp @@ -69,7 +69,7 @@ void initializeSecHandler() } if (!exception_msg.empty()) // an exception was thrown. { - throw LLProtectedDataException(exception_msg.c_str()); + throw LLProtectedDataException(exception_msg); } } diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index 6fe3ee31cf..02438f77b7 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -32,6 +32,7 @@ #include #include #include "llpointer.h" +#include #ifdef LL_WINDOWS #pragma warning(disable:4250) @@ -116,17 +117,14 @@ -class LLProtectedDataException +struct LLProtectedDataException: public std::runtime_error { -public: - LLProtectedDataException(const char *msg) + LLProtectedDataException(const std::string& msg): + std::runtime_error(msg) { - LL_WARNS("SECAPI") << "Protected Data Error: " << (std::string)msg << LL_ENDL; - mMsg = (std::string)msg; + LL_WARNS("SECAPI") << "Protected Data Error: " << msg << LL_ENDL; } - std::string getMessage() { return mMsg; } -protected: - std::string mMsg; + std::string getMessage() { return what(); } }; // class LLCertificate @@ -334,22 +332,22 @@ std::ostream& operator <<(std::ostream& s, const LLCredential& cred); // All error handling is via exceptions. -class LLCertException +class LLCertException: public std::runtime_error { public: - LLCertException(LLPointer cert, const char* msg) + LLCertException(LLPointer cert, const std::string& msg): + std::runtime_error(msg) { mCert = cert; - LL_WARNS("SECAPI") << "Certificate Error: " << (std::string)msg << LL_ENDL; - mMsg = (std::string)msg; + LL_WARNS("SECAPI") << "Certificate Error: " << msg << LL_ENDL; } + virtual ~LLCertException() throw() {} LLPointer getCert() { return mCert; } - std::string getMessage() { return mMsg; } + std::string getMessage() { return what(); } protected: LLPointer mCert; - std::string mMsg; }; class LLInvalidCertificate : public LLCertException @@ -358,6 +356,7 @@ public: LLInvalidCertificate(LLPointer cert) : LLCertException(cert, "CertInvalid") { } + virtual ~LLInvalidCertificate() throw() {} protected: }; @@ -367,6 +366,7 @@ public: LLCertValidationTrustException(LLPointer cert) : LLCertException(cert, "CertUntrusted") { } + virtual ~LLCertValidationTrustException() throw() {} protected: }; @@ -378,7 +378,7 @@ public: { mHostname = hostname; } - + virtual ~LLCertValidationHostnameException() throw() {} std::string getHostname() { return mHostname; } protected: std::string mHostname; @@ -392,6 +392,7 @@ public: { mTime = current_time; } + virtual ~LLCertValidationExpirationException() throw() {} LLDate GetTime() { return mTime; } protected: LLDate mTime; @@ -403,6 +404,7 @@ public: LLCertKeyUsageValidationException(LLPointer cert) : LLCertException(cert, "CertKeyUsage") { } + virtual ~LLCertKeyUsageValidationException() throw() {} protected: }; @@ -412,6 +414,7 @@ public: LLCertBasicConstraintsValidationException(LLPointer cert) : LLCertException(cert, "CertBasicConstraints") { } + virtual ~LLCertBasicConstraintsValidationException() throw() {} protected: }; @@ -421,6 +424,7 @@ public: LLCertValidationInvalidSignatureException(LLPointer cert) : LLCertException(cert, "CertInvalidSignature") { } + virtual ~LLCertValidationInvalidSignatureException() throw() {} protected: }; diff --git a/indra/viewer_components/updater/llupdateinstaller.cpp b/indra/viewer_components/updater/llupdateinstaller.cpp index a0e2c0b362..4432c6574e 100644 --- a/indra/viewer_components/updater/llupdateinstaller.cpp +++ b/indra/viewer_components/updater/llupdateinstaller.cpp @@ -35,12 +35,14 @@ #pragma warning(disable: 4702) // disable 'unreachable code' so we can use lexical_cast (really!). #endif #include - +#include namespace { - class RelocateError {}; - - + struct RelocateError: public std::runtime_error + { + RelocateError(): std::runtime_error("llupdateinstaller: RelocateError") {} + }; + std::string copy_to_temp(std::string const & path) { std::string scriptFile = gDirUtilp->getBaseFileName(path); -- cgit v1.2.3