diff --git a/startupcache/StartupCache.cpp b/startupcache/StartupCache.cpp index 93cc3259cac2..12fa22a5b118 100644 --- a/startupcache/StartupCache.cpp +++ b/startupcache/StartupCache.cpp @@ -149,7 +149,8 @@ StartupCache::StartupCache() mCurTableReferenced(false), mRequestedCount(0), mCacheEntriesBaseOffset(0), - mWriteThread(nullptr) {} + mWriteThread(nullptr), + mPrefetchThread(nullptr) {} StartupCache::~StartupCache() { if (mTimer) { @@ -160,6 +161,7 @@ StartupCache::~StartupCache() { // but an early shutdown means either mTimer didn't run // or the write thread is still running. WaitOnWriteThread(); + WaitOnPrefetchThread(); // If we shutdown quickly timer wont have fired. Instead of writing // it on the main thread and block the shutdown we simply wont update @@ -243,6 +245,15 @@ nsresult StartupCache::Init() { return NS_OK; } +void StartupCache::StartPrefetchMemoryThread() { + // XXX: It would be great for this to not create its own thread, unfortunately + // there doesn't seem to be an existing thread that makes sense for this, so + // barring a coordinated global scheduling system this is the best we get. + mPrefetchThread = PR_CreateThread( + PR_USER_THREAD, StartupCache::ThreadedPrefetch, this, PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); +} + /** * LoadArchive can be called from the main thread or while reloading cache on * write thread. @@ -252,6 +263,9 @@ Result StartupCache::LoadArchive() { MOZ_TRY(mCacheData.init(mFile)); auto size = mCacheData.size(); + if (CanPrefetchMemory()) { + StartPrefetchMemoryThread(); + } uint32_t headerSize; if (size < sizeof(MAGIC) + sizeof(headerSize)) { @@ -365,9 +379,6 @@ nsresult StartupCache::GetBuffer(const char* id, const char** outbuf, Span compressed = MakeSpan( mCacheData.get().get() + mCacheEntriesBaseOffset + value.mOffset, value.mCompressedSize); - if (CanPrefetchMemory()) { - PrefetchMemory((uint8_t*)compressed.Elements(), compressed.Length()); - } value.mData = MakeUnique(value.mUncompressedSize); Span uncompressed = MakeSpan(value.mData.get(), value.mUncompressedSize); @@ -611,6 +622,23 @@ void StartupCache::WaitOnWriteThread() { mWriteThread = nullptr; } +void StartupCache::WaitOnPrefetchThread() { + if (!mPrefetchThread || mPrefetchThread == PR_GetCurrentThread()) return; + + PR_JoinThread(mPrefetchThread); + mPrefetchThread = nullptr; +} + +void StartupCache::ThreadedPrefetch(void* aClosure) { + AUTO_PROFILER_REGISTER_THREAD("StartupCache"); + NS_SetCurrentThreadName("StartupCache"); + mozilla::IOInterposer::RegisterCurrentThread(); + StartupCache* startupCacheObj = static_cast(aClosure); + PrefetchMemory(startupCacheObj->mCacheData.get().get(), + startupCacheObj->mCacheData.size()); + mozilla::IOInterposer::UnregisterCurrentThread(); +} + void StartupCache::ThreadedWrite(void* aClosure) { AUTO_PROFILER_REGISTER_THREAD("StartupCache"); NS_SetCurrentThreadName("StartupCache"); @@ -660,6 +688,7 @@ void StartupCache::WriteTimeout(nsITimer* aTimer, void* aClosure) { return; } + startupCacheObj->WaitOnPrefetchThread(); startupCacheObj->mStartupWriteInitiated = false; startupCacheObj->mDirty = true; startupCacheObj->mCacheData.reset(); diff --git a/startupcache/StartupCache.h b/startupcache/StartupCache.h index bb901ac89e56..5a322f08078c 100644 --- a/startupcache/StartupCache.h +++ b/startupcache/StartupCache.h @@ -202,10 +202,13 @@ class StartupCache : public nsIMemoryReporter { Result WriteToDisk(); void WaitOnWriteThread(); + void WaitOnPrefetchThread(); + void StartPrefetchMemoryThread(); static nsresult InitSingleton(); static void WriteTimeout(nsITimer* aTimer, void* aClosure); static void ThreadedWrite(void* aClosure); + static void ThreadedPrefetch(void* aClosure); HashMap mTable; // owns references to the contents of tables which have been invalidated. @@ -230,6 +233,7 @@ class StartupCache : public nsIMemoryReporter { static bool gShutdownInitiated; static bool gIgnoreDiskCache; PRThread* mWriteThread; + PRThread* mPrefetchThread; UniquePtr mDecompressionContext; #ifdef DEBUG nsTHashtable mWriteObjectMap;