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."
master
Nat Goodspeed 2016-06-30 16:51:50 -04:00
parent c2ef3b4c71
commit 464a0df4c1
20 changed files with 288 additions and 306 deletions

View File

@ -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;

View File

@ -114,7 +114,7 @@ void LLCrashLoggerLinux::gatherPlatformSpecificFiles()
{
}
bool LLCrashLoggerLinux::mainLoop()
bool LLCrashLoggerLinux::frame()
{
bool send_logs = true;
if(CRASH_BEHAVIOR_ASK == getCrashBehavior())

View File

@ -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();

View File

@ -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

View File

@ -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; }

View File

@ -41,7 +41,7 @@
@property (retain) NSString *currentInputLanguage;
- (void) mainLoop;
- (void) oneFrame;
- (void) showInputWindow:(bool)show withEvent:(NSEvent*)textEvent;
- (void) languageUpdated;
- (bool) romanScript;

View File

@ -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);

View File

@ -64,7 +64,7 @@ void LLCrashLoggerMac::gatherPlatformSpecificFiles()
{
}
bool LLCrashLoggerMac::mainLoop()
bool LLCrashLoggerMac::frame()
{
if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND)

View File

@ -37,7 +37,7 @@ public:
LLCrashLoggerMac(void);
~LLCrashLoggerMac(void);
virtual bool init();
virtual bool mainLoop();
virtual bool frame();
virtual bool cleanup();
virtual void gatherPlatformSpecificFiles();
};

View File

@ -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;

View File

@ -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];
}

View File

