master
Ansariel 2021-06-05 14:03:30 +02:00
commit dde3c2c7a8
11 changed files with 103 additions and 42 deletions

View File

@ -115,7 +115,8 @@ BOOL LLApp::sDisableCrashlogger = FALSE;
BOOL LLApp::sLogInSignal = FALSE;
// static
LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED; // Keeps track of application status
// Keeps track of application status
LLScalarCond<LLApp::EAppStatus> LLApp::sStatus{LLApp::APP_STATUS_STOPPED};
LLAppErrorHandler LLApp::sErrorHandler = NULL;
BOOL LLApp::sErrorThreadRunning = FALSE;
@ -582,7 +583,8 @@ static std::map<LLApp::EAppStatus, const char*> statusDesc
// static
void LLApp::setStatus(EAppStatus status)
{
sStatus = status;
// notify everyone waiting on sStatus any time its value changes
sStatus.set_all(status);
// This can also happen very late in the application lifecycle -- don't
// resurrect a deleted LLSingleton
@ -612,6 +614,12 @@ void LLApp::setError()
setStatus(APP_STATUS_ERROR);
}
// static
bool LLApp::sleep(F32Milliseconds duration)
{
return ! sStatus.wait_for_unequal(duration, APP_STATUS_RUNNING);
}
void LLApp::setMiniDumpDir(const std::string &path)
{
if (path.empty())
@ -671,28 +679,28 @@ void LLApp::setStopped()
// static
bool LLApp::isStopped()
{
return (APP_STATUS_STOPPED == sStatus);
return (APP_STATUS_STOPPED == sStatus.get());
}
// static
bool LLApp::isRunning()
{
return (APP_STATUS_RUNNING == sStatus);
return (APP_STATUS_RUNNING == sStatus.get());
}
// static
bool LLApp::isError()
{
return (APP_STATUS_ERROR == sStatus);
return (APP_STATUS_ERROR == sStatus.get());
}
// static
bool LLApp::isQuitting()
{
return (APP_STATUS_QUITTING == sStatus);
return (APP_STATUS_QUITTING == sStatus.get());
}
// static

View File

@ -28,9 +28,11 @@
#define LL_LLAPP_H
#include <map>
#include "llcond.h"
#include "llrun.h"
#include "llsd.h"
#include <atomic>
#include <chrono>
// Forward declarations
class LLErrorThread;
class LLLiveFile;
@ -211,6 +213,36 @@ public:
static bool isExiting(); // Either quitting or error (app is exiting, cleanly or not)
static int getPid();
//
// Sleep for specified time while still running
//
// For use by a coroutine or thread that performs some maintenance on a
// periodic basis. (See also LLEventTimer.) This method supports the
// pattern of an "infinite" loop that sleeps for some time, performs some
// action, then sleeps again. The trouble with literally sleeping a worker
// thread is that it could potentially sleep right through attempted
// application shutdown. This method avoids that by returning false as
// soon as the application status changes away from APP_STATUS_RUNNING
// (isRunning()).
//
// sleep() returns true if it sleeps undisturbed for the entire specified
// duration. The idea is that you can code 'while sleep(duration) ...',
// which will break the loop once shutdown begins.
//
// Since any time-based LLUnit should be implicitly convertible to
// F32Milliseconds, accept that specific type as a proxy.
static bool sleep(F32Milliseconds duration);
// Allow any duration defined in terms of <chrono>.
// One can imagine a wonderfully general bidirectional conversion system
// between any type derived from LLUnits::LLUnit<T, LLUnits::Seconds> and
// any std::chrono::duration -- but that doesn't yet exist.
template <typename Rep, typename Period>
bool sleep(const std::chrono::duration<Rep, Period>& duration)
{
// wait_for_unequal() has the opposite bool return convention
return ! sStatus.wait_for_unequal(duration, APP_STATUS_RUNNING);
}
/** @name Error handling methods */
//@{
/**
@ -241,8 +273,8 @@ public:
// Return the Google Breakpad minidump filename after a crash.
char *getMiniDumpFilename() { return mMinidumpPath; }
std::string* getStaticDebugFile() { return &mStaticDebugFileName; }
std::string* getDynamicDebugFile() { return &mDynamicDebugFileName; }
std::string* getStaticDebugFile() { return &mStaticDebugFileName; }
std::string* getDynamicDebugFile() { return &mDynamicDebugFileName; }
// Write out a Google Breakpad minidump file.
void writeMiniDump();
@ -266,7 +298,7 @@ public:
protected:
static void setStatus(EAppStatus status); // Use this to change the application status.
static EAppStatus sStatus; // Reflects current application status
static LLScalarCond<EAppStatus> sStatus; // Reflects current application status
static BOOL sErrorThreadRunning; // Set while the error thread is running
static BOOL sDisableCrashlogger; // Let the OS handle crashes for us.
std::wstring mCrashReportPipeStr; //Name of pipe to use for crash reporting.

View File

@ -27,7 +27,6 @@
#ifndef LL_LLTHREAD_H
#define LL_LLTHREAD_H
#include "llapp.h"
#include "llapr.h"
#include "boost/intrusive_ptr.hpp"
#include "llrefcount.h"

View File

@ -33,6 +33,7 @@
#include <iphlpapi.h>
#endif
#include "llapp.h"
#include "lldefs.h"
#include "llerror.h"

View File

@ -725,7 +725,7 @@ bool LLCrashLogger::init()
#if LL_WINDOWS
Sleep(1000);
#else
sleep(1);
::sleep(1);
#endif
locked = mKeyMaster.checkMaster();
}

View File

@ -31,6 +31,7 @@
*/
#include "linden_common.h"
#include "llapp.h"
#include "llassettype.h"
#include "lldir.h"
#include <boost/filesystem.hpp>
@ -62,6 +63,34 @@ LLDiskCache::LLDiskCache(const std::string cache_dir,
// </FS:Ansariel>
}
// WARNING: purge() is called by LLPurgeDiskCacheThread. As such it must
// NOT touch any LLDiskCache data without introducing and locking a mutex!
// Interaction through the filesystem itself should be safe. Lets say thread
// A is accessing the cache file for reading/writing and thread B is trimming
// the cache. Lets also assume using llifstream to open a file and
// boost::filesystem::remove are not atomic (which will be pretty much the
// case).
// Now, A is trying to open the file using llifstream ctor. It does some
// checks if the file exists and whatever else it might be doing, but has not
// issued the call to the OS to actually open the file yet. Now B tries to
// delete the file: If the file has been already marked as in use by the OS,
// deleting the file will fail and B will continue with the next file. A can
// safely continue opening the file. If the file has not yet been marked as in
// use, B will delete the file. Now A actually wants to open it, operation
// will fail, subsequent check via llifstream.is_open will fail, asset will
// have to be re-requested. (Assuming here the viewer will actually handle
// this situation properly, that can also happen if there is a file containing
// garbage.)
// Other situation: B is trimming the cache and A wants to read a file that is
// about to get deleted. boost::filesystem::remove does whatever it is doing
// before actually deleting the file. If A opens the file before the file is
// actually gone, the OS call from B to delete the file will fail since the OS
// will prevent this. B continues with the next file. If the file is already
// gone before A finally gets to open it, this operation will fail and the
// asset will have to be re-requested.
void LLDiskCache::purge()
{
//if (mEnableCacheDebugInfo)
@ -364,26 +393,17 @@ uintmax_t LLDiskCache::dirFileSize(const std::string dir)
return total_file_size;
}
// <FS:Ansariel> Regular disk cache cleanup
FSPurgeDiskCacheThread::FSPurgeDiskCacheThread() :
LLPurgeDiskCacheThread::LLPurgeDiskCacheThread() :
LLThread("PurgeDiskCacheThread", nullptr)
{
}
void FSPurgeDiskCacheThread::run()
void LLPurgeDiskCacheThread::run()
{
constexpr F64 CHECK_INTERVAL = 60;
mTimer.setTimerExpirySec(CHECK_INTERVAL);
mTimer.start();
constexpr std::chrono::seconds CHECK_INTERVAL{60};
do
while (LLApp::instance()->sleep(CHECK_INTERVAL))
{
if (mTimer.checkExpirationAndReset(CHECK_INTERVAL))
{
LLDiskCache::instance().purge();
}
ms_sleep(100);
} while (!isQuitting());
LLDiskCache::instance().purge();
}
}
// </FS:Ansariel>

