From f78d18d8272f5a18b6f4e9f5ee09a19cd2f52904 Mon Sep 17 00:00:00 2001 From: Brindusan Cristian Date: Tue, 6 Apr 2021 17:41:19 +0300 Subject: [PATCH] Backed out 8 changesets (bug 1695580) for causing build bustages on DataMutex.h. CLOSED TREE Backed out changeset ec0b0fcc8d88 (bug 1695580) Backed out changeset 982a46056fcb (bug 1695580) Backed out changeset e38e8b90f119 (bug 1695580) Backed out changeset 6fdd154aa151 (bug 1695580) Backed out changeset d04f7a7ec375 (bug 1695580) Backed out changeset 2103cd9e58b7 (bug 1695580) Backed out changeset de9a7dd7fc79 (bug 1695580) Backed out changeset ae16f09be41b (bug 1695580) --- dom/media/mediacontrol/MediaController.h | 1 - modules/libpref/init/all.js | 2 +- netwerk/base/nsStreamTransportService.cpp | 51 +-------- netwerk/base/nsStreamTransportService.h | 15 +-- .../protocol/websocket/WebSocketChannel.cpp | 2 - testing/mochitest/mochitest_options.py | 1 + xpcom/build/XPCOMInit.cpp | 1 - xpcom/tests/gtest/TestDelayedRunnable.cpp | 104 ------------------ xpcom/tests/gtest/moz.build | 1 - xpcom/threads/AbstractThread.cpp | 31 +----- xpcom/threads/DelayedRunnable.cpp | 73 ------------ xpcom/threads/DelayedRunnable.h | 50 --------- xpcom/threads/InputTaskManager.h | 1 - xpcom/threads/TaskQueue.cpp | 52 +-------- xpcom/threads/TaskQueue.h | 37 +------ xpcom/threads/ThreadEventTarget.cpp | 28 +---- xpcom/threads/ThreadEventTarget.h | 20 +--- xpcom/threads/moz.build | 3 - xpcom/threads/nsIDelayedRunnableObserver.h | 50 --------- xpcom/threads/nsThread.cpp | 16 --- xpcom/threads/nsThread.h | 7 -- xpcom/threads/nsThreadManager.cpp | 55 +++------ xpcom/threads/nsThreadManager.h | 8 -- xpcom/threads/nsThreadUtils.cpp | 47 ++++++++ xpcom/threads/nsThreadUtils.h | 22 ++++ 25 files changed, 102 insertions(+), 576 deletions(-) delete mode 100644 xpcom/tests/gtest/TestDelayedRunnable.cpp delete mode 100644 xpcom/threads/DelayedRunnable.cpp delete mode 100644 xpcom/threads/DelayedRunnable.h delete mode 100644 xpcom/threads/nsIDelayedRunnableObserver.h diff --git a/dom/media/mediacontrol/MediaController.h b/dom/media/mediacontrol/MediaController.h index ef7a64556eeb..cc126c428aad 100644 --- a/dom/media/mediacontrol/MediaController.h +++ b/dom/media/mediacontrol/MediaController.h @@ -15,7 +15,6 @@ #include "mozilla/dom/MediaSession.h" #include "mozilla/LinkedList.h" #include "nsISupportsImpl.h" -#include "nsITimer.h" namespace mozilla { namespace dom { diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 4e9682addc2b..720e182eab98 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -803,7 +803,7 @@ pref("toolkit.telemetry.unified", true); #if defined(MOZ_TSAN) pref("toolkit.asyncshutdown.crash_timeout", 360000); // 6 minutes #else - pref("toolkit.asyncshutdown.crash_timeout", 300000); // 5 minutes + pref("toolkit.asyncshutdown.crash_timeout", 180000); // 3 minutes #endif #endif // !defined(MOZ_ASAN) && !defined(MOZ_TSAN) // Extra logging for AsyncShutdown barriers and phases diff --git a/netwerk/base/nsStreamTransportService.cpp b/netwerk/base/nsStreamTransportService.cpp index 90219b291df3..8de72ae3da13 100644 --- a/netwerk/base/nsStreamTransportService.cpp +++ b/netwerk/base/nsStreamTransportService.cpp @@ -16,7 +16,6 @@ #include "nsITransport.h" #include "nsIObserverService.h" #include "nsThreadPool.h" -#include "mozilla/DelayedRunnable.h" #include "mozilla/Services.h" namespace mozilla { @@ -244,12 +243,6 @@ nsInputStreamTransport::OnInputStreamReady(nsIAsyncInputStream* aStream) { // nsStreamTransportService //----------------------------------------------------------------------------- -nsStreamTransportService::nsStreamTransportService() - : mScheduledDelayedRunnables( - "nsStreamTransportService.mScheduledDelayedRunnables"), - mShutdownLock("nsStreamTransportService.mShutdownLock"), - mIsShutdown(false) {} - nsStreamTransportService::~nsStreamTransportService() { NS_ASSERTION(!mPool, "thread pool wasn't shutdown"); } @@ -269,25 +262,8 @@ nsresult nsStreamTransportService::Init() { return NS_OK; } -void nsStreamTransportService::OnDelayedRunnableCreated( - DelayedRunnable* aRunnable) {} - -void nsStreamTransportService::OnDelayedRunnableScheduled( - DelayedRunnable* aRunnable) { - MOZ_ASSERT(IsOnCurrentThread()); - auto delayedRunnables = mScheduledDelayedRunnables.Lock(); - delayedRunnables->AppendElement(aRunnable); -} - -void nsStreamTransportService::OnDelayedRunnableRan( - DelayedRunnable* aRunnable) { - MOZ_ASSERT(IsOnCurrentThread()); - auto delayedRunnables = mScheduledDelayedRunnables.Lock(); - MOZ_ALWAYS_TRUE(delayedRunnables->RemoveElement(aRunnable)); -} - NS_IMPL_ISUPPORTS(nsStreamTransportService, nsIStreamTransportService, - nsIEventTarget, nsIDelayedRunnableObserver, nsIObserver) + nsIEventTarget, nsIObserver) NS_IMETHODIMP nsStreamTransportService::DispatchFromScript(nsIRunnable* task, @@ -377,31 +353,6 @@ nsStreamTransportService::Observe(nsISupports* subject, const char* topic, mPool->Shutdown(); mPool = nullptr; } - - // Because the DelayedRunnables are run by a thread pool, no guarantee is - // given to which thread they run or get released on. Releasing them on the - // thread pool or on the background target thus doesn't really matter. We are - // forced to do it on the background target after the thread pool has finished - // processing all events, since doing it on the thread pool would allow the - // shutdown task to race with scheduling new DelayedRunnables, possibly - // missing the cleanup of some of them. - nsTArray> delayedRunnables; - { - auto sdrs = mScheduledDelayedRunnables.Lock(); - std::swap(*sdrs, delayedRunnables); - MOZ_ASSERT(sdrs->IsEmpty()); - } - if (!delayedRunnables.IsEmpty()) { - NS_DispatchBackgroundTask( - NS_NewRunnableFunction( - "nsStreamTransportService::mScheduledDelayedRunnables Cancel", - [delayedRunnables = std::move(delayedRunnables)] { - for (const auto& r : delayedRunnables) { - r->CancelTimer(); - } - }), - NS_DISPATCH_SYNC); - } return NS_OK; } diff --git a/netwerk/base/nsStreamTransportService.h b/netwerk/base/nsStreamTransportService.h index 5175633ed2ff..187db4f87cd6 100644 --- a/netwerk/base/nsStreamTransportService.h +++ b/netwerk/base/nsStreamTransportService.h @@ -5,26 +5,21 @@ #ifndef nsStreamTransportService_h__ #define nsStreamTransportService_h__ -#include "nsIDelayedRunnableObserver.h" #include "nsIStreamTransportService.h" #include "nsIEventTarget.h" #include "nsIObserver.h" #include "nsCOMPtr.h" #include "nsThreadUtils.h" #include "mozilla/Attributes.h" -#include "mozilla/DataMutex.h" #include "mozilla/Mutex.h" class nsIThreadPool; namespace mozilla { -class DelayedRunnable; - namespace net { class nsStreamTransportService final : public nsIStreamTransportService, public nsIEventTarget, - public nsIDelayedRunnableObserver, public nsIObserver { public: NS_DECL_THREADSAFE_ISUPPORTS @@ -34,19 +29,15 @@ class nsStreamTransportService final : public nsIStreamTransportService, nsresult Init(); - nsStreamTransportService(); - - void OnDelayedRunnableCreated(DelayedRunnable* aRunnable) override; - void OnDelayedRunnableScheduled(DelayedRunnable* aRunnable) override; - void OnDelayedRunnableRan(DelayedRunnable* aRunnable) override; + nsStreamTransportService() + : mShutdownLock("nsStreamTransportService.mShutdownLock"), + mIsShutdown(false) {} private: ~nsStreamTransportService(); nsCOMPtr mPool; - DataMutex>> mScheduledDelayedRunnables; - mozilla::Mutex mShutdownLock; bool mIsShutdown; }; diff --git a/netwerk/protocol/websocket/WebSocketChannel.cpp b/netwerk/protocol/websocket/WebSocketChannel.cpp index 3759ec7951f3..0193e4903e1d 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.cpp +++ b/netwerk/protocol/websocket/WebSocketChannel.cpp @@ -1181,8 +1181,6 @@ WebSocketChannel::~WebSocketChannel() { NS_ReleaseOnMainThread("WebSocketChannel::mLoadGroup", mLoadGroup.forget()); NS_ReleaseOnMainThread("WebSocketChannel::mLoadInfo", mLoadInfo.forget()); - NS_ReleaseOnMainThread("WebSocketChannel::mTargetThread", - mTargetThread.forget()); NS_ReleaseOnMainThread("WebSocketChannel::mService", mService.forget()); } diff --git a/testing/mochitest/mochitest_options.py b/testing/mochitest/mochitest_options.py index c9d293d91a7c..522daa57368a 100644 --- a/testing/mochitest/mochitest_options.py +++ b/testing/mochitest/mochitest_options.py @@ -1174,6 +1174,7 @@ class MochitestArguments(ArgumentContainer): "forkserver": options.defaultLeakThreshold, # GMP rarely gets a log, but when it does, it leaks a little. "gmplugin": 20000, + "rdd": 400, } # See the dependencies of bug 1401764. diff --git a/xpcom/build/XPCOMInit.cpp b/xpcom/build/XPCOMInit.cpp index 792c8d04bed5..b305d4200b06 100644 --- a/xpcom/build/XPCOMInit.cpp +++ b/xpcom/build/XPCOMInit.cpp @@ -621,7 +621,6 @@ nsresult ShutdownXPCOM(nsIServiceManager* aServMgr) { mozilla::AppShutdown::AdvanceShutdownPhase( mozilla::ShutdownPhase::XPCOMShutdownThreads); - nsThreadManager::get().CancelBackgroundDelayedRunnables(); gXPCOMThreadsShutDown = true; NS_ProcessPendingEvents(thread); diff --git a/xpcom/tests/gtest/TestDelayedRunnable.cpp b/xpcom/tests/gtest/TestDelayedRunnable.cpp deleted file mode 100644 index ac45374105a7..000000000000 --- a/xpcom/tests/gtest/TestDelayedRunnable.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/DelayedRunnable.h" - -#include "gtest/gtest.h" -#include "mozilla/media/MediaUtils.h" -#include "VideoUtils.h" - -namespace { -struct ReleaseDetector { - explicit ReleaseDetector(Atomic* aActive) : mActive(aActive) { - *mActive = true; - } - ReleaseDetector(ReleaseDetector&& aOther) noexcept : mActive(aOther.mActive) { - aOther.mActive = nullptr; - } - ReleaseDetector(const ReleaseDetector&) = delete; - ~ReleaseDetector() { - if (mActive) { - *mActive = false; - } - } - Atomic* mActive; -}; -} // namespace - -TEST(DelayedRunnable, TaskQueueShutdownLeak) -{ - Atomic active{false}; - auto taskQueue = - MakeRefPtr(GetMediaThreadPool(MediaThreadType::SUPERVISOR)); - taskQueue->DelayedDispatch( - NS_NewRunnableFunction(__func__, [release = ReleaseDetector(&active)] {}), - 60e3 /* 1 minute */); - EXPECT_TRUE(active); - taskQueue->BeginShutdown(); - taskQueue->AwaitIdle(); - // Leaks are often detected after process shutdown. This doesn't wait that - // long, but leaking past thread shutdown would be equally bad since the - // runnable can no longer be released on the target thread. This is also the - // reason why timers assert that they don't release the last reference to - // their callbacks when dispatch fails (like when the target has been - // shutdown). - EXPECT_FALSE(active); -} - -TEST(DelayedRunnable, nsThreadShutdownLeak) -{ - Atomic active{false}; - nsCOMPtr thread; - ASSERT_EQ(NS_NewNamedThread("Test Thread", getter_AddRefs(thread)), NS_OK); - thread->DelayedDispatch( - NS_NewRunnableFunction(__func__, [release = ReleaseDetector(&active)] {}), - 60e3 /* 1 minute */); - EXPECT_TRUE(active); - ASSERT_EQ(thread->Shutdown(), NS_OK); - // Leaks are often detected after process shutdown. This doesn't wait that - // long, but leaking past thread shutdown would be equally bad since the - // runnable can no longer be released on the target thread. This is also the - // reason why timers assert that they don't release the last reference to - // their callbacks when dispatch fails (like when the target has been - // shutdown). - EXPECT_FALSE(active); -} - -/* - * This tests a case where we create a background TaskQueue that lives until - * xpcom shutdown. This test will fail (by assertion failure) if the TaskQueue - * shutdown task is dispatched too late in the shutdown sequence, or: - * If the background thread pool is then empty, the TaskQueue shutdown task will - * when dispatched require creating a new nsThread, which is forbidden too late - * in the shutdown sequence. - */ -TEST(DelayedRunnable, BackgroundTaskQueueShutdownTask) -{ - nsCOMPtr taskQueue; - nsresult rv = NS_CreateBackgroundTaskQueue("TestDelayedRunnable", - getter_AddRefs(taskQueue)); - ASSERT_TRUE(NS_SUCCEEDED(rv)); - - // Leak the queue, so it gets cleaned up by xpcom-shutdown. - nsISerialEventTarget* tq = taskQueue.forget().take(); - Unused << tq; -} - -/* - * Like BackgroundTaskQueueShutdownTask but for nsThread, since both background - * TaskQueues and nsThreads are managed by nsThreadManager. For nsThread things - * are different and the shutdown task doesn't use Dispatch, but timings are - * similar. - */ -TEST(DelayedRunnable, nsThreadShutdownTask) -{ - nsCOMPtr thread; - ASSERT_EQ(NS_NewNamedThread("Test Thread", getter_AddRefs(thread)), NS_OK); - - // Leak the thread, so it gets cleaned up by xpcom-shutdown. - nsIThread* t = thread.forget().take(); - Unused << t; -} diff --git a/xpcom/tests/gtest/moz.build b/xpcom/tests/gtest/moz.build index 531a6df03bdc..e3d46fed5ff1 100644 --- a/xpcom/tests/gtest/moz.build +++ b/xpcom/tests/gtest/moz.build @@ -16,7 +16,6 @@ UNIFIED_SOURCES += [ "TestCOMPtrEq.cpp", "TestCRT.cpp", "TestDafsa.cpp", - "TestDelayedRunnable.cpp", "TestEncoding.cpp", "TestEscape.cpp", "TestEventPriorities.cpp", diff --git a/xpcom/threads/AbstractThread.cpp b/xpcom/threads/AbstractThread.cpp index 1be487673ad4..796b1539e903 100644 --- a/xpcom/threads/AbstractThread.cpp +++ b/xpcom/threads/AbstractThread.cpp @@ -7,7 +7,6 @@ #include "mozilla/AbstractThread.h" #include "mozilla/ClearOnShutdown.h" -#include "mozilla/DelayedRunnable.h" #include "mozilla/Maybe.h" #include "mozilla/MozPromise.h" // We initialize the MozPromise logging in this file. #include "mozilla/StateWatching.h" // We initialize the StateWatching logging in this file. @@ -31,14 +30,12 @@ MOZ_THREAD_LOCAL(AbstractThread*) AbstractThread::sCurrentThreadTLS; class XPCOMThreadWrapper final : public AbstractThread, public nsIThreadObserver, - public nsIDirectTaskDispatcher, - public nsIDelayedRunnableObserver { + public nsIDirectTaskDispatcher { public: XPCOMThreadWrapper(nsIThreadInternal* aThread, bool aRequireTailDispatch, bool aOnThread) : AbstractThread(aRequireTailDispatch), mThread(aThread), - mDelayedRunnableObserver(do_QueryInterface(mThread)), mDirectTaskDispatcher(do_QueryInterface(aThread)), mOnThread(aOnThread) { MOZ_DIAGNOSTIC_ASSERT(mThread && mDirectTaskDispatcher); @@ -160,22 +157,8 @@ class XPCOMThreadWrapper final : public AbstractThread, return mDirectTaskDispatcher->HaveDirectTasks(aResult); } - //----------------------------------------------------------------------------- - // nsIDelayedRunnableObserver - //----------------------------------------------------------------------------- - void OnDelayedRunnableCreated(DelayedRunnable* aRunnable) override { - mDelayedRunnableObserver->OnDelayedRunnableCreated(aRunnable); - } - void OnDelayedRunnableScheduled(DelayedRunnable* aRunnable) override { - mDelayedRunnableObserver->OnDelayedRunnableScheduled(aRunnable); - } - void OnDelayedRunnableRan(DelayedRunnable* aRunnable) override { - mDelayedRunnableObserver->OnDelayedRunnableRan(aRunnable); - } - private: const RefPtr mThread; - const nsCOMPtr mDelayedRunnableObserver; const nsCOMPtr mDirectTaskDispatcher; Maybe mTailDispatcher; const bool mOnThread; @@ -231,16 +214,8 @@ class XPCOMThreadWrapper final : public AbstractThread, const RefPtr mRunnable; }; }; - -NS_INTERFACE_MAP_BEGIN(XPCOMThreadWrapper) - NS_INTERFACE_MAP_ENTRY(nsIThreadObserver) - NS_INTERFACE_MAP_ENTRY(nsIDirectTaskDispatcher) - NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDelayedRunnableObserver, - mDelayedRunnableObserver) -NS_INTERFACE_MAP_END_INHERITING(AbstractThread) - -NS_IMPL_ADDREF_INHERITED(XPCOMThreadWrapper, AbstractThread) -NS_IMPL_RELEASE_INHERITED(XPCOMThreadWrapper, AbstractThread) +NS_IMPL_ISUPPORTS_INHERITED(XPCOMThreadWrapper, AbstractThread, + nsIThreadObserver, nsIDirectTaskDispatcher); NS_IMPL_ISUPPORTS(AbstractThread, nsIEventTarget, nsISerialEventTarget) diff --git a/xpcom/threads/DelayedRunnable.cpp b/xpcom/threads/DelayedRunnable.cpp deleted file mode 100644 index d782d52e3059..000000000000 --- a/xpcom/threads/DelayedRunnable.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "DelayedRunnable.h" - -namespace mozilla { - -DelayedRunnable::DelayedRunnable(already_AddRefed aTarget, - already_AddRefed aRunnable, - uint32_t aDelay) - : mozilla::Runnable("DelayedRunnable"), - mTarget(aTarget), - mObserver(do_QueryInterface(mTarget)), - mWrappedRunnable(aRunnable), - mDelayedFrom(TimeStamp::NowLoRes()), - mDelay(aDelay) { - MOZ_DIAGNOSTIC_ASSERT(mObserver, - "Target must implement nsIDelayedRunnableObserver"); -} - -nsresult DelayedRunnable::Init() { - mObserver->OnDelayedRunnableCreated(this); - return NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, mDelay, - nsITimer::TYPE_ONE_SHOT, mTarget); -} - -void DelayedRunnable::CancelTimer() { - MOZ_ASSERT(mTarget->IsOnCurrentThread()); - mTimer->Cancel(); -} - -NS_IMETHODIMP DelayedRunnable::Run() { - MOZ_ASSERT(mTimer, "DelayedRunnable without Init?"); - - // Already ran? - if (!mWrappedRunnable) { - return NS_OK; - } - - // Are we too early? - if ((mozilla::TimeStamp::NowLoRes() - mDelayedFrom).ToMilliseconds() < - mDelay) { - if (mObserver) { - mObserver->OnDelayedRunnableScheduled(this); - } - return NS_OK; // Let the nsITimer run us. - } - - mTimer->Cancel(); - return DoRun(); -} - -NS_IMETHODIMP DelayedRunnable::Notify(nsITimer* aTimer) { - // If we already ran, the timer should have been canceled. - MOZ_ASSERT(mWrappedRunnable); - - if (mObserver) { - mObserver->OnDelayedRunnableRan(this); - } - return DoRun(); -} - -nsresult DelayedRunnable::DoRun() { - nsCOMPtr r = std::move(mWrappedRunnable); - return r->Run(); -} - -NS_IMPL_ISUPPORTS_INHERITED(DelayedRunnable, Runnable, nsITimerCallback) - -} // namespace mozilla diff --git a/xpcom/threads/DelayedRunnable.h b/xpcom/threads/DelayedRunnable.h deleted file mode 100644 index 0bca644e42ff..000000000000 --- a/xpcom/threads/DelayedRunnable.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef XPCOM_THREADS_DELAYEDRUNNABLE_H_ -#define XPCOM_THREADS_DELAYEDRUNNABLE_H_ - -#include "mozilla/TimeStamp.h" -#include "nsCOMPtr.h" -#include "nsIDelayedRunnableObserver.h" -#include "nsIRunnable.h" -#include "nsITimer.h" -#include "nsThreadUtils.h" - -namespace mozilla { - -class DelayedRunnable : public Runnable, public nsITimerCallback { - public: - DelayedRunnable(already_AddRefed aTarget, - already_AddRefed aRunnable, uint32_t aDelay); - - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSIRUNNABLE - NS_DECL_NSITIMERCALLBACK - - nsresult Init(); - - /** - * Cancels the underlying timer. Called when the target is going away, so the - * runnable can be released safely on the target thread. - */ - void CancelTimer(); - - private: - ~DelayedRunnable() = default; - nsresult DoRun(); - - const nsCOMPtr mTarget; - const nsCOMPtr mObserver; - nsCOMPtr mWrappedRunnable; - nsCOMPtr mTimer; - const TimeStamp mDelayedFrom; - uint32_t mDelay; -}; - -} // namespace mozilla - -#endif diff --git a/xpcom/threads/InputTaskManager.h b/xpcom/threads/InputTaskManager.h index c5d7d524c6af..454883bf8d77 100644 --- a/xpcom/threads/InputTaskManager.h +++ b/xpcom/threads/InputTaskManager.h @@ -11,7 +11,6 @@ #include "TaskController.h" #include "mozilla/StaticPtr.h" #include "mozilla/StaticPrefs_dom.h" -#include "nsXULAppAPI.h" namespace mozilla { diff --git a/xpcom/threads/TaskQueue.cpp b/xpcom/threads/TaskQueue.cpp index 0e8e5fba3694..3236137bec29 100644 --- a/xpcom/threads/TaskQueue.cpp +++ b/xpcom/threads/TaskQueue.cpp @@ -6,7 +6,6 @@ #include "mozilla/TaskQueue.h" -#include "mozilla/DelayedRunnable.h" #include "nsThreadUtils.h" namespace mozilla { @@ -28,11 +27,9 @@ TaskQueue::TaskQueue(already_AddRefed aTarget, TaskQueue::~TaskQueue() { // No one is referencing this TaskQueue anymore, meaning no tasks can be // pending as all Runner hold a reference to this TaskQueue. - MOZ_ASSERT(mScheduledDelayedRunnables.IsEmpty()); } -NS_IMPL_ISUPPORTS_INHERITED(TaskQueue, AbstractThread, nsIDirectTaskDispatcher, - nsIDelayedRunnableObserver); +NS_IMPL_ISUPPORTS_INHERITED(TaskQueue, AbstractThread, nsIDirectTaskDispatcher); TaskDispatcher& TaskQueue::TailDispatcher() { MOZ_ASSERT(IsCurrentThreadIn()); @@ -107,52 +104,6 @@ void TaskQueue::AwaitShutdownAndIdle() { AwaitIdleLocked(); } -void TaskQueue::OnDelayedRunnableCreated(DelayedRunnable* aRunnable) { -#ifdef DEBUG - MonitorAutoLock mon(mQueueMonitor); - MOZ_ASSERT(!mDelayedRunnablesCancelPromise); -#endif -} - -void TaskQueue::OnDelayedRunnableScheduled(DelayedRunnable* aRunnable) { - MOZ_ASSERT(IsOnCurrentThread()); - mScheduledDelayedRunnables.AppendElement(aRunnable); -} - -void TaskQueue::OnDelayedRunnableRan(DelayedRunnable* aRunnable) { - MOZ_ASSERT(IsOnCurrentThread()); - MOZ_ALWAYS_TRUE(mScheduledDelayedRunnables.RemoveElement(aRunnable)); -} - -auto TaskQueue::CancelDelayedRunnables() -> RefPtr { - MonitorAutoLock mon(mQueueMonitor); - return CancelDelayedRunnablesLocked(); -} - -auto TaskQueue::CancelDelayedRunnablesLocked() -> RefPtr { - mQueueMonitor.AssertCurrentThreadOwns(); - if (mDelayedRunnablesCancelPromise) { - return mDelayedRunnablesCancelPromise; - } - mDelayedRunnablesCancelPromise = - mDelayedRunnablesCancelHolder.Ensure(__func__); - nsCOMPtr cancelRunnable = - NewRunnableMethod("TaskQueue::CancelDelayedRunnablesImpl", this, - &TaskQueue::CancelDelayedRunnablesImpl); - MOZ_ALWAYS_SUCCEEDS(DispatchLocked(/* passed by ref */ cancelRunnable, - NS_DISPATCH_NORMAL, TailDispatch)); - return mDelayedRunnablesCancelPromise; -} - -void TaskQueue::CancelDelayedRunnablesImpl() { - MOZ_ASSERT(IsOnCurrentThread()); - for (const auto& runnable : mScheduledDelayedRunnables) { - runnable->CancelTimer(); - } - mScheduledDelayedRunnables.Clear(); - mDelayedRunnablesCancelHolder.Resolve(true, __func__); -} - RefPtr TaskQueue::BeginShutdown() { // Dispatch any tasks for this queue waiting in the caller's tail dispatcher, // since this is the last opportunity to do so. @@ -160,7 +111,6 @@ RefPtr TaskQueue::BeginShutdown() { currentThread->TailDispatchTasksFor(this); } MonitorAutoLock mon(mQueueMonitor); - Unused << CancelDelayedRunnablesLocked(); mIsShutdown = true; RefPtr p = mShutdownPromise.Ensure(__func__); MaybeResolveShutdown(); diff --git a/xpcom/threads/TaskQueue.h b/xpcom/threads/TaskQueue.h index 245914299c2a..5b9837ecbd53 100644 --- a/xpcom/threads/TaskQueue.h +++ b/xpcom/threads/TaskQueue.h @@ -15,7 +15,6 @@ #include "mozilla/MozPromise.h" #include "mozilla/RefPtr.h" #include "mozilla/TaskDispatcher.h" -#include "nsIDelayedRunnableObserver.h" #include "nsIDirectTaskDispatcher.h" #include "nsThreadUtils.h" @@ -48,9 +47,7 @@ typedef MozPromise ShutdownPromise; // A TaskQueue does not require explicit shutdown, however it provides a // BeginShutdown() method that places TaskQueue in a shut down state and returns // a promise that gets resolved once all pending tasks have completed -class TaskQueue : public AbstractThread, - public nsIDirectTaskDispatcher, - public nsIDelayedRunnableObserver { +class TaskQueue : public AbstractThread, public nsIDirectTaskDispatcher { class EventTargetWrapper; public: @@ -96,18 +93,6 @@ class TaskQueue : public AbstractThread, // So we can access nsIEventTarget::Dispatch(nsIRunnable*, uint32_t aFlags) using nsIEventTarget::Dispatch; - // nsIDelayedRunnableObserver - void OnDelayedRunnableCreated(DelayedRunnable* aRunnable) override; - void OnDelayedRunnableScheduled(DelayedRunnable* aRunnable) override; - void OnDelayedRunnableRan(DelayedRunnable* aRunnable) override; - - using CancelPromise = MozPromise; - - // Dispatches a task to cancel any pending DelayedRunnables. Idempotent. Only - // dispatches the task on the first call. Creating DelayedRunnables after this - // is called will result in assertion failures. - RefPtr CancelDelayedRunnables(); - // Puts the queue in a shutdown state and returns immediately. The queue will // remain alive at least until all the events are drained, because the Runners // hold a strong reference to the task queue, and one of them is always held @@ -141,11 +126,6 @@ class TaskQueue : public AbstractThread, nsresult DispatchLocked(nsCOMPtr& aRunnable, uint32_t aFlags, DispatchReason aReason = NormalDispatch); - RefPtr CancelDelayedRunnablesLocked(); - - // Cancels any scheduled DelayedRunnables on this TaskQueue. - void CancelDelayedRunnablesImpl(); - void MaybeResolveShutdown() { mQueueMonitor.AssertCurrentThreadOwns(); if (mIsShutdown && !mIsRunning) { @@ -156,8 +136,7 @@ class TaskQueue : public AbstractThread, nsCOMPtr mTarget; - // Monitor that protects the queue, mIsRunning and - // mDelayedRunnablesCancelPromise; + // Monitor that protects the queue and mIsRunning; Monitor mQueueMonitor; typedef struct TaskStruct { @@ -168,18 +147,6 @@ class TaskQueue : public AbstractThread, // Queue of tasks to run. std::queue mTasks; - // DelayedRunnables (from DelayedDispatch) that are managed by their - // respective timers, but have not yet run. Accessed only on this - // TaskQueue. - nsTArray> mScheduledDelayedRunnables; - - // Manages resolving mDelayedRunnablesCancelPromise. - MozPromiseHolder mDelayedRunnablesCancelHolder; - - // Set once the task to cancel all pending DelayedRunnables has been - // dispatched. Guarded by mQueueMonitor. - RefPtr mDelayedRunnablesCancelPromise; - // The thread currently running the task queue. We store a reference // to this so that IsCurrentThreadIn() can tell if the current thread // is the thread currently running in the task queue. diff --git a/xpcom/threads/ThreadEventTarget.cpp b/xpcom/threads/ThreadEventTarget.cpp index e36f5a92c650..a7e82d782ffc 100644 --- a/xpcom/threads/ThreadEventTarget.cpp +++ b/xpcom/threads/ThreadEventTarget.cpp @@ -8,7 +8,6 @@ #include "mozilla/ThreadEventQueue.h" #include "LeakRefPtr.h" -#include "mozilla/DelayedRunnable.h" #include "mozilla/SpinEventLoopUntil.h" #include "mozilla/TimeStamp.h" #include "nsComponentManagerUtils.h" @@ -33,18 +32,13 @@ ThreadEventTarget::ThreadEventTarget(ThreadTargetSink* aSink, mThread = PR_GetCurrentThread(); } -ThreadEventTarget::~ThreadEventTarget() { - MOZ_ASSERT(mScheduledDelayedRunnables.IsEmpty()); -} - void ThreadEventTarget::SetCurrentThread(PRThread* aThread) { mThread = aThread; } void ThreadEventTarget::ClearCurrentThread() { mThread = nullptr; } -NS_IMPL_ISUPPORTS(ThreadEventTarget, nsIEventTarget, nsISerialEventTarget, - nsIDelayedRunnableObserver) +NS_IMPL_ISUPPORTS(ThreadEventTarget, nsIEventTarget, nsISerialEventTarget) NS_IMETHODIMP ThreadEventTarget::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags) { @@ -141,23 +135,3 @@ ThreadEventTarget::IsOnCurrentThreadInfallible() { // we are called, we can never be on this thread. return false; } - -void ThreadEventTarget::OnDelayedRunnableCreated(DelayedRunnable* aRunnable) {} - -void ThreadEventTarget::OnDelayedRunnableScheduled(DelayedRunnable* aRunnable) { - MOZ_ASSERT(IsOnCurrentThread()); - mScheduledDelayedRunnables.AppendElement(aRunnable); -} - -void ThreadEventTarget::OnDelayedRunnableRan(DelayedRunnable* aRunnable) { - MOZ_ASSERT(IsOnCurrentThread()); - MOZ_ALWAYS_TRUE(mScheduledDelayedRunnables.RemoveElement(aRunnable)); -} - -void ThreadEventTarget::NotifyShutdown() { - MOZ_ASSERT(IsOnCurrentThread()); - for (const auto& runnable : mScheduledDelayedRunnables) { - runnable->CancelTimer(); - } - mScheduledDelayedRunnables.Clear(); -} diff --git a/xpcom/threads/ThreadEventTarget.h b/xpcom/threads/ThreadEventTarget.h index cd766a7f0066..dd41d3218800 100644 --- a/xpcom/threads/ThreadEventTarget.h +++ b/xpcom/threads/ThreadEventTarget.h @@ -10,31 +10,19 @@ #include "mozilla/MemoryReporting.h" #include "mozilla/Mutex.h" #include "mozilla/SynchronizedEventQueue.h" // for ThreadTargetSink -#include "nsIDelayedRunnableObserver.h" #include "nsISerialEventTarget.h" namespace mozilla { -class DelayedRunnable; // ThreadEventTarget handles the details of posting an event to a thread. It can // be used with any ThreadTargetSink implementation. -class ThreadEventTarget final : public nsISerialEventTarget, - public nsIDelayedRunnableObserver { +class ThreadEventTarget final : public nsISerialEventTarget { public: ThreadEventTarget(ThreadTargetSink* aSink, bool aIsMainThread); NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIEVENTTARGET_FULL - // nsIDelayedRunnableObserver - void OnDelayedRunnableCreated(DelayedRunnable* aRunnable) override; - void OnDelayedRunnableScheduled(DelayedRunnable* aRunnable) override; - void OnDelayedRunnableRan(DelayedRunnable* aRunnable) override; - - // Notification from, and on, the owner thread that it is shutting down. - // Cancels any scheduled DelayedRunnables. - void NotifyShutdown(); - // Disconnects the target so that it can no longer post events. void Disconnect(const MutexAutoLock& aProofOfLock) { mSink->Disconnect(aProofOfLock); @@ -55,14 +43,10 @@ class ThreadEventTarget final : public nsISerialEventTarget, } private: - ~ThreadEventTarget(); + ~ThreadEventTarget() = default; RefPtr mSink; bool mIsMainThread; - - // DelayedRunnables (from DelayedDispatch) that are managed by their - // respective timers, but have not yet run. Accessed only on this nsThread. - nsTArray> mScheduledDelayedRunnables; }; } // namespace mozilla diff --git a/xpcom/threads/moz.build b/xpcom/threads/moz.build index 386c7de6eb79..2a78ebbdeffc 100644 --- a/xpcom/threads/moz.build +++ b/xpcom/threads/moz.build @@ -30,7 +30,6 @@ XPCOM_MANIFESTS += [ EXPORTS += [ "MainThreadUtils.h", "nsICancelableRunnable.h", - "nsIDelayedRunnableObserver.h", "nsIDiscardableRunnable.h", "nsIIdleRunnable.h", "nsMemoryPressure.h", @@ -49,7 +48,6 @@ EXPORTS.mozilla += [ "CPUUsageWatcher.h", "DataMutex.h", "DeadlockDetector.h", - "DelayedRunnable.h", "EventQueue.h", "IdlePeriodState.h", "IdleTaskRunner.h", @@ -91,7 +89,6 @@ UNIFIED_SOURCES += [ "AbstractThread.cpp", "BlockingResourceBase.cpp", "CPUUsageWatcher.cpp", - "DelayedRunnable.cpp", "EventQueue.cpp", "IdlePeriodState.cpp", "InputEventStatistics.cpp", diff --git a/xpcom/threads/nsIDelayedRunnableObserver.h b/xpcom/threads/nsIDelayedRunnableObserver.h deleted file mode 100644 index ad4e6de51aaa..000000000000 --- a/xpcom/threads/nsIDelayedRunnableObserver.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef XPCOM_THREADS_NSIDELAYEDRUNNABLEOBSERVER_H_ -#define XPCOM_THREADS_NSIDELAYEDRUNNABLEOBSERVER_H_ - -#include "nsISupports.h" - -namespace mozilla { -class DelayedRunnable; -} - -#define NS_IDELAYEDRUNNABLEOBSERVER_IID \ - { \ - 0xd226bade, 0xac13, 0x46fe, { \ - 0x9f, 0xcc, 0xde, 0xe7, 0x48, 0x35, 0xcd, 0x82 \ - } \ - } - -class NS_NO_VTABLE nsIDelayedRunnableObserver : public nsISupports { - public: - NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDELAYEDRUNNABLEOBSERVER_IID) - - /** - * Called by the DelayedRunnable after being created, on the dispatching - * thread. This allows for various lifetime checks and gives assertions a - * chance to provide useful stack traces. - */ - virtual void OnDelayedRunnableCreated( - mozilla::DelayedRunnable* aRunnable) = 0; - /** - * Called by the DelayedRunnable on its target thread when delegating the - * responsibility for being run to its underlying timer. - */ - virtual void OnDelayedRunnableScheduled( - mozilla::DelayedRunnable* aRunnable) = 0; - /** - * Called by the DelayedRunnable on its target thread after having been run by - * its underlying timer. - */ - virtual void OnDelayedRunnableRan(mozilla::DelayedRunnable* aRunnable) = 0; -}; - -NS_DEFINE_STATIC_IID_ACCESSOR(nsIDelayedRunnableObserver, - NS_IDELAYEDRUNNABLEOBSERVER_IID) - -#endif diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp index eaa6296e9e07..4680d17732bc 100644 --- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -186,7 +186,6 @@ NS_INTERFACE_MAP_BEGIN(nsThread) NS_INTERFACE_MAP_ENTRY(nsIEventTarget) NS_INTERFACE_MAP_ENTRY(nsISerialEventTarget) NS_INTERFACE_MAP_ENTRY(nsISupportsPriority) - NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDelayedRunnableObserver, mEventTarget) NS_INTERFACE_MAP_ENTRY(nsIDirectTaskDispatcher) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIThread) if (aIID.Equals(NS_GET_IID(nsIClassInfo))) { @@ -237,9 +236,6 @@ class nsThreadShutdownEvent : public Runnable { mShutdownContext(aCtx) {} NS_IMETHOD Run() override { mThread->mShutdownContext = mShutdownContext; - if (mThread->mEventTarget) { - mThread->mEventTarget->NotifyShutdown(); - } MessageLoop::current()->Quit(); return NS_OK; } @@ -1391,18 +1387,6 @@ nsIEventTarget* nsThread::EventTarget() { return this; } nsISerialEventTarget* nsThread::SerialEventTarget() { return this; } -void nsThread::OnDelayedRunnableCreated(mozilla::DelayedRunnable* aRunnable) { - mEventTarget->OnDelayedRunnableCreated(aRunnable); -} - -void nsThread::OnDelayedRunnableScheduled(mozilla::DelayedRunnable* aRunnable) { - mEventTarget->OnDelayedRunnableScheduled(aRunnable); -} - -void nsThread::OnDelayedRunnableRan(mozilla::DelayedRunnable* aRunnable) { - mEventTarget->OnDelayedRunnableRan(aRunnable); -} - nsLocalExecutionRecord nsThread::EnterLocalExecution() { MOZ_RELEASE_ASSERT(!mIsInLocalExecutionMode); MOZ_ASSERT(IsOnCurrentThread()); diff --git a/xpcom/threads/nsThread.h b/xpcom/threads/nsThread.h index dc3606969971..46074acd3667 100644 --- a/xpcom/threads/nsThread.h +++ b/xpcom/threads/nsThread.h @@ -21,7 +21,6 @@ #include "mozilla/TaskDispatcher.h" #include "mozilla/TimeStamp.h" #include "mozilla/UniquePtr.h" -#include "nsIDelayedRunnableObserver.h" #include "nsIDirectTaskDispatcher.h" #include "nsIEventTarget.h" #include "nsISerialEventTarget.h" @@ -32,7 +31,6 @@ namespace mozilla { class CycleCollectedJSContext; -class DelayedRunnable; class SynchronizedEventQueue; class ThreadEventQueue; class ThreadEventTarget; @@ -154,7 +152,6 @@ class PerformanceCounterState { // A native thread class nsThread : public nsIThreadInternal, public nsISupportsPriority, - public nsIDelayedRunnableObserver, public nsIDirectTaskDispatcher, private mozilla::LinkedListElement { friend mozilla::LinkedList; @@ -261,10 +258,6 @@ class nsThread : public nsIThreadInternal, mUseHangMonitor = aValue; } - void OnDelayedRunnableCreated(mozilla::DelayedRunnable* aRunnable) override; - void OnDelayedRunnableScheduled(mozilla::DelayedRunnable* aRunnable) override; - void OnDelayedRunnableRan(mozilla::DelayedRunnable* aRunnable) override; - private: void DoMainThreadSpecificProcessing() const; diff --git a/xpcom/threads/nsThreadManager.cpp b/xpcom/threads/nsThreadManager.cpp index eccd710928ce..dbc317f51999 100644 --- a/xpcom/threads/nsThreadManager.cpp +++ b/xpcom/threads/nsThreadManager.cpp @@ -51,9 +51,6 @@ class BackgroundEventTarget final : public nsIEventTarget { already_AddRefed CreateBackgroundTaskQueue( const char* aName); - using CancelPromise = TaskQueue::CancelPromise::AllPromiseType; - RefPtr CancelBackgroundDelayedRunnables(); - void BeginShutdown(nsTArray>&); void FinishShutdown(); @@ -65,7 +62,6 @@ class BackgroundEventTarget final : public nsIEventTarget { Mutex mMutex; nsTArray> mTaskQueues; - bool mIsBackgroundDelayedRunnablesCanceled; }; NS_IMPL_ISUPPORTS(BackgroundEventTarget, nsIEventTarget) @@ -202,19 +198,6 @@ BackgroundEventTarget::CreateBackgroundTaskQueue(const char* aName) { return queue.forget(); } -auto BackgroundEventTarget::CancelBackgroundDelayedRunnables() - -> RefPtr { - MOZ_ASSERT(NS_IsMainThread()); - MutexAutoLock lock(mMutex); - mIsBackgroundDelayedRunnablesCanceled = true; - nsTArray> promises; - for (const auto& tq : mTaskQueues) { - promises.AppendElement(tq->CancelDelayedRunnables()); - } - return TaskQueue::CancelPromise::All(GetMainThreadSerialEventTarget(), - promises); -} - extern "C" { // This uses the C language linkage because it's exposed to Rust // via the xpcom/rust/moz_task crate. @@ -369,17 +352,28 @@ void nsThreadManager::Shutdown() { // Empty the main thread event queue before we begin shutting down threads. NS_ProcessPendingEvents(mMainThread); + typedef typename ShutdownPromise::AllPromiseType AllPromise; + typename AllPromise::ResolveOrRejectValue val; + using ResolveValueT = typename AllPromise::ResolveValueType; + using RejectValueT = typename AllPromise::RejectValueType; + nsTArray> promises; mBackgroundEventTarget->BeginShutdown(promises); + RefPtr complete = ShutdownPromise::All(mMainThread, promises); + bool taskQueuesShutdown = false; - // It's fine to capture everything by reference in the Then handler since it - // runs before we exit the nested event loop, thanks to the SpinEventLoopUntil - // below. - ShutdownPromise::All(mMainThread, promises)->Then(mMainThread, __func__, [&] { - mBackgroundEventTarget->FinishShutdown(); - taskQueuesShutdown = true; - }); + + complete->Then( + mMainThread, __func__, + [&](const ResolveValueT& aResolveValue) { + mBackgroundEventTarget->FinishShutdown(); + taskQueuesShutdown = true; + }, + [&](RejectValueT aRejectValue) { + mBackgroundEventTarget->FinishShutdown(); + taskQueuesShutdown = true; + }); // Wait for task queues to shutdown, so we don't shut down the underlying // threads of the background event target in the block below, thereby @@ -419,8 +413,6 @@ void nsThreadManager::Shutdown() { // in-flight asynchronous thread shutdowns to complete. mMainThread->WaitForAllAsynchronousShutdowns(); - mMainThread->mEventTarget->NotifyShutdown(); - // In case there are any more events somehow... NS_ProcessPendingEvents(mMainThread); @@ -509,17 +501,6 @@ nsThreadManager::CreateBackgroundTaskQueue(const char* aName) { return mBackgroundEventTarget->CreateBackgroundTaskQueue(aName); } -void nsThreadManager::CancelBackgroundDelayedRunnables() { - if (!mInitialized) { - return; - } - - bool canceled = false; - mBackgroundEventTarget->CancelBackgroundDelayedRunnables()->Then( - GetMainThreadSerialEventTarget(), __func__, [&] { canceled = true; }); - ::SpinEventLoopUntil([&]() { return canceled; }); -} - nsThread* nsThreadManager::GetCurrentThread() { // read thread local storage void* data = PR_GetThreadPrivate(mCurThreadIndex); diff --git a/xpcom/threads/nsThreadManager.h b/xpcom/threads/nsThreadManager.h index 36187ec4684b..f4b685178e2e 100644 --- a/xpcom/threads/nsThreadManager.h +++ b/xpcom/threads/nsThreadManager.h @@ -67,14 +67,6 @@ class nsThreadManager : public nsIThreadManager { already_AddRefed CreateBackgroundTaskQueue( const char* aName); - // For each background TaskQueue cancel pending DelayedRunnables, and prohibit - // creating future DelayedRunnables for them, since we'll soon be shutting - // them down. - // Pending DelayedRunnables are canceled on their respective TaskQueue. - // We block main thread until they are all done, but spin the eventloop in the - // meantime. - void CancelBackgroundDelayedRunnables(); - ~nsThreadManager(); void EnableMainThreadEventPrioritization(); diff --git a/xpcom/threads/nsThreadUtils.cpp b/xpcom/threads/nsThreadUtils.cpp index 10390ec86dbf..bbca11b6b34d 100644 --- a/xpcom/threads/nsThreadUtils.cpp +++ b/xpcom/threads/nsThreadUtils.cpp @@ -762,6 +762,53 @@ void SerialEventTargetGuard::InitTLS() { } } +DelayedRunnable::DelayedRunnable(already_AddRefed aTarget, + already_AddRefed aRunnable, + uint32_t aDelay) + : mozilla::Runnable("DelayedRunnable"), + mTarget(aTarget), + mWrappedRunnable(aRunnable), + mDelayedFrom(TimeStamp::NowLoRes()), + mDelay(aDelay) {} + +nsresult DelayedRunnable::Init() { + return NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, mDelay, + nsITimer::TYPE_ONE_SHOT, mTarget); +} + +NS_IMETHODIMP DelayedRunnable::Run() { + MOZ_ASSERT(mTimer, "DelayedRunnable without Init?"); + + // Already ran? + if (!mWrappedRunnable) { + return NS_OK; + } + + // Are we too early? + if ((mozilla::TimeStamp::NowLoRes() - mDelayedFrom).ToMilliseconds() < + mDelay) { + return NS_OK; // Let the nsITimer run us. + } + + mTimer->Cancel(); + return DoRun(); +} + +NS_IMETHODIMP DelayedRunnable::Notify(nsITimer* aTimer) { + // If we already ran, the timer should have been canceled. + MOZ_ASSERT(mWrappedRunnable); + MOZ_ASSERT(aTimer == mTimer); + + return DoRun(); +} + +nsresult DelayedRunnable::DoRun() { + nsCOMPtr r = std::move(mWrappedRunnable); + return r->Run(); +} + +NS_IMPL_ISUPPORTS_INHERITED(DelayedRunnable, Runnable, nsITimerCallback) + } // namespace mozilla bool nsIEventTarget::IsOnCurrentThread() { diff --git a/xpcom/threads/nsThreadUtils.h b/xpcom/threads/nsThreadUtils.h index 85b230380871..a8d64de83e6c 100644 --- a/xpcom/threads/nsThreadUtils.h +++ b/xpcom/threads/nsThreadUtils.h @@ -1941,6 +1941,28 @@ typedef LogTaskBase LogFrameRequestCallback; // If you add new types don't forget to add: // `template class LogTaskBase;` to nsThreadUtils.cpp +class DelayedRunnable : public mozilla::Runnable, public nsITimerCallback { + public: + DelayedRunnable(already_AddRefed aTarget, + already_AddRefed aRunnable, uint32_t aDelay); + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIRUNNABLE + NS_DECL_NSITIMERCALLBACK + + nsresult Init(); + + private: + ~DelayedRunnable() = default; + nsresult DoRun(); + + const nsCOMPtr mTarget; + nsCOMPtr mWrappedRunnable; + nsCOMPtr mTimer; + const mozilla::TimeStamp mDelayedFrom; + uint32_t mDelay; +}; + } // namespace mozilla #endif // nsThreadUtils_h__