author | Randell Jesup <rjesup@jesup.org> |
Sat, 26 Jan 2019 12:18:05 -0500 | |
changeset 455556 | 65cf08e33fe2b12a90a505462f3246df204c64ad |
parent 455555 | 0f5c896960f5147c3600c847209fb786dc6c1481 |
child 455557 | 7f8594d21c51ba9966c85b1bacbf0d245e45395f |
push id | 35445 |
push user | cbrindusan@mozilla.com |
push date | Sun, 27 Jan 2019 09:36:05 +0000 |
treeherder | mozilla-central@2013099b2c13 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | froyd |
bugs | 1522150 |
milestone | 66.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/base/ChromeUtils.cpp +++ b/dom/base/ChromeUtils.cpp @@ -365,20 +365,21 @@ NS_IMPL_ISUPPORTS_INHERITED(IdleDispatch const IdleRequestOptions& aOptions, ErrorResult& aRv) { nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); MOZ_ASSERT(global); auto runnable = MakeRefPtr<IdleDispatchRunnable>(global, aCallback); if (aOptions.mTimeout.WasPassed()) { - aRv = NS_IdleDispatchToCurrentThread(runnable.forget(), - aOptions.mTimeout.Value()); + aRv = NS_DispatchToCurrentThreadQueue( + runnable.forget(), aOptions.mTimeout.Value(), EventQueuePriority::Idle); } else { - aRv = NS_IdleDispatchToCurrentThread(runnable.forget()); + aRv = NS_DispatchToCurrentThreadQueue(runnable.forget(), + EventQueuePriority::Idle); } } /* static */ void ChromeUtils::Import( const GlobalObject& aGlobal, const nsAString& aResourceURI, const Optional<JS::Handle<JSObject*>>& aTargetObj, JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv) { RefPtr<mozJSComponentLoader> moduleloader = mozJSComponentLoader::Get();
--- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -8783,17 +8783,18 @@ void Document::RegisterPendingLinkUpdate aLink->SetHasPendingLinkUpdate(); if (!mHasLinksToUpdateRunnable && !mFlushingPendingLinkUpdates) { nsCOMPtr<nsIRunnable> event = NewRunnableMethod("Document::FlushPendingLinkUpdatesFromRunnable", this, &Document::FlushPendingLinkUpdatesFromRunnable); // Do this work in a second in the worst case. - nsresult rv = NS_IdleDispatchToCurrentThread(event.forget(), 1000); + nsresult rv = NS_DispatchToCurrentThreadQueue(event.forget(), 1000, + EventQueuePriority::Idle); if (NS_FAILED(rv)) { // If during shutdown posting a runnable doesn't succeed, we probably // don't need to update link states. return; } mHasLinksToUpdateRunnable = true; } @@ -11971,17 +11972,18 @@ void Document::MaybeStoreUserInteraction return; } if (mHasUserInteractionTimerScheduled) { return; } nsCOMPtr<nsIRunnable> task = new UserIntractionTimer(this); - nsresult rv = NS_IdleDispatchToCurrentThread(task.forget(), 2500); + nsresult rv = NS_DispatchToCurrentThreadQueue(task.forget(), 2500, + EventQueuePriority::Idle); if (NS_WARN_IF(NS_FAILED(rv))) { return; } // This value will be reset by the timer. mHasUserInteractionTimerScheduled = true; }
--- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -1254,17 +1254,18 @@ class ContentUnbinder : public Runnable if (this == sContentUnbinder) { sContentUnbinder = nullptr; if (mNext) { RefPtr<ContentUnbinder> next; next.swap(mNext); sContentUnbinder = next; next->mLast = mLast; mLast = nullptr; - NS_IdleDispatchToCurrentThread(next.forget()); + NS_DispatchToCurrentThreadQueue(next.forget(), + EventQueuePriority::Idle); } } return NS_OK; } static void UnbindAll() { RefPtr<ContentUnbinder> ub = sContentUnbinder; sContentUnbinder = nullptr; @@ -1273,17 +1274,17 @@ class ContentUnbinder : public Runnable ub = ub->mNext; } } static void Append(nsIContent* aSubtreeRoot) { if (!sContentUnbinder) { sContentUnbinder = new ContentUnbinder(); nsCOMPtr<nsIRunnable> e = sContentUnbinder; - NS_IdleDispatchToCurrentThread(e.forget()); + NS_DispatchToCurrentThreadQueue(e.forget(), EventQueuePriority::Idle); } if (sContentUnbinder->mLast->mSubtreeRoots.Length() >= SUBTREE_UNBINDINGS_PER_RUNNABLE) { sContentUnbinder->mLast->mNext = new ContentUnbinder(); sContentUnbinder->mLast = sContentUnbinder->mLast->mNext; } sContentUnbinder->mLast->mSubtreeRoots.AppendElement(aSubtreeRoot);
--- a/dom/base/WindowDestroyedEvent.cpp +++ b/dom/base/WindowDestroyedEvent.cpp @@ -83,17 +83,18 @@ WindowDestroyedEvent::Run() { if (mTopic.EqualsLiteral("inner-window-destroyed")) { mTopic.AssignLiteral("inner-window-nuked"); } else if (mTopic.EqualsLiteral("outer-window-destroyed")) { mTopic.AssignLiteral("outer-window-nuked"); } mPhase = Phase::Nuking; nsCOMPtr<nsIRunnable> copy(this); - NS_IdleDispatchToCurrentThread(copy.forget(), 1000); + NS_DispatchToCurrentThreadQueue(copy.forget(), 1000, + EventQueuePriority::Idle); } } break; case Phase::Nuking: { nsCOMPtr<nsISupports> window = do_QueryReferent(mWindow); if (window) { nsGlobalWindowInner* currentInner; if (mIsInnerWindow) {
--- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -3669,23 +3669,26 @@ void nsContentUtils::AsyncPrecreateStrin // If we attempt to create a bundle in the child before its memory region is // available, we need to create a temporary non-shared bundle, and later // replace that with the shared memory copy. So attempting to pre-load in the // child is wasteful and unnecessary. MOZ_ASSERT(XRE_IsParentProcess()); for (uint32_t bundleIndex = 0; bundleIndex < PropertiesFile_COUNT; ++bundleIndex) { - nsresult rv = NS_IdleDispatchToCurrentThread( - NS_NewRunnableFunction("AsyncPrecreateStringBundles", [bundleIndex]() { - PropertiesFile file = static_cast<PropertiesFile>(bundleIndex); - EnsureStringBundle(file); - nsIStringBundle* bundle = sStringBundles[file]; - bundle->AsyncPreload(); - })); + nsresult rv = NS_DispatchToCurrentThreadQueue( + NS_NewRunnableFunction("AsyncPrecreateStringBundles", + [bundleIndex]() { + PropertiesFile file = + static_cast<PropertiesFile>(bundleIndex); + EnsureStringBundle(file); + nsIStringBundle* bundle = sStringBundles[file]; + bundle->AsyncPreload(); + }), + EventQueuePriority::Idle); Unused << NS_WARN_IF(NS_FAILED(rv)); } } /* static */ nsresult nsContentUtils::GetLocalizedString(PropertiesFile aFile, const char* aKey, nsAString& aResult) {
--- a/dom/base/nsGlobalWindowInner.cpp +++ b/dom/base/nsGlobalWindowInner.cpp @@ -612,17 +612,17 @@ void IdleRequestExecutor::MaybeDispatch( TimeDuration delay = aDelayUntil - now; DelayedDispatch(static_cast<uint32_t>(delay.ToMilliseconds())); } void IdleRequestExecutor::ScheduleDispatch() { MOZ_ASSERT(mWindow); mDelayedExecutorHandle = Nothing(); RefPtr<IdleRequestExecutor> request = this; - NS_IdleDispatchToCurrentThread(request.forget()); + NS_DispatchToCurrentThreadQueue(request.forget(), EventQueuePriority::Idle); } void IdleRequestExecutor::DelayedDispatch(uint32_t aDelay) { MOZ_ASSERT(mWindow); MOZ_ASSERT(mDelayedExecutorHandle.isNothing()); int32_t handle; mWindow->TimeoutManager().SetTimeout( mDelayedExecutorDispatcher, aDelay, false,
--- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -1713,17 +1713,18 @@ mozilla::ipc::IPCResult ContentChild::Re static bool hasRunOnce = false; if (!hasRunOnce) { hasRunOnce = true; MOZ_ASSERT(!gFirstIdleTask); RefPtr<CancelableRunnable> firstIdleTask = NewCancelableRunnableFunction("FirstIdleRunnable", FirstIdle); gFirstIdleTask = firstIdleTask; - if (NS_FAILED(NS_IdleDispatchToCurrentThread(firstIdleTask.forget()))) { + if (NS_FAILED(NS_DispatchToCurrentThreadQueue(firstIdleTask.forget(), + EventQueuePriority::Idle))) { gFirstIdleTask = nullptr; hasRunOnce = false; } } return nsIContentChild::RecvPBrowserConstructor( aActor, aTabId, aSameTabGroupAs, aContext, aChromeFlags, aCpID, aIsForBrowser);
--- a/dom/ipc/PreallocatedProcessManager.cpp +++ b/dom/ipc/PreallocatedProcessManager.cpp @@ -240,19 +240,20 @@ void PreallocatedProcessManagerImpl::All sPrelaunchDelayMS); } void PreallocatedProcessManagerImpl::AllocateOnIdle() { if (!mEnabled) { return; } - NS_IdleDispatchToCurrentThread( + NS_DispatchToCurrentThreadQueue( NewRunnableMethod("PreallocatedProcessManagerImpl::AllocateNow", this, - &PreallocatedProcessManagerImpl::AllocateNow)); + &PreallocatedProcessManagerImpl::AllocateNow), + EventQueuePriority::Idle); } void PreallocatedProcessManagerImpl::AllocateNow() { if (!CanAllocate()) { if (mEnabled && !mShutdown && IsEmpty() && !mBlockers.IsEmpty()) { // If it's too early to allocate a process let's retry later. AllocateAfterDelay(); }
--- a/dom/ipc/SharedMap.cpp +++ b/dom/ipc/SharedMap.cpp @@ -410,18 +410,20 @@ void WritableSharedMap::IdleFlush() { nsresult WritableSharedMap::KeyChanged(const nsACString& aName) { if (!mChangedKeys.ContainsSorted(aName)) { mChangedKeys.InsertElementSorted(aName); } mEntryArray.reset(); if (!mPendingFlush) { - MOZ_TRY(NS_IdleDispatchToCurrentThread(NewRunnableMethod( - "WritableSharedMap::IdleFlush", this, &WritableSharedMap::IdleFlush))); + MOZ_TRY(NS_DispatchToCurrentThreadQueue( + NewRunnableMethod("WritableSharedMap::IdleFlush", this, + &WritableSharedMap::IdleFlush), + EventQueuePriority::Idle)); mPendingFlush = true; } return NS_OK; } JSObject* SharedMap::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto) { return MozSharedMap_Binding::Wrap(aCx, this, aGivenProto); }
--- a/dom/script/ScriptLoader.cpp +++ b/dom/script/ScriptLoader.cpp @@ -2750,17 +2750,18 @@ void ScriptLoader::MaybeTriggerBytecodeE return; } // Create a new runnable dedicated to encoding the content of the bytecode of // all enqueued scripts when the document is idle. In case of failure, we // give-up on encoding the bytecode. nsCOMPtr<nsIRunnable> encoder = NewRunnableMethod( "ScriptLoader::EncodeBytecode", this, &ScriptLoader::EncodeBytecode); - if (NS_FAILED(NS_IdleDispatchToCurrentThread(encoder.forget()))) { + if (NS_FAILED(NS_DispatchToCurrentThreadQueue(encoder.forget(), + EventQueuePriority::Idle))) { GiveUpBytecodeEncoding(); return; } LOG(("ScriptLoader (%p): Schedule bytecode encoding.", this)); } void ScriptLoader::EncodeBytecode() {
--- a/editor/spellchecker/EditorSpellCheck.cpp +++ b/editor/spellchecker/EditorSpellCheck.cpp @@ -183,17 +183,18 @@ class ContentPrefInitializerRunnable fin }; NS_IMETHODIMP DictionaryFetcher::Fetch(nsIEditor* aEditor) { NS_ENSURE_ARG_POINTER(aEditor); nsCOMPtr<nsIRunnable> runnable = new ContentPrefInitializerRunnable(aEditor, this); - NS_IdleDispatchToCurrentThread(runnable.forget(), 1000); + NS_DispatchToCurrentThreadQueue(runnable.forget(), 1000, + EventQueuePriority::Idle); return NS_OK; } /** * Stores the current dictionary for aEditor's document URL. */ static nsresult StoreCurrentDictionary(EditorBase* aEditorBase,
--- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp +++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp @@ -450,17 +450,18 @@ class mozInlineSpellResume : public Runn mozInlineSpellResume(UniquePtr<mozInlineSpellStatus>&& aStatus, uint32_t aDisabledAsyncToken) : Runnable("mozInlineSpellResume"), mDisabledAsyncToken(aDisabledAsyncToken), mStatus(std::move(aStatus)) {} nsresult Post() { nsCOMPtr<nsIRunnable> runnable(this); - return NS_IdleDispatchToCurrentThread(runnable.forget(), 1000); + return NS_DispatchToCurrentThreadQueue(runnable.forget(), 1000, + EventQueuePriority::Idle); } NS_IMETHOD Run() override { // Discard the resumption if the spell checker was disabled after the // resumption was scheduled. if (mDisabledAsyncToken == mStatus->mSpellChecker->mDisabledAsyncToken) { mStatus->mSpellChecker->ResumeCheck(std::move(mStatus)); }
--- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -396,17 +396,17 @@ void gfxPlatformFontList::InitOtherFamil // (This is used so we can reliably run reftests that depend on localized // font-family names being available.) if (aDeferOtherFamilyNamesLoading && Preferences::GetUint(FONT_LOADER_DELAY_PREF) > 0) { if (!mPendingOtherFamilyNameTask) { RefPtr<mozilla::CancelableRunnable> task = new InitOtherFamilyNamesRunnable(); mPendingOtherFamilyNameTask = task; - NS_IdleDispatchToMainThread(task.forget()); + NS_DispatchToMainThreadQueue(task.forget(), EventQueuePriority::Idle); } } else { InitOtherFamilyNamesInternal(false); } } // time limit for loading facename lists (ms) #define NAMELIST_TIMEOUT 200
--- a/intl/strres/nsStringBundle.cpp +++ b/intl/strres/nsStringBundle.cpp @@ -312,19 +312,20 @@ template <typename T, typename... Args> nsStringBundle::nsStringBundle(const char* aURLSpec) : nsStringBundleBase(aURLSpec) {} nsStringBundle::~nsStringBundle() {} NS_IMETHODIMP nsStringBundleBase::AsyncPreload() { - return NS_IdleDispatchToCurrentThread( + return NS_DispatchToCurrentThreadQueue( NewIdleRunnableMethod("nsStringBundleBase::LoadProperties", this, - &nsStringBundleBase::LoadProperties)); + &nsStringBundleBase::LoadProperties), + EventQueuePriority::Idle); } size_t nsStringBundle::SizeOfIncludingThis( mozilla::MallocSizeOf aMallocSizeOf) const { size_t n = 0; if (mProps) { n += mProps->SizeOfIncludingThis(aMallocSizeOf); }
--- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -151,17 +151,18 @@ class AsyncFreeSnowWhite : public Runnab } else { mActive = false; } return NS_OK; } nsresult Dispatch() { nsCOMPtr<nsIRunnable> self(this); - return NS_IdleDispatchToCurrentThread(self.forget(), 500); + return NS_DispatchToCurrentThreadQueue(self.forget(), 500, + EventQueuePriority::Idle); } void Start(bool aContinuation = false, bool aPurge = false) { if (mContinuation) { mContinuation = aContinuation; } mPurge = aPurge; if (!mActive && NS_SUCCEEDED(Dispatch())) {
--- a/layout/base/nsRefreshDriver.cpp +++ b/layout/base/nsRefreshDriver.cpp @@ -2001,18 +2001,19 @@ void nsRefreshDriver::Tick(VsyncId aId, gfxPrefs::AlwaysPaint()) { ScheduleViewManagerFlush(); } if (dispatchRunnablesAfterTick && sPendingIdleRunnables) { AutoTArray<RunnableWithDelay, 8>* runnables = sPendingIdleRunnables; sPendingIdleRunnables = nullptr; for (RunnableWithDelay& runnableWithDelay : *runnables) { - NS_IdleDispatchToCurrentThread(runnableWithDelay.mRunnable.forget(), - runnableWithDelay.mDelay); + NS_DispatchToCurrentThreadQueue(runnableWithDelay.mRunnable.forget(), + runnableWithDelay.mDelay, + EventQueuePriority::Idle); } delete runnables; } } void nsRefreshDriver::BeginRefreshingImages(RequestTable& aEntries, mozilla::TimeStamp aDesired) { for (auto iter = aEntries.Iter(); !iter.Done(); iter.Next()) {
--- a/toolkit/components/antitracking/AntiTrackingCommon.cpp +++ b/toolkit/components/antitracking/AntiTrackingCommon.cpp @@ -282,17 +282,17 @@ void ReportBlockingToConsole(nsPIDOMWind uint32_t lineNumber = 0, columnNumber = 0; JSContext* cx = nsContentUtils::GetCurrentJSContext(); if (cx) { nsJSUtils::GetCallingLocation(cx, sourceLine, &lineNumber, &columnNumber); } nsCOMPtr<nsIURI> uri(aURI); - nsresult rv = NS_IdleDispatchToCurrentThread( + nsresult rv = NS_DispatchToCurrentThreadQueue( NS_NewRunnableFunction( "ReportBlockingToConsoleDelayed", [doc, sourceLine, lineNumber, columnNumber, uri, aRejectedReason]() { const char* message = nullptr; nsAutoCString category; switch (aRejectedReason) { case nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION: message = "CookieBlockedByPermission"; @@ -333,17 +333,17 @@ void ReportBlockingToConsole(nsPIDOMWind const char16_t* params[] = {spec.get()}; nsContentUtils::ReportToConsole( nsIScriptError::warningFlag, category, doc, nsContentUtils::eNECKO_PROPERTIES, message, params, ArrayLength(params), nullptr, sourceLine, lineNumber, columnNumber); }), - kMaxConsoleOutputDelayMs); + kMaxConsoleOutputDelayMs, EventQueuePriority::Idle); if (NS_WARN_IF(NS_FAILED(rv))) { return; } } void ReportUnblockingToConsole( nsPIDOMWindowInner* aWindow, const nsAString& aTrackingOrigin, const nsAString& aGrantedOrigin, @@ -369,17 +369,17 @@ void ReportUnblockingToConsole( nsAutoString sourceLine; uint32_t lineNumber = 0, columnNumber = 0; JSContext* cx = nsContentUtils::GetCurrentJSContext(); if (cx) { nsJSUtils::GetCallingLocation(cx, sourceLine, &lineNumber, &columnNumber); } - nsresult rv = NS_IdleDispatchToCurrentThread( + nsresult rv = NS_DispatchToCurrentThreadQueue( NS_NewRunnableFunction( "ReportUnblockingToConsoleDelayed", [doc, principal, trackingOrigin, grantedOrigin, sourceLine, lineNumber, columnNumber, aReason]() { nsAutoString origin; nsresult rv = nsContentUtils::GetUTFOrigin(principal, origin); if (NS_WARN_IF(NS_FAILED(rv))) { return; @@ -417,17 +417,17 @@ void ReportUnblockingToConsole( } else { nsContentUtils::ReportToConsole( nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Content Blocking"), doc, nsContentUtils::eNECKO_PROPERTIES, messageWithDifferentOrigin, params, 3, nullptr, sourceLine, lineNumber, columnNumber); } }), - kMaxConsoleOutputDelayMs); + kMaxConsoleOutputDelayMs, EventQueuePriority::Idle); if (NS_WARN_IF(NS_FAILED(rv))) { return; } } already_AddRefed<nsPIDOMWindowOuter> GetTopWindow(nsPIDOMWindowInner* aWindow) { Document* document = aWindow->GetExtantDoc(); if (!document) {
--- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -2075,21 +2075,21 @@ void nsBaseWidget::UnregisterPluginWindo } MOZ_ASSERT(sPluginWidgetList); sPluginWidgetList->Remove(id); #endif } nsresult nsBaseWidget::AsyncEnableDragDrop(bool aEnable) { RefPtr<nsBaseWidget> kungFuDeathGrip = this; - return NS_IdleDispatchToCurrentThread( + return NS_DispatchToCurrentThreadQueue( NS_NewRunnableFunction( "AsyncEnableDragDropFn", [this, aEnable, kungFuDeathGrip]() { EnableDragDrop(aEnable); }), - kAsyncDragDropTimeout); + kAsyncDragDropTimeout, EventQueuePriority::Idle); } // static nsIWidget* nsIWidget::LookupRegisteredPluginWindow(uintptr_t aWindowID) { #if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK) MOZ_ASSERT_UNREACHABLE( "nsBaseWidget::LookupRegisteredPluginWindow " "not implemented!");
--- a/xpcom/base/CycleCollectedJSContext.cpp +++ b/xpcom/base/CycleCollectedJSContext.cpp @@ -422,17 +422,17 @@ void CycleCollectedJSContext::IsIdleGCTa return NS_OK; } nsresult Cancel() override { return NS_OK; } }; if (Runtime()->IsIdleGCTaskNeeded()) { nsCOMPtr<nsIRunnable> gc_task = new IdleTimeGCTaskRunnable(); - NS_IdleDispatchToCurrentThread(gc_task.forget()); + NS_DispatchToCurrentThreadQueue(gc_task.forget(), EventQueuePriority::Idle); Runtime()->SetPendingIdleGCTask(); } } uint32_t CycleCollectedJSContext::RecursionDepth() const { return mOwningThread->RecursionDepth(); }
--- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -1321,17 +1321,18 @@ void CycleCollectedJSRuntime::FinalizeDe mFinalizeRunnable = new IncrementalFinalizeRunnable(this, mDeferredFinalizerTable); // Everything should be gone now. MOZ_ASSERT(mDeferredFinalizerTable.Count() == 0); if (aType == CycleCollectedJSContext::FinalizeIncrementally) { - NS_IdleDispatchToCurrentThread(do_AddRef(mFinalizeRunnable), 2500); + NS_DispatchToCurrentThreadQueue(do_AddRef(mFinalizeRunnable), 2500, + EventQueuePriority::Idle); } else { mFinalizeRunnable->ReleaseNow(false); MOZ_ASSERT(!mFinalizeRunnable); } } const char* CycleCollectedJSRuntime::OOMStateToString( const OOMState aOomState) const {
--- a/xpcom/base/MemoryTelemetry.cpp +++ b/xpcom/base/MemoryTelemetry.cpp @@ -520,19 +520,21 @@ nsresult MemoryTelemetry::Observe(nsISup auto now = TimeStamp::Now(); if (!mLastPoll.IsNull() && (now - mLastPoll).ToMilliseconds() < kTelemetryInterval) { return NS_OK; } mLastPoll = now; - NS_IdleDispatchToCurrentThread(NewRunnableMethod<std::function<void()>>( - "MemoryTelemetry::GatherReports", this, &MemoryTelemetry::GatherReports, - nullptr)); + NS_DispatchToCurrentThreadQueue( + NewRunnableMethod<std::function<void()>>( + "MemoryTelemetry::GatherReports", this, + &MemoryTelemetry::GatherReports, nullptr), + EventQueuePriority::Idle); } else if (strcmp(aTopic, "content-child-shutdown") == 0) { if (nsCOMPtr<nsITelemetry> telemetry = do_GetService("@mozilla.org/base/telemetry;1")) { telemetry->FlushBatchedChildTelemetry(); } } return NS_OK; }
--- a/xpcom/tests/gtest/TestEventPriorities.cpp +++ b/xpcom/tests/gtest/TestEventPriorities.cpp @@ -50,19 +50,19 @@ NS_IMPL_ISUPPORTS_INHERITED(TestEvent, R TEST(EventPriorities, IdleAfterNormal) { int normalRan = 0, idleRan = 0; RefPtr<TestEvent> evNormal = new TestEvent(&normalRan, [&] { ASSERT_EQ(idleRan, 0); }); RefPtr<TestEvent> evIdle = new TestEvent(&idleRan, [&] { ASSERT_EQ(normalRan, 3); }); - NS_IdleDispatchToCurrentThread(do_AddRef(evIdle)); - NS_IdleDispatchToCurrentThread(do_AddRef(evIdle)); - NS_IdleDispatchToCurrentThread(do_AddRef(evIdle)); + NS_DispatchToCurrentThreadQueue(do_AddRef(evIdle), EventQueuePriority::Idle); + NS_DispatchToCurrentThreadQueue(do_AddRef(evIdle), EventQueuePriority::Idle); + NS_DispatchToCurrentThreadQueue(do_AddRef(evIdle), EventQueuePriority::Idle); NS_DispatchToMainThread(evNormal); NS_DispatchToMainThread(evNormal); NS_DispatchToMainThread(evNormal); MOZ_ALWAYS_TRUE( SpinEventLoopUntil([&]() { return normalRan == 3 && idleRan == 3; })); }
--- a/xpcom/tests/gtest/TestThreadUtils.cpp +++ b/xpcom/tests/gtest/TestThreadUtils.cpp @@ -602,23 +602,23 @@ class IdleObject final { NewRunnableMethod("IdleObject::Method3", this, &IdleObject::Method3)); } void Method3() { CheckExecutedMethods("Method3", 3); NS_NewTimerWithFuncCallback(getter_AddRefs(mTimer), Method4, this, 10, nsITimer::TYPE_ONE_SHOT, "IdleObject::Method3"); - NS_IdleDispatchToCurrentThread( + NS_DispatchToCurrentThreadQueue( NewIdleRunnableMethodWithTimer("IdleObject::Method5", this, &IdleObject::Method5), - 50); - NS_IdleDispatchToCurrentThread( + 50, EventQueuePriority::Idle); + NS_DispatchToCurrentThreadQueue( NewRunnableMethod("IdleObject::Method6", this, &IdleObject::Method6), - 100); + 100, EventQueuePriority::Idle); PR_Sleep(PR_MillisecondsToInterval(200)); mRunnableExecuted[3] = true; mSetIdleDeadlineCalled = false; } static void Method4(nsITimer* aTimer, void* aClosure) { RefPtr<IdleObject> self = static_cast<IdleObject*>(aClosure); @@ -659,33 +659,43 @@ TEST(ThreadUtils, IdleRunnableMethod) { RefPtr<IdleObject> idle = new IdleObject(); RefPtr<IdleObjectWithoutSetDeadline> idleNoSetDeadline = new IdleObjectWithoutSetDeadline(); RefPtr<IdleObjectInheritedSetDeadline> idleInheritedSetDeadline = new IdleObjectInheritedSetDeadline(); NS_DispatchToCurrentThread( NewRunnableMethod("IdleObject::Method0", idle, &IdleObject::Method0)); - NS_IdleDispatchToCurrentThread(NewIdleRunnableMethod( - "IdleObject::Method1", idle, &IdleObject::Method1)); - NS_IdleDispatchToCurrentThread( + NS_DispatchToCurrentThreadQueue( + NewIdleRunnableMethod("IdleObject::Method1", idle, + &IdleObject::Method1), + EventQueuePriority::Idle); + NS_DispatchToCurrentThreadQueue( NewIdleRunnableMethodWithTimer("IdleObject::Method2", idle, &IdleObject::Method2), - 60000); - NS_IdleDispatchToCurrentThread(NewIdleRunnableMethod( - "IdleObject::Method7", idle, &IdleObject::Method7)); - NS_IdleDispatchToCurrentThread(NewIdleRunnableMethod<const char*, uint32_t>( - "IdleObject::CheckExecutedMethods", idle, - &IdleObject::CheckExecutedMethods, "final", 8)); - NS_IdleDispatchToCurrentThread(NewIdleRunnableMethod( - "IdleObjectWithoutSetDeadline::Method", idleNoSetDeadline, - &IdleObjectWithoutSetDeadline::Method)); - NS_IdleDispatchToCurrentThread(NewIdleRunnableMethod( - "IdleObjectInheritedSetDeadline::Method", idleInheritedSetDeadline, - &IdleObjectInheritedSetDeadline::Method)); + 60000, EventQueuePriority::Idle); + NS_DispatchToCurrentThreadQueue( + NewIdleRunnableMethod("IdleObject::Method7", idle, + &IdleObject::Method7), + EventQueuePriority::Idle); + NS_DispatchToCurrentThreadQueue( + NewIdleRunnableMethod<const char*, uint32_t>( + "IdleObject::CheckExecutedMethods", idle, + &IdleObject::CheckExecutedMethods, "final", 8), + EventQueuePriority::Idle); + NS_DispatchToCurrentThreadQueue( + NewIdleRunnableMethod("IdleObjectWithoutSetDeadline::Method", + idleNoSetDeadline, + &IdleObjectWithoutSetDeadline::Method), + EventQueuePriority::Idle); + NS_DispatchToCurrentThreadQueue( + NewIdleRunnableMethod("IdleObjectInheritedSetDeadline::Method", + idleInheritedSetDeadline, + &IdleObjectInheritedSetDeadline::Method), + EventQueuePriority::Idle); NS_ProcessPendingEvents(nullptr); ASSERT_TRUE(idleNoSetDeadline->mRunnableExecuted); ASSERT_TRUE(idleInheritedSetDeadline->mRunnableExecuted); ASSERT_TRUE(idleInheritedSetDeadline->mSetDeadlineCalled); } }
--- a/xpcom/threads/AbstractEventQueue.h +++ b/xpcom/threads/AbstractEventQueue.h @@ -14,16 +14,17 @@ class nsIRunnable; namespace mozilla { enum class EventQueuePriority { High, Input, Normal, + DeferredTimers, Idle, Count }; // AbstractEventQueue is an abstract base class for all our unsynchronized event // queue implementations: // - EventQueue: A queue of runnables. Used for non-main threads.
--- a/xpcom/threads/IdleTaskRunner.cpp +++ b/xpcom/threads/IdleTaskRunner.cpp @@ -80,17 +80,17 @@ static void TimedOut(nsITimer* aTimer, v void IdleTaskRunner::SetDeadline(mozilla::TimeStamp aDeadline) { mDeadline = aDeadline; }; void IdleTaskRunner::SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) { MOZ_ASSERT(NS_IsMainThread()); // aTarget is always the main thread event target provided from - // NS_IdleDispatchToCurrentThread(). We ignore aTarget here to ensure that + // NS_DispatchToCurrentThreadQueue(). We ignore aTarget here to ensure that // CollectorRunner always run specifically on SystemGroup::EventTargetFor( // TaskCategory::GarbageCollection) of the main thread. SetTimerInternal(aDelay); } nsresult IdleTaskRunner::Cancel() { CancelTimer(); mTimer = nullptr; @@ -122,17 +122,18 @@ void IdleTaskRunner::Schedule(bool aAllo nsRefreshDriver::DispatchIdleRunnableAfterTick(this, mDelay); // Ensure we get called at some point, even if RefreshDriver is stopped. SetTimerInternal(mDelay); } else { // RefreshDriver doesn't seem to be running. if (aAllowIdleDispatch) { nsCOMPtr<nsIRunnable> runnable = this; SetTimerInternal(mDelay); - NS_IdleDispatchToCurrentThread(runnable.forget()); + NS_DispatchToCurrentThreadQueue(runnable.forget(), + EventQueuePriority::Idle); } else { if (!mScheduleTimer) { nsIEventTarget* target = nullptr; if (TaskCategory::Count != mTaskCategory) { target = SystemGroup::EventTargetFor(mTaskCategory); } mScheduleTimer = NS_NewTimer(target); if (!mScheduleTimer) {
--- a/xpcom/threads/LazyIdleThread.cpp +++ b/xpcom/threads/LazyIdleThread.cpp @@ -481,17 +481,18 @@ NS_IMETHODIMP LazyIdleThread::HasPendingHighPriorityEvents(bool* aHasPendingEvents) { // This is only supposed to be called from the thread itself so it's not // implemented here. MOZ_ASSERT_UNREACHABLE("Shouldn't ever call this!"); return NS_ERROR_UNEXPECTED; } NS_IMETHODIMP -LazyIdleThread::IdleDispatch(already_AddRefed<nsIRunnable> aEvent) { +LazyIdleThread::DispatchToQueue(already_AddRefed<nsIRunnable> aEvent, + EventQueuePriority aQueue) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP LazyIdleThread::ProcessNextEvent(bool aMayWait, bool* aEventWasProcessed) { // This is only supposed to be called from the thread itself so it's not // implemented here. MOZ_ASSERT_UNREACHABLE("Shouldn't ever call this!");
--- a/xpcom/threads/MainThreadQueue.h +++ b/xpcom/threads/MainThreadQueue.h @@ -21,16 +21,17 @@ inline already_AddRefed<nsThread> Create nsIIdlePeriod* aIdlePeriod, SynchronizedQueueT** aSynchronizedQueue = nullptr) { using MainThreadQueueT = PrioritizedEventQueue<InnerQueueT>; auto queue = MakeUnique<MainThreadQueueT>( MakeUnique<InnerQueueT>(EventQueuePriority::High), MakeUnique<InnerQueueT>(EventQueuePriority::Input), MakeUnique<InnerQueueT>(EventQueuePriority::Normal), + MakeUnique<InnerQueueT>(EventQueuePriority::DeferredTimers), MakeUnique<InnerQueueT>(EventQueuePriority::Idle), do_AddRef(aIdlePeriod)); MainThreadQueueT* prioritized = queue.get(); RefPtr<SynchronizedQueueT> synchronizedQueue = new SynchronizedQueueT(std::move(queue));
--- a/xpcom/threads/PrioritizedEventQueue.cpp +++ b/xpcom/threads/PrioritizedEventQueue.cpp @@ -11,21 +11,24 @@ #include "nsXPCOMPrivate.h" // for gXPCOMThreadsShutDown #include "InputEventStatistics.h" using namespace mozilla; template <class InnerQueueT> PrioritizedEventQueue<InnerQueueT>::PrioritizedEventQueue( UniquePtr<InnerQueueT> aHighQueue, UniquePtr<InnerQueueT> aInputQueue, - UniquePtr<InnerQueueT> aNormalQueue, UniquePtr<InnerQueueT> aIdleQueue, + UniquePtr<InnerQueueT> aNormalQueue, + UniquePtr<InnerQueueT> aDeferredTimersQueue, + UniquePtr<InnerQueueT> aIdleQueue, already_AddRefed<nsIIdlePeriod> aIdlePeriod) : mHighQueue(std::move(aHighQueue)), mInputQueue(std::move(aInputQueue)), mNormalQueue(std::move(aNormalQueue)), + mDeferredTimersQueue(std::move(aDeferredTimersQueue)), mIdleQueue(std::move(aIdleQueue)), mIdlePeriod(aIdlePeriod) { static_assert(IsBaseOf<AbstractEventQueue, InnerQueueT>::value, "InnerQueueT must be an AbstractEventQueue subclass"); } template <class InnerQueueT> void PrioritizedEventQueue<InnerQueueT>::PutEvent( @@ -45,16 +48,19 @@ void PrioritizedEventQueue<InnerQueueT>: mHighQueue->PutEvent(event.forget(), priority, aProofOfLock); break; case EventQueuePriority::Input: mInputQueue->PutEvent(event.forget(), priority, aProofOfLock); break; case EventQueuePriority::Normal: mNormalQueue->PutEvent(event.forget(), priority, aProofOfLock); break; + case EventQueuePriority::DeferredTimers: + mDeferredTimersQueue->PutEvent(event.forget(), priority, aProofOfLock); + break; case EventQueuePriority::Idle: mIdleQueue->PutEvent(event.forget(), priority, aProofOfLock); break; case EventQueuePriority::Count: MOZ_CRASH("EventQueuePriority::Count isn't a valid priority"); break; } } @@ -103,18 +109,16 @@ TimeStamp PrioritizedEventQueue<InnerQue return TimeStamp::Now(); } return idleDeadline; } template <class InnerQueueT> EventQueuePriority PrioritizedEventQueue<InnerQueueT>::SelectQueue( bool aUpdateState, const MutexAutoLock& aProofOfLock) { - bool highPending = !mHighQueue->IsEmpty(aProofOfLock); - bool normalPending = !mNormalQueue->IsEmpty(aProofOfLock); size_t inputCount = mInputQueue->Count(aProofOfLock); if (aUpdateState && mInputQueueState == STATE_ENABLED && mInputHandlingStartTime.IsNull() && inputCount > 0) { mInputHandlingStartTime = InputEventStatistics::Get().GetInputHandlingStartTime(inputCount); } @@ -126,42 +130,47 @@ EventQueuePriority PrioritizedEventQueue // INPUT: if inputCount > 0 && TimeStamp::Now() > mInputHandlingStartTime // NORMAL: if normalPending // // If we still don't have an event, then we take events from the queues // in the following order: // // HIGH // INPUT + // DEFERREDTIMERS: if GetIdleDeadline() // IDLE: if GetIdleDeadline() // // If we don't get an event in this pass, then we return null since no events // are ready. // This variable determines which queue we will take an event from. EventQueuePriority queue; + bool highPending = !mHighQueue->IsEmpty(aProofOfLock); if (mProcessHighPriorityQueue) { queue = EventQueuePriority::High; } else if (inputCount > 0 && (mInputQueueState == STATE_FLUSHING || (mInputQueueState == STATE_ENABLED && !mInputHandlingStartTime.IsNull() && TimeStamp::Now() > mInputHandlingStartTime))) { queue = EventQueuePriority::Input; - } else if (normalPending) { + } else if (!mNormalQueue->IsEmpty(aProofOfLock)) { MOZ_ASSERT(mInputQueueState != STATE_FLUSHING, - "Shouldn't consume normal event when flusing input events"); + "Shouldn't consume normal event when flushing input events"); queue = EventQueuePriority::Normal; } else if (highPending) { queue = EventQueuePriority::High; } else if (inputCount > 0 && mInputQueueState != STATE_SUSPEND) { MOZ_ASSERT( mInputQueueState != STATE_DISABLED, "Shouldn't consume input events when the input queue is disabled"); queue = EventQueuePriority::Input; + } else if (!mDeferredTimersQueue->IsEmpty(aProofOfLock)) { + // We may not actually return an idle event in this case. + queue = EventQueuePriority::DeferredTimers; } else { // We may not actually return an idle event in this case. queue = EventQueuePriority::Idle; } MOZ_ASSERT_IF( queue == EventQueuePriority::Input, mInputQueueState != STATE_DISABLED && mInputQueueState != STATE_SUSPEND); @@ -207,30 +216,36 @@ already_AddRefed<nsIRunnable> Prioritize } if (queue == EventQueuePriority::Normal) { nsCOMPtr<nsIRunnable> event = mNormalQueue->GetEvent(aPriority, aProofOfLock); return event.forget(); } - // If we get here, then all queues except idle are empty. - MOZ_ASSERT(queue == EventQueuePriority::Idle); + // If we get here, then all queues except deferredtimers and idle are empty. + MOZ_ASSERT(queue == EventQueuePriority::Idle || + queue == EventQueuePriority::DeferredTimers); - if (mIdleQueue->IsEmpty(aProofOfLock)) { + if (mIdleQueue->IsEmpty(aProofOfLock) && + mDeferredTimersQueue->IsEmpty(aProofOfLock)) { MOZ_ASSERT(!mHasPendingEventsPromisedIdleEvent); return nullptr; } TimeStamp idleDeadline = GetIdleDeadline(); if (!idleDeadline) { return nullptr; } - nsCOMPtr<nsIRunnable> event = mIdleQueue->GetEvent(aPriority, aProofOfLock); + nsCOMPtr<nsIRunnable> event = + mDeferredTimersQueue->GetEvent(aPriority, aProofOfLock); + if (!event) { + event = mIdleQueue->GetEvent(aPriority, aProofOfLock); + } if (event) { nsCOMPtr<nsIIdleRunnable> idleEvent = do_QueryInterface(event); if (idleEvent) { idleEvent->SetDeadline(idleDeadline); } #ifndef RELEASE_OR_BETA // Store the next idle deadline to be able to determine budget use @@ -245,16 +260,17 @@ already_AddRefed<nsIRunnable> Prioritize template <class InnerQueueT> bool PrioritizedEventQueue<InnerQueueT>::IsEmpty( const MutexAutoLock& aProofOfLock) { // Just check IsEmpty() on the sub-queues. Don't bother checking the idle // deadline since that only determines whether an idle event is ready or not. return mHighQueue->IsEmpty(aProofOfLock) && mInputQueue->IsEmpty(aProofOfLock) && mNormalQueue->IsEmpty(aProofOfLock) && + mDeferredTimersQueue->IsEmpty(aProofOfLock) && mIdleQueue->IsEmpty(aProofOfLock); } template <class InnerQueueT> bool PrioritizedEventQueue<InnerQueueT>::HasReadyEvent( const MutexAutoLock& aProofOfLock) { mHasPendingEventsPromisedIdleEvent = false; @@ -263,26 +279,29 @@ bool PrioritizedEventQueue<InnerQueueT>: if (queue == EventQueuePriority::High) { return mHighQueue->HasReadyEvent(aProofOfLock); } else if (queue == EventQueuePriority::Input) { return mInputQueue->HasReadyEvent(aProofOfLock); } else if (queue == EventQueuePriority::Normal) { return mNormalQueue->HasReadyEvent(aProofOfLock); } - MOZ_ASSERT(queue == EventQueuePriority::Idle); + MOZ_ASSERT(queue == EventQueuePriority::Idle || + queue == EventQueuePriority::DeferredTimers); // If we get here, then both the high and normal queues are empty. - if (mIdleQueue->IsEmpty(aProofOfLock)) { + if (mDeferredTimersQueue->IsEmpty(aProofOfLock) && + mIdleQueue->IsEmpty(aProofOfLock)) { return false; } TimeStamp idleDeadline = GetIdleDeadline(); - if (idleDeadline && mIdleQueue->HasReadyEvent(aProofOfLock)) { + if (idleDeadline && (mDeferredTimersQueue->HasReadyEvent(aProofOfLock) || + mIdleQueue->HasReadyEvent(aProofOfLock))) { mHasPendingEventsPromisedIdleEvent = true; return true; } return false; } template <class InnerQueueT>
--- a/xpcom/threads/PrioritizedEventQueue.h +++ b/xpcom/threads/PrioritizedEventQueue.h @@ -38,16 +38,17 @@ namespace mozilla { template <class InnerQueueT> class PrioritizedEventQueue final : public AbstractEventQueue { public: static const bool SupportsPrioritization = true; PrioritizedEventQueue(UniquePtr<InnerQueueT> aHighQueue, UniquePtr<InnerQueueT> aInputQueue, UniquePtr<InnerQueueT> aNormalQueue, + UniquePtr<InnerQueueT> aDeferredTimersQueue, UniquePtr<InnerQueueT> aIdleQueue, already_AddRefed<nsIIdlePeriod> aIdlePeriod); void PutEvent(already_AddRefed<nsIRunnable>&& aEvent, EventQueuePriority aPriority, const MutexAutoLock& aProofOfLock) final; already_AddRefed<nsIRunnable> GetEvent( EventQueuePriority* aPriority, const MutexAutoLock& aProofOfLock) final; @@ -79,16 +80,17 @@ class PrioritizedEventQueue final : publ size_t SizeOfExcludingThis( mozilla::MallocSizeOf aMallocSizeOf) const override { size_t n = 0; n += mHighQueue->SizeOfIncludingThis(aMallocSizeOf); n += mInputQueue->SizeOfIncludingThis(aMallocSizeOf); n += mNormalQueue->SizeOfIncludingThis(aMallocSizeOf); + n += mDeferredTimersQueue->SizeOfIncludingThis(aMallocSizeOf); n += mIdleQueue->SizeOfIncludingThis(aMallocSizeOf); if (mIdlePeriod) { n += aMallocSizeOf(mIdlePeriod); } return n; } @@ -98,16 +100,17 @@ class PrioritizedEventQueue final : publ const MutexAutoLock& aProofOfLock); // Returns a null TimeStamp if we're not in the idle period. mozilla::TimeStamp GetIdleDeadline(); UniquePtr<InnerQueueT> mHighQueue; UniquePtr<InnerQueueT> mInputQueue; UniquePtr<InnerQueueT> mNormalQueue; + UniquePtr<InnerQueueT> mDeferredTimersQueue; UniquePtr<InnerQueueT> mIdleQueue; // We need to drop the queue mutex when checking the idle deadline, so we keep // a pointer to it here. Mutex* mMutex = nullptr; #ifndef RELEASE_OR_BETA // Pointer to a place where the most recently computed idle deadline is
--- a/xpcom/threads/nsIThread.idl +++ b/xpcom/threads/nsIThread.idl @@ -5,20 +5,22 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsISerialEventTarget.idl" %{C++ #include "mozilla/AlreadyAddRefed.h" namespace mozilla { class TimeStamp; +enum class EventQueuePriority; } %} [ptr] native PRThread(PRThread); +native EventQueuePriority(mozilla::EventQueuePriority); native nsIEventTargetPtr(nsIEventTarget*); native nsISerialEventTargetPtr(nsISerialEventTarget*); native TimeStamp(mozilla::TimeStamp); /** * This interface provides a high-level abstraction for an operating system * thread. @@ -125,30 +127,35 @@ interface nsIThread : nsISerialEventTarg * Indicates that this method was erroneously called when this thread was * the current thread, that this thread was not created with a call to * nsIThreadManager::NewThread, or if this method was called more than once * on the thread object. */ void asyncShutdown(); /** - * Dispatch an event to the thread's idle queue. This function may be called - * from any thread, and it may be called re-entrantly. + * Dispatch an event to a specified queue for the thread. This function + * may be called from any thread, and it may be called re-entrantly. + * Most users should use the NS_Dispatch*() functions in nsThreadUtils instead + * of calling this directly. * * @param event * The alreadyAddRefed<> event to dispatch. * NOTE that the event will be leaked if it fails to dispatch. + * @param queue + * Which event priority queue this should be added to * * @throws NS_ERROR_INVALID_ARG * Indicates that event is null. * @throws NS_ERROR_UNEXPECTED * Indicates that the thread is shutting down and has finished processing * events, so this event would never run and has not been dispatched. */ - [noscript] void idleDispatch(in alreadyAddRefed_nsIRunnable event); + [noscript] void dispatchToQueue(in alreadyAddRefed_nsIRunnable event, + in EventQueuePriority queue); /** * Use this attribute to dispatch runnables to the thread. Eventually, the * eventTarget attribute will be the only way to dispatch events to a * thread--nsIThread will no longer inherit from nsIEventTarget. */ readonly attribute nsIEventTarget eventTarget;
--- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -895,24 +895,25 @@ nsThread::HasPendingHighPriorityEvents(b return NS_ERROR_NOT_SAME_THREAD; } *aResult = mEvents->HasPendingHighPriorityEvents(); return NS_OK; } NS_IMETHODIMP -nsThread::IdleDispatch(already_AddRefed<nsIRunnable> aEvent) { +nsThread::DispatchToQueue(already_AddRefed<nsIRunnable> aEvent, + EventQueuePriority aQueue) { nsCOMPtr<nsIRunnable> event = aEvent; if (NS_WARN_IF(!event)) { return NS_ERROR_INVALID_ARG; } - if (!mEvents->PutEvent(event.forget(), EventQueuePriority::Idle)) { + if (!mEvents->PutEvent(event.forget(), aQueue)) { NS_WARNING( "An idle event was posted to a thread that will never run it " "(rejected)"); return NS_ERROR_UNEXPECTED; } return NS_OK; }
--- a/xpcom/threads/nsThreadManager.cpp +++ b/xpcom/threads/nsThreadManager.cpp @@ -575,26 +575,28 @@ bool nsThreadManager::MainThreadHasPendi get().mMainThread->HasPendingHighPriorityEvents(&retVal); } return retVal; } NS_IMETHODIMP nsThreadManager::IdleDispatchToMainThread(nsIRunnable* aEvent, uint32_t aTimeout) { - // Note: C++ callers should instead use NS_IdleDispatchToThread or - // NS_IdleDispatchToCurrentThread. + // Note: C++ callers should instead use NS_DispatchToThreadQueue or + // NS_DispatchToCurrentThreadQueue. MOZ_ASSERT(NS_IsMainThread()); nsCOMPtr<nsIRunnable> event(aEvent); if (aTimeout) { - return NS_IdleDispatchToThread(event.forget(), aTimeout, mMainThread); + return NS_DispatchToThreadQueue(event.forget(), aTimeout, mMainThread, + EventQueuePriority::Idle); } - return NS_IdleDispatchToThread(event.forget(), mMainThread); + return NS_DispatchToThreadQueue(event.forget(), mMainThread, + EventQueuePriority::Idle); } namespace mozilla { PRThread* GetCurrentVirtualThread() { // We call GetCurrentVirtualThread very early in startup, before the TLS is // initialized. Make sure we don't assert in that case. if (gTlsCurrentVirtualThread.initialized()) {
--- a/xpcom/threads/nsThreadUtils.cpp +++ b/xpcom/threads/nsThreadUtils.cpp @@ -261,49 +261,51 @@ nsresult NS_DelayedDispatchToCurrentThre if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } #endif return thread->DelayedDispatch(event.forget(), aDelayMs); } -nsresult NS_IdleDispatchToThread(already_AddRefed<nsIRunnable>&& aEvent, - nsIThread* aThread) { +nsresult NS_DispatchToThreadQueue(already_AddRefed<nsIRunnable>&& aEvent, + nsIThread* aThread, + EventQueuePriority aQueue) { nsresult rv; nsCOMPtr<nsIRunnable> event(aEvent); NS_ENSURE_TRUE(event, NS_ERROR_INVALID_ARG); if (!aThread) { return NS_ERROR_UNEXPECTED; } // To keep us from leaking the runnable if dispatch method fails, // we grab the reference on failures and release it. nsIRunnable* temp = event.get(); - rv = aThread->IdleDispatch(event.forget()); + rv = aThread->DispatchToQueue(event.forget(), aQueue); if (NS_WARN_IF(NS_FAILED(rv))) { // Dispatch() leaked the reference to the event, but due to caller's // assumptions, we shouldn't leak here. And given we are on the same // thread as the dispatch target, it's mostly safe to do it here. NS_RELEASE(temp); } return rv; } -nsresult NS_IdleDispatchToCurrentThread( - already_AddRefed<nsIRunnable>&& aEvent) { - return NS_IdleDispatchToThread(std::move(aEvent), NS_GetCurrentThread()); +nsresult NS_DispatchToCurrentThreadQueue(already_AddRefed<nsIRunnable>&& aEvent, + EventQueuePriority aQueue) { + return NS_DispatchToThreadQueue(std::move(aEvent), NS_GetCurrentThread(), + aQueue); } -extern nsresult NS_IdleDispatchToMainThread( - already_AddRefed<nsIRunnable>&& aEvent) { +extern nsresult NS_DispatchToMainThreadQueue( + already_AddRefed<nsIRunnable>&& aEvent, EventQueuePriority aQueue) { nsCOMPtr<nsIThread> mainThread; nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread)); if (NS_SUCCEEDED(rv)) { - return NS_IdleDispatchToThread(std::move(aEvent), mainThread); + return NS_DispatchToThreadQueue(std::move(aEvent), mainThread, aQueue); } return rv; } class IdleRunnableWrapper final : public IdleRunnable { public: explicit IdleRunnableWrapper(already_AddRefed<nsIRunnable>&& aEvent) : mRunnable(std::move(aEvent)) {} @@ -354,43 +356,47 @@ class IdleRunnableWrapper final : public mTimer->Cancel(); } } nsCOMPtr<nsITimer> mTimer; nsCOMPtr<nsIRunnable> mRunnable; }; -extern nsresult NS_IdleDispatchToThread(already_AddRefed<nsIRunnable>&& aEvent, - uint32_t aTimeout, nsIThread* aThread) { +extern nsresult NS_DispatchToThreadQueue(already_AddRefed<nsIRunnable>&& aEvent, + uint32_t aTimeout, nsIThread* aThread, + EventQueuePriority aQueue) { nsCOMPtr<nsIRunnable> event(std::move(aEvent)); NS_ENSURE_TRUE(event, NS_ERROR_INVALID_ARG); + MOZ_ASSERT(aQueue == EventQueuePriority::Idle || + aQueue == EventQueuePriority::DeferredTimers); // XXX Using current thread for now as the nsIEventTarget. nsIEventTarget* target = mozilla::GetCurrentThreadEventTarget(); if (!target) { return NS_ERROR_UNEXPECTED; } nsCOMPtr<nsIIdleRunnable> idleEvent = do_QueryInterface(event); if (!idleEvent) { idleEvent = new IdleRunnableWrapper(event.forget()); event = do_QueryInterface(idleEvent); MOZ_DIAGNOSTIC_ASSERT(event); } idleEvent->SetTimer(aTimeout, target); - return NS_IdleDispatchToThread(event.forget(), aThread); + return NS_DispatchToThreadQueue(event.forget(), aThread, aQueue); } -extern nsresult NS_IdleDispatchToCurrentThread( - already_AddRefed<nsIRunnable>&& aEvent, uint32_t aTimeout) { - return NS_IdleDispatchToThread(std::move(aEvent), aTimeout, - NS_GetCurrentThread()); +extern nsresult NS_DispatchToCurrentThreadQueue( + already_AddRefed<nsIRunnable>&& aEvent, uint32_t aTimeout, + EventQueuePriority aQueue) { + return NS_DispatchToThreadQueue(std::move(aEvent), aTimeout, + NS_GetCurrentThread(), aQueue); } #ifndef XPCOM_GLUE_AVOID_NSPR nsresult NS_ProcessPendingEvents(nsIThread* aThread, PRIntervalTime aTimeout) { nsresult rv = NS_OK; # ifdef MOZILLA_INTERNAL_API if (!aThread) {
--- a/xpcom/threads/nsThreadUtils.h +++ b/xpcom/threads/nsThreadUtils.h @@ -17,16 +17,17 @@ #include "nsIRunnable.h" #include "nsIThreadManager.h" #include "nsITimer.h" #include "nsIThread.h" #include "nsString.h" #include "nsCOMPtr.h" #include "nsAutoPtr.h" #include "xpcpublic.h" +#include "mozilla/AbstractEventQueue.h" #include "mozilla/Atomics.h" #include "mozilla/Likely.h" #include "mozilla/Maybe.h" #include "mozilla/Move.h" #include "mozilla/TimeStamp.h" #include "mozilla/Tuple.h" #include "mozilla/TypeTraits.h" @@ -108,102 +109,114 @@ extern nsresult NS_DispatchToMainThread( extern nsresult NS_DispatchToMainThread( already_AddRefed<nsIRunnable>&& aEvent, uint32_t aDispatchFlags = NS_DISPATCH_NORMAL); extern nsresult NS_DelayedDispatchToCurrentThread( already_AddRefed<nsIRunnable>&& aEvent, uint32_t aDelayMs); /** - * Dispatch the given event to the idle queue of the current thread. + * Dispatch the given event to the specified queue of the current thread. * - * @param aEvent - * The event to dispatch. + * @param aEvent The event to dispatch. + * @param aQueue The event queue for the thread to use * * @returns NS_ERROR_INVALID_ARG * If event is null. * @returns NS_ERROR_UNEXPECTED * If the thread is shutting down. */ -extern nsresult NS_IdleDispatchToCurrentThread( - already_AddRefed<nsIRunnable>&& aEvent); +extern nsresult NS_DispatchToCurrentThreadQueue( + already_AddRefed<nsIRunnable>&& aEvent, mozilla::EventQueuePriority aQueue); /** - * Dispatch the given event to the idle queue of the main thread. + * Dispatch the given event to the specified queue of the main thread. * * @param aEvent The event to dispatch. + * @param aQueue The event queue for the thread to use * * @returns NS_ERROR_INVALID_ARG * If event is null. * @returns NS_ERROR_UNEXPECTED * If the thread is shutting down. */ -extern nsresult NS_IdleDispatchToMainThread( - already_AddRefed<nsIRunnable>&& aEvent); +extern nsresult NS_DispatchToMainThreadQueue( + already_AddRefed<nsIRunnable>&& aEvent, mozilla::EventQueuePriority aQueue); /** - * Dispatch the given event to the idle queue of the current thread. + * Dispatch the given event to an idle queue of the current thread. * * @param aEvent The event to dispatch. If the event implements * nsIIdleRunnable, it will receive a call on * nsIIdleRunnable::SetTimer when dispatched, with the value of * aTimeout. * * @param aTimeout The time in milliseconds until the event should be - * moved from the idle queue to the regular queue, if it hasn't been + * moved from an idle queue to the regular queue, if it hasn't been * executed. If aEvent is also an nsIIdleRunnable, it is expected * that it should handle the timeout itself, after a call to * nsIIdleRunnable::SetTimer. * + * @param aQueue + * The event queue for the thread to use. Must be an idle queue + * (Idle or DeferredTimers) + * * @returns NS_ERROR_INVALID_ARG * If event is null. * @returns NS_ERROR_UNEXPECTED * If the thread is shutting down. */ -extern nsresult NS_IdleDispatchToCurrentThread( - already_AddRefed<nsIRunnable>&& aEvent, uint32_t aTimeout); +extern nsresult NS_DispatchToCurrentThreadQueue( + already_AddRefed<nsIRunnable>&& aEvent, uint32_t aTimeout, + mozilla::EventQueuePriority aQueue); /** - * Dispatch the given event to the idle queue of a thread. + * Dispatch the given event to a queue of a thread. * * @param aEvent The event to dispatch. - * * @param aThread The target thread for the dispatch. + * @param aQueue The event queue for the thread to use. * * @returns NS_ERROR_INVALID_ARG * If event is null. * @returns NS_ERROR_UNEXPECTED * If the thread is shutting down. */ -extern nsresult NS_IdleDispatchToThread(already_AddRefed<nsIRunnable>&& aEvent, - nsIThread* aThread); +extern nsresult NS_DispatchToThreadQueue(already_AddRefed<nsIRunnable>&& aEvent, + nsIThread* aThread, + mozilla::EventQueuePriority aQueue); /** - * Dispatch the given event to the idle queue of a thread. + * Dispatch the given event to an idle queue of a thread. * * @param aEvent The event to dispatch. If the event implements * nsIIdleRunnable, it will receive a call on * nsIIdleRunnable::SetTimer when dispatched, with the value of * aTimeout. * * @param aTimeout The time in milliseconds until the event should be - * moved from the idle queue to the regular queue, if it hasn't been + * moved from an idle queue to the regular queue, if it hasn't been * executed. If aEvent is also an nsIIdleRunnable, it is expected * that it should handle the timeout itself, after a call to * nsIIdleRunnable::SetTimer. * * @param aThread The target thread for the dispatch. * + * @param aQueue + * The event queue for the thread to use. Must be an idle queue + * (Idle or DeferredTimers) + * * @returns NS_ERROR_INVALID_ARG * If event is null. * @returns NS_ERROR_UNEXPECTED * If the thread is shutting down. */ -extern nsresult NS_IdleDispatchToThread(already_AddRefed<nsIRunnable>&& aEvent, - uint32_t aTimeout, nsIThread* aThread); +extern nsresult NS_DispatchToThreadQueue(already_AddRefed<nsIRunnable>&& aEvent, + uint32_t aTimeout, nsIThread* aThread, + mozilla::EventQueuePriority aQueue); #ifndef XPCOM_GLUE_AVOID_NSPR /** * Process all pending events for the given thread before returning. This * method simply calls ProcessNextEvent on the thread while HasPendingEvents * continues to return true and the time spent in NS_ProcessPendingEvents * does not exceed the given timeout value. *