View File

@ -126,6 +126,13 @@ class LLDiskCache :
/**
* Purge the oldest items in the cache so that the combined size of all files
* is no bigger than mMaxSizeBytes.
*
* WARNING: purge() is called by LLPurgeDiskCacheThread. As such it must
* NOT touch any LLDiskCache data without introducing and locking a mutex!
*
* Purging the disk cache involves nontrivial work on the viewer's
* filesystem. If called on the main thread, this causes a noticeable
* freeze.
*/
void purge();
@ -191,17 +198,12 @@ class LLDiskCache :
bool mEnableCacheDebugInfo;
};
// <FS:Ansariel> Regular disk cache cleanup
class FSPurgeDiskCacheThread : public LLThread
class LLPurgeDiskCacheThread : public LLThread
{
public:
FSPurgeDiskCacheThread();
LLPurgeDiskCacheThread();
protected:
void run() override;
private:
LLTimer mTimer;
};
// </FS:Ansariel>
#endif // _LLDISKCACHE

View File

@ -46,6 +46,7 @@
#include "apr_poll.h"
// linden library headers
#include "llapp.h"
#include "indra_constants.h"
#include "lldir.h"
#include "llerror.h"

View File

@ -28,6 +28,7 @@
#include "linden_common.h"
#include "llapp.h"
#include "llpluginprocessparent.h"
#include "llpluginmessagepipe.h"
#include "llpluginmessageclasses.h"

