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__