зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1371248: Avoid hangs when preloader cache flush is triggered during shutdown. r=erahm
MozReview-Commit-ID: FpW53d5TTCG --HG-- extra : rebase_source : f7201ba0309675db292c1e1e7f4f21c04292d6f8
This commit is contained in:
Родитель
90cc3a89f7
Коммит
a85cdee020
|
@ -241,6 +241,10 @@ ScriptPreloader::ForceWriteCacheFile()
|
|||
if (mSaveThread) {
|
||||
MonitorAutoLock mal(mSaveMonitor);
|
||||
|
||||
// Make sure we've prepared scripts, so we don't risk deadlocking while
|
||||
// dispatching the prepare task during shutdown.
|
||||
PrepareCacheWriteInternal();
|
||||
|
||||
// Unblock the save thread, so it can start saving before we get to
|
||||
// XPCOM shutdown.
|
||||
mal.Notify();
|
||||
|
@ -253,6 +257,10 @@ ScriptPreloader::Cleanup()
|
|||
if (mSaveThread) {
|
||||
MonitorAutoLock mal(mSaveMonitor);
|
||||
|
||||
// Make sure the save thread is not blocked dispatching a sync task to
|
||||
// the main thread, or we will deadlock.
|
||||
MOZ_RELEASE_ASSERT(!mBlockedOnSyncDispatch);
|
||||
|
||||
while (!mSaveComplete && mSaveThread) {
|
||||
mal.Wait();
|
||||
}
|
||||
|
@ -288,6 +296,10 @@ ScriptPreloader::InvalidateCache()
|
|||
if (mSaveComplete && mChildCache) {
|
||||
mSaveComplete = false;
|
||||
|
||||
// Make sure scripts are prepared to avoid deadlock when invalidating
|
||||
// the cache during shutdown.
|
||||
PrepareCacheWriteInternal();
|
||||
|
||||
Unused << NS_NewNamedThread("SaveScripts",
|
||||
getter_AddRefs(mSaveThread), this);
|
||||
}
|
||||
|
@ -499,10 +511,12 @@ Write(PRFileDesc* fd, const void* data, int32_t len)
|
|||
}
|
||||
|
||||
void
|
||||
ScriptPreloader::PrepareCacheWrite()
|
||||
ScriptPreloader::PrepareCacheWriteInternal()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mSaveMonitor.AssertCurrentThreadOwns();
|
||||
|
||||
auto cleanup = MakeScopeExit([&] () {
|
||||
if (mChildCache) {
|
||||
mChildCache->PrepareCacheWrite();
|
||||
|
@ -547,6 +561,14 @@ ScriptPreloader::PrepareCacheWrite()
|
|||
mDataPrepared = true;
|
||||
}
|
||||
|
||||
void
|
||||
ScriptPreloader::PrepareCacheWrite()
|
||||
{
|
||||
MonitorAutoLock mal(mSaveMonitor);
|
||||
|
||||
PrepareCacheWriteInternal();
|
||||
}
|
||||
|
||||
// Writes out a script cache file for the scripts accessed during early
|
||||
// startup in this session. The cache file is a little-endian binary file with
|
||||
// the following format:
|
||||
|
@ -568,6 +590,9 @@ ScriptPreloader::WriteCache()
|
|||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
if (!mDataPrepared && !mSaveComplete) {
|
||||
MOZ_ASSERT(!mBlockedOnSyncDispatch);
|
||||
mBlockedOnSyncDispatch = true;
|
||||
|
||||
MonitorAutoUnlock mau(mSaveMonitor);
|
||||
|
||||
NS_DispatchToMainThread(
|
||||
|
@ -577,6 +602,8 @@ ScriptPreloader::WriteCache()
|
|||
NS_DISPATCH_SYNC);
|
||||
}
|
||||
|
||||
mBlockedOnSyncDispatch = false;
|
||||
|
||||
if (mSaveComplete) {
|
||||
// If we don't have anything we need to save, we're done.
|
||||
return Ok();
|
||||
|
@ -642,8 +669,12 @@ ScriptPreloader::Run()
|
|||
MonitorAutoLock mal(mSaveMonitor);
|
||||
|
||||
// Ideally wait about 10 seconds before saving, to avoid unnecessary IO
|
||||
// during early startup.
|
||||
mal.Wait(10000);
|
||||
// during early startup. But only if the cache hasn't been invalidated,
|
||||
// since that can trigger a new write during shutdown, and we don't want to
|
||||
// cause shutdown hangs.
|
||||
if (!mCacheInvalidated) {
|
||||
mal.Wait(10000);
|
||||
}
|
||||
|
||||
auto result = WriteCache();
|
||||
Unused << NS_WARN_IF(result.isErr());
|
||||
|
|
|
@ -367,6 +367,8 @@ private:
|
|||
// XDR, and calculating their size-based offsets.
|
||||
void PrepareCacheWrite();
|
||||
|
||||
void PrepareCacheWriteInternal();
|
||||
|
||||
// Returns a file pointer for the cache file with the given name in the
|
||||
// current profile.
|
||||
Result<nsCOMPtr<nsIFile>, nsresult>
|
||||
|
@ -410,6 +412,7 @@ private:
|
|||
bool mSaveComplete = false;
|
||||
bool mDataPrepared = false;
|
||||
bool mCacheInvalidated = false;
|
||||
bool mBlockedOnSyncDispatch = false;
|
||||
|
||||
// The list of scripts that we read from the initial startup cache file,
|
||||
// but have yet to initiate a decode task for.
|
||||
|
|
Загрузка…
Ссылка в новой задаче