View File

@ -735,7 +735,7 @@ LLAppViewer* LLAppViewer::sInstance = NULL;
LLTextureCache* LLAppViewer::sTextureCache = NULL;
LLImageDecodeThread* LLAppViewer::sImageDecodeThread = NULL;
LLTextureFetch* LLAppViewer::sTextureFetch = NULL;
FSPurgeDiskCacheThread* LLAppViewer::sPurgeDiskCacheThread = NULL; // <FS:Ansariel> Regular disk cache cleanup
LLPurgeDiskCacheThread* LLAppViewer::sPurgeDiskCacheThread = NULL;
std::string getRuntime()
{
@ -2448,7 +2448,7 @@ bool LLAppViewer::cleanup()
sTextureFetch->shutdown();
sTextureCache->shutdown();
sImageDecodeThread->shutdown();
sPurgeDiskCacheThread->shutdown(); // <FS:Ansariel> Regular disk cache cleanup
sPurgeDiskCacheThread->shutdown();
sTextureFetch->shutDownTextureCacheThread() ;
sTextureFetch->shutDownImageDecodeThread() ;
@ -2471,10 +2471,8 @@ bool LLAppViewer::cleanup()
sImageDecodeThread = NULL;
delete mFastTimerLogThread;
mFastTimerLogThread = NULL;
// <FS:Ansariel> Regular disk cache cleanup
delete sPurgeDiskCacheThread;
sPurgeDiskCacheThread = NULL;
// </FS:Ansariel>
if (LLFastTimerView::sAnalyzePerformance)
{
@ -2599,7 +2597,7 @@ bool LLAppViewer::initThreads()
sImageDecodeThread,
enable_threads && true,
app_metrics_qa_mode);
LLAppViewer::sPurgeDiskCacheThread = new FSPurgeDiskCacheThread(); // <FS:Ansariel> Regular disk cache cleanup
LLAppViewer::sPurgeDiskCacheThread = new LLPurgeDiskCacheThread();
if (LLTrace::BlockTimer::sLog || LLTrace::BlockTimer::sMetricLog)
{
@ -5076,7 +5074,6 @@ bool LLAppViewer::initCache()
LLDiskCache::getInstance()->purge();
}
}
// <FS:Ansariel> Regular disk cache cleanup
LLAppViewer::getPurgeDiskCacheThread()->start();
// <FS:Ansariel> FIRE-13066

View File

@ -58,8 +58,8 @@ class LLImageDecodeThread;
class LLTextureFetch;
class LLWatchdogTimeout;
class LLViewerJoystick;
class LLPurgeDiskCacheThread;
class LLViewerRegion; // <FS:Beq/>
class FSPurgeDiskCacheThread; // <FS:Ansariel> Regular disk cache cleanup
extern LLTrace::BlockTimerStatHandle FTM_FRAME;
@ -119,7 +119,7 @@ public:
static LLTextureCache* getTextureCache() { return sTextureCache; }
static LLImageDecodeThread* getImageDecodeThread() { return sImageDecodeThread; }
static LLTextureFetch* getTextureFetch() { return sTextureFetch; }
static FSPurgeDiskCacheThread* getPurgeDiskCacheThread() { return sPurgeDiskCacheThread; } // <FS:Ansariel> Regular disk cache cleanup
static LLPurgeDiskCacheThread* getPurgeDiskCacheThread() { return sPurgeDiskCacheThread; }
static U32 getTextureCacheVersion() ;
static U32 getObjectCacheVersion() ;
@ -309,7 +309,7 @@ private:
static LLTextureCache* sTextureCache;
static LLImageDecodeThread* sImageDecodeThread;
static LLTextureFetch* sTextureFetch;
static FSPurgeDiskCacheThread* sPurgeDiskCacheThread; // <FS:Ansariel> Regular disk cache cleanup
static LLPurgeDiskCacheThread* sPurgeDiskCacheThread;
S32 mNumSessions;