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:
Kris Maglione 2017-06-28 14:46:30 -07:00
Родитель 90cc3a89f7
Коммит a85cdee020
2 изменённых файлов: 37 добавлений и 3 удалений

Просмотреть файл

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