diff --git a/netwerk/cache2/CacheFileIOManager.cpp b/netwerk/cache2/CacheFileIOManager.cpp index 004e7ff907e7..91d2a57a652a 100644 --- a/netwerk/cache2/CacheFileIOManager.cpp +++ b/netwerk/cache2/CacheFileIOManager.cpp @@ -42,7 +42,9 @@ namespace net { #define kOpenHandlesLimit 64 #define kMetadataWriteDelay 5000 +#define kEvictionLoopLimit 40 // in milliseconds #define kRemoveTrashStartDelay 60000 // in milliseconds +#define kRemoveTrashLoopLimit 40 // in milliseconds bool CacheFileHandle::DispatchRelease() @@ -2351,7 +2353,7 @@ CacheFileIOManager::OverLimitEvictionInternal() MOZ_ASSERT(mIOThread->IsCurrentThread()); // mOverLimitEvicting is accessed only on IO thread, so we can set it to false - // here and set it to true again once we dispatch another event that will + // here and set ti to true again once we dispatch another event that will // continue with the eviction. The reason why we do so is that we can fail // early anywhere in this method and the variable will contain a correct // value. Otherwise we would need to set it to false on every failing place. @@ -2361,6 +2363,8 @@ CacheFileIOManager::OverLimitEvictionInternal() return NS_ERROR_NOT_INITIALIZED; } + TimeStamp start; + while (true) { uint32_t cacheUsage; rv = CacheIndex::GetCacheSize(&cacheUsage); @@ -2376,11 +2380,15 @@ CacheFileIOManager::OverLimitEvictionInternal() LOG(("CacheFileIOManager::OverLimitEvictionInternal() - Cache size over " "limit. [cacheSize=%u, limit=%u]", cacheUsage, cacheLimit)); - if (CacheIOThread::YieldAndRerun()) { - LOG(("CacheFileIOManager::OverLimitEvictionInternal() - Breaking loop " - "for higher level events.")); - mOverLimitEvicting = true; - return NS_OK; + if (start.IsNull()) { + start = TimeStamp::NowLoRes(); + } else { + TimeDuration elapsed = TimeStamp::NowLoRes() - start; + if (elapsed.ToMilliseconds() >= kEvictionLoopLimit) { + LOG(("CacheFileIOManager::OverLimitEvictionInternal() - Breaking loop " + "after %u ms.", static_cast(elapsed.ToMilliseconds()))); + break; + } } SHA1Sum::Hash hash; @@ -2435,7 +2443,14 @@ CacheFileIOManager::OverLimitEvictionInternal() } } - NS_NOTREACHED("We should never get here"); + nsCOMPtr ev; + ev = NS_NewRunnableMethod(this, + &CacheFileIOManager::OverLimitEvictionInternal); + + rv = mIOThread->Dispatch(ev, CacheIOThread::EVICT); + NS_ENSURE_SUCCESS(rv, rv); + + mOverLimitEvicting = true; return NS_OK; } @@ -2613,12 +2628,20 @@ CacheFileIOManager::RemoveTrashInternal() // we don't have to drop the flag on any possible early return. mRemovingTrashDirs = false; + TimeStamp start; + while (true) { - if (CacheIOThread::YieldAndRerun()) { - LOG(("CacheFileIOManager::RemoveTrashInternal() - Breaking loop for " - "higher level events.")); - mRemovingTrashDirs = true; - return NS_OK; + if (start.IsNull()) { + start = TimeStamp::NowLoRes(); + } else { + static TimeDuration const kLimit = TimeDuration::FromMilliseconds( + kRemoveTrashLoopLimit); + TimeDuration elapsed = TimeStamp::NowLoRes() - start; + if (elapsed >= kLimit) { + LOG(("CacheFileIOManager::RemoveTrashInternal() - Breaking loop after " + "%u ms.", static_cast(elapsed.ToMilliseconds()))); + break; + } } // Find some trash directory @@ -2686,7 +2709,14 @@ CacheFileIOManager::RemoveTrashInternal() } } - NS_NOTREACHED("We should never get here"); + nsCOMPtr ev; + ev = NS_NewRunnableMethod(this, + &CacheFileIOManager::RemoveTrashInternal); + + rv = mIOThread->Dispatch(ev, CacheIOThread::EVICT); + NS_ENSURE_SUCCESS(rv, rv); + + mRemovingTrashDirs = true; return NS_OK; } diff --git a/netwerk/cache2/CacheIOThread.cpp b/netwerk/cache2/CacheIOThread.cpp index c0c1910dfe45..2b0509c04861 100644 --- a/netwerk/cache2/CacheIOThread.cpp +++ b/netwerk/cache2/CacheIOThread.cpp @@ -14,25 +14,19 @@ namespace mozilla { namespace net { -CacheIOThread* CacheIOThread::sSelf = nullptr; - NS_IMPL_ISUPPORTS1(CacheIOThread, nsIThreadObserver) CacheIOThread::CacheIOThread() : mMonitor("CacheIOThread") , mThread(nullptr) , mLowestLevelWaiting(LAST_LEVEL) -, mCurrentlyExecutingLevel(0) , mHasXPCOMEvents(false) -, mRerunCurrentEvent(false) , mShutdown(false) { - sSelf = this; } CacheIOThread::~CacheIOThread() { - sSelf = nullptr; #ifdef DEBUG for (uint32_t level = 0; level < LAST_LEVEL; ++level) { MOZ_ASSERT(!mEventQueue[level].Length()); @@ -74,27 +68,6 @@ bool CacheIOThread::IsCurrentThread() return mThread == PR_GetCurrentThread(); } -bool CacheIOThread::YieldInternal() -{ - if (!IsCurrentThread()) { - NS_WARNING("Trying to yield to priority events on non-cache2 I/O thread? " - "You probably do something wrong."); - return false; - } - - if (mCurrentlyExecutingLevel == XPCOM_LEVEL) { - // Doesn't make any sense, since this handler is the one - // that would be executed as the next one. - return false; - } - - if (!EventsPending(mCurrentlyExecutingLevel)) - return false; - - mRerunCurrentEvent = true; - return true; -} - nsresult CacheIOThread::Shutdown() { { @@ -164,8 +137,6 @@ loopStart: "net::cache::io::level(xpcom)"); mHasXPCOMEvents = false; - mCurrentlyExecutingLevel = XPCOM_LEVEL; - MonitorAutoUnlock unlock(mMonitor); bool processedEvent; @@ -233,8 +204,6 @@ void CacheIOThread::LoopOneLevel(uint32_t aLevel) events.SwapElements(mEventQueue[aLevel]); uint32_t length = events.Length(); - mCurrentlyExecutingLevel = aLevel; - bool returnEvents = false; uint32_t index; { @@ -248,19 +217,7 @@ void CacheIOThread::LoopOneLevel(uint32_t aLevel) break; } - // Drop any previous flagging, only an event on the current level may set - // this flag. - mRerunCurrentEvent = false; - events[index]->Run(); - - if (mRerunCurrentEvent) { - // The event handler yields to higher priority events and wants to rerun. - returnEvents = true; - break; - } - - // Release outside the lock. events[index] = nullptr; } } diff --git a/netwerk/cache2/CacheIOThread.h b/netwerk/cache2/CacheIOThread.h index b2305899ad76..7d45ee2f0095 100644 --- a/netwerk/cache2/CacheIOThread.h +++ b/netwerk/cache2/CacheIOThread.h @@ -36,32 +36,12 @@ public: CLOSE, BUILD_OR_UPDATE_INDEX, EVICT, - LAST_LEVEL, - - // This is actually executed as the first level, but we want this enum - // value merely as an indicator while other values are used as indexes - // to the queue array. Hence put at end and not as the first. - XPCOM_LEVEL + LAST_LEVEL }; nsresult Init(); nsresult Dispatch(nsIRunnable* aRunnable, uint32_t aLevel); bool IsCurrentThread(); - - /** - * Callable only on this thread, checks if there is an event waiting in - * the event queue with a higher execution priority. If so, the result - * is true and the current event handler should break it's work and return - * from Run() method immediately. The event handler will be rerun again - * when all more priority events are processed. Events pending after this - * handler (i.e. the one that called YieldAndRerun()) will not execute sooner - * then this handler is executed w/o a call to YieldAndRerun(). - */ - static bool YieldAndRerun() - { - return sSelf ? sSelf->YieldInternal() : false; - } - nsresult Shutdown(); already_AddRefed Target(); @@ -74,19 +54,14 @@ private: void ThreadFunc(); void LoopOneLevel(uint32_t aLevel); bool EventsPending(uint32_t aLastLevel = LAST_LEVEL); - bool YieldInternal(); - - static CacheIOThread* sSelf; mozilla::Monitor mMonitor; PRThread* mThread; nsCOMPtr mXPCOMThread; uint32_t mLowestLevelWaiting; - uint32_t mCurrentlyExecutingLevel; nsTArray > mEventQueue[LAST_LEVEL]; bool mHasXPCOMEvents; - bool mRerunCurrentEvent; bool mShutdown; }; diff --git a/netwerk/cache2/CacheIndex.cpp b/netwerk/cache2/CacheIndex.cpp index c6c5659856dc..82acafa33f86 100644 --- a/netwerk/cache2/CacheIndex.cpp +++ b/netwerk/cache2/CacheIndex.cpp @@ -25,6 +25,8 @@ #define kIndexVersion 0x00000001 #define kBuildIndexStartDelay 10000 // in milliseconds #define kUpdateIndexStartDelay 10000 // in milliseconds +#define kBuildIndexLoopLimit 40 // in milliseconds +#define kUpdateIndexLoopLimit 40 // in milliseconds const char kIndexName[] = "index"; const char kTempIndexName[] = "index.tmp"; @@ -2367,10 +2369,20 @@ CacheIndex::BuildIndex() } } + TimeStamp start; + while (true) { - if (CacheIOThread::YieldAndRerun()) { - LOG(("CacheIndex::BuildIndex() - Breaking loop for higher level events.")); - return; + if (start.IsNull()) { + start = TimeStamp::NowLoRes(); + } else { + static TimeDuration const kLimit = TimeDuration::FromMilliseconds( + kBuildIndexLoopLimit); + TimeDuration elapsed = TimeStamp::NowLoRes() - start; + if (elapsed >= kLimit) { + LOG(("CacheIndex::BuildIndex() - Breaking loop after %u ms.", + static_cast(elapsed.ToMilliseconds()))); + break; + } } nsCOMPtr file; @@ -2472,7 +2484,16 @@ CacheIndex::BuildIndex() } } - NS_NOTREACHED("We should never get here"); + nsRefPtr ioThread = CacheFileIOManager::IOThread(); + MOZ_ASSERT(ioThread); + + rv = ioThread->Dispatch(this, CacheIOThread::BUILD_OR_UPDATE_INDEX); + if (NS_FAILED(rv)) { + NS_WARNING("CacheIndex::BuildIndex() - Can't dispatch event"); + LOG(("CacheIndex::BuildIndex() - Can't dispatch event" )); + FinishBuild(false); + return; + } } void @@ -2599,11 +2620,20 @@ CacheIndex::UpdateIndex() } } + TimeStamp start; + while (true) { - if (CacheIOThread::YieldAndRerun()) { - LOG(("CacheIndex::UpdateIndex() - Breaking loop for higher level " - "events.")); - return; + if (start.IsNull()) { + start = TimeStamp::NowLoRes(); + } else { + static TimeDuration const kLimit = TimeDuration::FromMilliseconds( + kUpdateIndexLoopLimit); + TimeDuration elapsed = TimeStamp::NowLoRes() - start; + if (elapsed >= kLimit) { + LOG(("CacheIndex::UpdateIndex() - Breaking loop after %u ms.", + static_cast(elapsed.ToMilliseconds()))); + break; + } } nsCOMPtr file; @@ -2739,7 +2769,16 @@ CacheIndex::UpdateIndex() } } - NS_NOTREACHED("We should never get here"); + nsRefPtr ioThread = CacheFileIOManager::IOThread(); + MOZ_ASSERT(ioThread); + + rv = ioThread->Dispatch(this, CacheIOThread::BUILD_OR_UPDATE_INDEX); + if (NS_FAILED(rv)) { + NS_WARNING("CacheIndex::UpdateIndex() - Can't dispatch event"); + LOG(("CacheIndex::UpdateIndex() - Can't dispatch event" )); + FinishUpdate(false); + return; + } } void diff --git a/netwerk/cache2/CacheStorageService.cpp b/netwerk/cache2/CacheStorageService.cpp index e305415c737f..aadeecf8ede3 100644 --- a/netwerk/cache2/CacheStorageService.cpp +++ b/netwerk/cache2/CacheStorageService.cpp @@ -638,11 +638,13 @@ nsresult CacheFilesDeletor::Execute() } nsresult rv; + TimeStamp start; switch (mMode) { case ALL: case DOOMED: // Simply delete all files, don't doom then though the backend + start = TimeStamp::NowLoRes(); while (mEnumerator->HasMore()) { nsCOMPtr file; @@ -663,9 +665,15 @@ nsresult CacheFilesDeletor::Execute() ++mRunning; - if (CacheIOThread::YieldAndRerun()) { - LOG((" deleted %u files, breaking loop for higher level events.")); - return NS_OK; + if (!(mRunning % (1 << 5)) && mEnumerator->HasMore()) { + TimeStamp now(TimeStamp::NowLoRes()); +#define DELETOR_LOOP_LIMIT_MS 200 + static TimeDuration const kLimitms = TimeDuration::FromMilliseconds(DELETOR_LOOP_LIMIT_MS); + if ((now - start) > kLimitms) { + LOG((" deleted %u files, breaking %dms loop", mRunning, DELETOR_LOOP_LIMIT_MS)); + rv = mIOThread->Dispatch(this, CacheIOThread::EVICT); + return rv; + } } } @@ -1058,9 +1066,7 @@ CacheStorageService::PurgeOverMemoryLimit() LOG((" purging took %1.2fms", (TimeStamp::Now() - start).ToMilliseconds())); - // When we exit because of yield, leave the flag so this event is not reposted - // from OnMemoryConsumptionChange unnecessarily until we are dequeued again. - mPurging = CacheIOThread::YieldAndRerun(); + mPurging = false; } void @@ -1074,9 +1080,6 @@ CacheStorageService::PurgeExpired() uint32_t const memoryLimit = CacheObserver::MemoryLimit(); for (uint32_t i = 0; mMemorySize > memoryLimit && i < mExpirationArray.Length();) { - if (CacheIOThread::YieldAndRerun()) - return; - nsRefPtr entry = mExpirationArray[i]; uint32_t expirationTime = entry->GetExpirationTime(); @@ -1106,9 +1109,6 @@ CacheStorageService::PurgeByFrecency(bool &aFrecencyNeedsSort, uint32_t aWhat) uint32_t const memoryLimit = CacheObserver::MemoryLimit(); for (uint32_t i = 0; mMemorySize > memoryLimit && i < mFrecencyArray.Length();) { - if (CacheIOThread::YieldAndRerun()) - return; - nsRefPtr entry = mFrecencyArray[i]; if (entry->Purge(aWhat)) { @@ -1129,9 +1129,6 @@ CacheStorageService::PurgeAll(uint32_t aWhat) MOZ_ASSERT(IsOnManagementThread()); for (uint32_t i = 0; i < mFrecencyArray.Length();) { - if (CacheIOThread::YieldAndRerun()) - return; - nsRefPtr entry = mFrecencyArray[i]; if (entry->Purge(aWhat)) {