@ -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");
LLTrace::get_thread_recorder()->pullFromChildren();
//clear call stack records
LL_CLEAR_CALLSTACKS();
//check memory availability information
checkMemory() ;
try
if (gViewerWindow)
{
pingMainloopTimeout("Main:MiscNativeWindowEvents");
LL_RECORD_BLOCK_TIME(FTM_MESSAGES);
gViewerWindow->getWindow()->processMiscNativeEvents();
}
if (gViewerWindow)
{
LL_RECORD_BLOCK_TIME(FTM_MESSAGES);
gViewerWindow->getWindow()->processMiscNativeEvents();
}
pingMainloopTimeout("Main:GatherInput");
if (gViewerWindow)
{
LL_RECORD_BLOCK_TIME(FTM_MESSAGES);
if (!restoreErrorTrap())
{
LL_WARNS() << " Someone took over my signal/exception handler (post messagehandling)!" << LL_ENDL;
}
pingMainloopTimeout("Main:GatherInput");
gViewerWindow->getWindow()->gatherInput();
if (gViewerWindow)
{
LL_RECORD_BLOCK_TIME(FTM_MESSAGES);
if (!restoreErrorTrap())
{
LL_WARNS() << " Someone took over my signal/exception handler (post messagehandling)!" << LL_ENDL;
}
gViewerWindow->getWindow()->gatherInput();
}
#if 1 && !LL_RELEASE_FOR_DOWNLOAD
// once per second debug info
if (debugTime.getElapsedTimeF32() > 1.f)
{
debugTime.reset();
}
// once per second debug info
if (debugTime.getElapsedTimeF32() > 1.f)
{
debugTime.reset();
}
#endif
//memory leaking simulation
LLFloaterMemLeak* mem_leak_instance =
LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
if(mem_leak_instance)
//memory leaking simulation
LLFloaterMemLeak* mem_leak_instance =
LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
if(mem_leak_instance)
{
mem_leak_instance->idle() ;
}
// canonical per-frame event
mainloop.post(newFrame);
if (!LLApp::isExiting())
{
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())
{
mem_leak_instance->idle() ;
}
// canonical per-frame event
mainloop.post(newFrame);
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())
{
joystick->scanJoystick();
gKeyboard->scanKeyboard();
}
// 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();
resumeMainloopTimeout();
}
if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
{
pauseMainloopTimeout();
saveFinalSnapshot();
disconnectViewer();
resumeMainloopTimeout();
}
// Render scene.
// *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18
if (!LLApp::isExiting() && !gHeadlessClient)
{
pingMainloopTimeout("Main:Display");
gGLActive = TRUE;
display();
pingMainloopTimeout("Main:Snapshot");
LLFloaterSnapshot::update(); // take snapshots
gGLActive = FALSE;
}
joystick->scanJoystick();
gKeyboard->scanKeyboard();
}
pingMainloopTimeout("Main:Sleep");
pauseMainloopTimeout();
// Sleep and run background threads
// Update state based on messages, user input, object idle.
{
LL_RECORD_BLOCK_TIME(FTM_SLEEP);
pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
// 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)
{
ms_sleep(milliseconds_to_sleep);
// also pause worker threads during this wait period
LLAppViewer::getTextureCache()->pause();
LLAppViewer::getImageDecodeThread()->pause();
}
}
if (mRandomizeFramerate)
{
ms_sleep(rand() % 200);
}
if (mPeriodicSlowFrame
&& (gFrameCount % 10 == 0))
{
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);
{
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() ;
if(!total_work_pending) //pause texture fetching threads if nothing to process.
{
LLAppViewer::getTextureCache()->pause();
LLAppViewer::getImageDecodeThread()->pause();
LLAppViewer::getTextureFetch()->pause();
}
if(!total_io_pending) //pause file threads if nothing to process.
{
LLVFSThread::sLocal->pause();
LLLFSThread::sLocal->pause();
}
//texture fetching debugger
if(LLTextureFetchDebugger::isEnabled())
{
LLFloaterTextureFetchDebugger* tex_fetch_debugger_instance =
LLFloaterReg::findTypedInstance<LLFloaterTextureFetchDebugger>("tex_fetch_debugger");
if(tex_fetch_debugger_instance)
{
tex_fetch_debugger_instance->idle() ;
}
}
if ((LLStartUp::getStartupState() >= STATE_CLEANUP) &&
(frameTimer.getElapsedTimeF64() > FRAME_STALL_THRESHOLD))
{
gFrameStalls++;
}
frameTimer.reset();
LL_RECORD_BLOCK_TIME(FTM_IDLE);
idle();
resumeMainloopTimeout();
pingMainloopTimeout("Main:End");
}
}
if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
{
pauseMainloopTimeout();
saveFinalSnapshot();
disconnectViewer();
resumeMainloopTimeout();
}
// Render scene.
// *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18
if (!LLApp::isExiting() && !gHeadlessClient)
{
pingMainloopTimeout("Main:Display");
gGLActive = TRUE;
display();
pingMainloopTimeout("Main:Snapshot");
LLFloaterSnapshot::update(); // take snapshots
gGLActive = FALSE;
}
}
catch(std::bad_alloc)
{
LLMemory::logMemoryInfo(TRUE) ;
//stop memory leaking simulation
LLFloaterMemLeak* mem_leak_instance =
LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
if(mem_leak_instance)
{
mem_leak_instance->stop() ;
LL_WARNS() << "Bad memory allocation in LLAppViewer::mainLoop()!" << LL_ENDL ;
}
else
{
//output possible call stacks to log file.
LLError::LLCallStacks::print() ;
pingMainloopTimeout("Main:Sleep");
LL_ERRS() << "Bad memory allocation in LLAppViewer::mainLoop()!" << LL_ENDL ;
pauseMainloopTimeout();
// Sleep and run background threads
{
LL_RECORD_BLOCK_TIME(FTM_SLEEP);
// yield some time to the os based on command line option
if(mYieldTime >= 0)
{
LL_RECORD_BLOCK_TIME(FTM_YIELD);
ms_sleep(mYieldTime);
}
// 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();
}
}
if (mRandomizeFramerate)
{
ms_sleep(rand() % 200);
}
if (mPeriodicSlowFrame
&& (gFrameCount % 10 == 0))
{
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);
{
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() ;
if(!total_work_pending) //pause texture fetching threads if nothing to process.
{
LLAppViewer::getTextureCache()->pause();
LLAppViewer::getImageDecodeThread()->pause();
LLAppViewer::getTextureFetch()->pause();
}
if(!total_io_pending) //pause file threads if nothing to process.
{
LLVFSThread::sLocal->pause();
LLLFSThread::sLocal->pause();
}
//texture fetching debugger
if(LLTextureFetchDebugger::isEnabled())
{
LLFloaterTextureFetchDebugger* tex_fetch_debugger_instance =
LLFloaterReg::findTypedInstance<LLFloaterTextureFetchDebugger>("tex_fetch_debugger");
if(tex_fetch_debugger_instance)
{
tex_fetch_debugger_instance->idle() ;
}
}
if ((LLStartUp::getStartupState() >= STATE_CLEANUP) &&
(frameTimer.getElapsedTimeF64() > FRAME_STALL_THRESHOLD))
{
gFrameStalls++;
}
frameTimer.reset();
resumeMainloopTimeout();
pingMainloopTimeout("Main:End");
}
}
catch(std::bad_alloc)
{
LLMemory::logMemoryInfo(TRUE) ;
//stop memory leaking simulation
LLFloaterMemLeak* mem_leak_instance =
LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
if(mem_leak_instance)
{
mem_leak_instance->stop() ;
LL_WARNS() << "Bad memory allocation in LLAppViewer::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)

View File

@ -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;

View File

@ -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())
{

View File

@ -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;
}

View File

@ -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())
{

View File

@ -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()

View File

@ -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)

View File

@ -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();

View File

@ -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;