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)
This commit is contained in:
Brindusan Cristian 2021-04-06 17:41:19 +03:00
Родитель 621339b801
Коммит f78d18d827
25 изменённых файлов: 102 добавлений и 576 удалений

Просмотреть файл

@ -15,7 +15,6 @@
#include "mozilla/dom/MediaSession.h"
#include "mozilla/LinkedList.h"
#include "nsISupportsImpl.h"
#include "nsITimer.h"
namespace mozilla {
namespace dom {

Просмотреть файл

@ -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

Просмотреть файл

@ -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<RefPtr<DelayedRunnable>> 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;
}

Просмотреть файл

@ -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<nsIThreadPool> mPool;
DataMutex<nsTArray<RefPtr<DelayedRunnable>>> mScheduledDelayedRunnables;
mozilla::Mutex mShutdownLock;
bool mIsShutdown;
};

Просмотреть файл

@ -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());
}

Просмотреть файл

@ -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.

Просмотреть файл

@ -621,7 +621,6 @@ nsresult ShutdownXPCOM(nsIServiceManager* aServMgr) {
mozilla::AppShutdown::AdvanceShutdownPhase(
mozilla::ShutdownPhase::XPCOMShutdownThreads);
nsThreadManager::get().CancelBackgroundDelayedRunnables();
gXPCOMThreadsShutDown = true;
NS_ProcessPendingEvents(thread);

Просмотреть файл

@ -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<bool>* 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<bool>* mActive;
};
} // namespace
TEST(DelayedRunnable, TaskQueueShutdownLeak)
{
Atomic<bool> active{false};
auto taskQueue =
MakeRefPtr<TaskQueue>(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<bool> active{false};
nsCOMPtr<nsIThread> 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<nsISerialEventTarget> 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<nsIThread> 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;
}

Просмотреть файл

@ -16,7 +16,6 @@ UNIFIED_SOURCES += [
"TestCOMPtrEq.cpp",
"TestCRT.cpp",
"TestDafsa.cpp",
"TestDelayedRunnable.cpp",
"TestEncoding.cpp",
"TestEscape.cpp",
"TestEventPriorities.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<nsIThreadInternal> mThread;
const nsCOMPtr<nsIDelayedRunnableObserver> mDelayedRunnableObserver;
const nsCOMPtr<nsIDirectTaskDispatcher> mDirectTaskDispatcher;
Maybe<AutoTaskDispatcher> mTailDispatcher;
const bool mOnThread;
@ -231,16 +214,8 @@ class XPCOMThreadWrapper final : public AbstractThread,
const RefPtr<nsIRunnable> 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)

Просмотреть файл

@ -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<nsIEventTarget> aTarget,
already_AddRefed<nsIRunnable> 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<nsIRunnable> r = std::move(mWrappedRunnable);
return r->Run();
}
NS_IMPL_ISUPPORTS_INHERITED(DelayedRunnable, Runnable, nsITimerCallback)
} // namespace mozilla

Просмотреть файл

@ -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<nsIEventTarget> aTarget,
already_AddRefed<nsIRunnable> 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<nsIEventTarget> mTarget;
const nsCOMPtr<nsIDelayedRunnableObserver> mObserver;
nsCOMPtr<nsIRunnable> mWrappedRunnable;
nsCOMPtr<nsITimer> mTimer;
const TimeStamp mDelayedFrom;
uint32_t mDelay;
};
} // namespace mozilla
#endif

Просмотреть файл

@ -11,7 +11,6 @@
#include "TaskController.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/StaticPrefs_dom.h"
#include "nsXULAppAPI.h"
namespace mozilla {

Просмотреть файл

@ -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<nsIEventTarget> 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<CancelPromise> {
MonitorAutoLock mon(mQueueMonitor);
return CancelDelayedRunnablesLocked();
}
auto TaskQueue::CancelDelayedRunnablesLocked() -> RefPtr<CancelPromise> {
mQueueMonitor.AssertCurrentThreadOwns();
if (mDelayedRunnablesCancelPromise) {
return mDelayedRunnablesCancelPromise;
}
mDelayedRunnablesCancelPromise =
mDelayedRunnablesCancelHolder.Ensure(__func__);
nsCOMPtr<nsIRunnable> 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<ShutdownPromise> 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<ShutdownPromise> TaskQueue::BeginShutdown() {
currentThread->TailDispatchTasksFor(this);
}
MonitorAutoLock mon(mQueueMonitor);
Unused << CancelDelayedRunnablesLocked();
mIsShutdown = true;
RefPtr<ShutdownPromise> p = mShutdownPromise.Ensure(__func__);
MaybeResolveShutdown();

Просмотреть файл

@ -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<bool, bool, false> 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<bool, bool, false>;
// 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<CancelPromise> 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<nsIRunnable>& aRunnable, uint32_t aFlags,
DispatchReason aReason = NormalDispatch);
RefPtr<CancelPromise> 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<nsIEventTarget> 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<TaskStruct> mTasks;
// DelayedRunnables (from DelayedDispatch) that are managed by their
// respective timers, but have not yet run. Accessed only on this
// TaskQueue.
nsTArray<RefPtr<DelayedRunnable>> mScheduledDelayedRunnables;
// Manages resolving mDelayedRunnablesCancelPromise.
MozPromiseHolder<CancelPromise> mDelayedRunnablesCancelHolder;
// Set once the task to cancel all pending DelayedRunnables has been
// dispatched. Guarded by mQueueMonitor.
RefPtr<CancelPromise> 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.

Просмотреть файл

@ -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();
}

Просмотреть файл

@ -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<ThreadTargetSink> mSink;
bool mIsMainThread;
// DelayedRunnables (from DelayedDispatch) that are managed by their
// respective timers, but have not yet run. Accessed only on this nsThread.
nsTArray<RefPtr<mozilla::DelayedRunnable>> mScheduledDelayedRunnables;
};
} // namespace mozilla

Просмотреть файл

@ -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",

Просмотреть файл

@ -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

Просмотреть файл

@ -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());

Просмотреть файл

@ -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<nsThread> {
friend mozilla::LinkedList<nsThread>;
@ -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;

Просмотреть файл

@ -51,9 +51,6 @@ class BackgroundEventTarget final : public nsIEventTarget {
already_AddRefed<nsISerialEventTarget> CreateBackgroundTaskQueue(
const char* aName);
using CancelPromise = TaskQueue::CancelPromise::AllPromiseType;
RefPtr<CancelPromise> CancelBackgroundDelayedRunnables();
void BeginShutdown(nsTArray<RefPtr<ShutdownPromise>>&);
void FinishShutdown();
@ -65,7 +62,6 @@ class BackgroundEventTarget final : public nsIEventTarget {
Mutex mMutex;
nsTArray<RefPtr<TaskQueue>> mTaskQueues;
bool mIsBackgroundDelayedRunnablesCanceled;
};
NS_IMPL_ISUPPORTS(BackgroundEventTarget, nsIEventTarget)
@ -202,19 +198,6 @@ BackgroundEventTarget::CreateBackgroundTaskQueue(const char* aName) {
return queue.forget();
}
auto BackgroundEventTarget::CancelBackgroundDelayedRunnables()
-> RefPtr<CancelPromise> {
MOZ_ASSERT(NS_IsMainThread());
MutexAutoLock lock(mMutex);
mIsBackgroundDelayedRunnablesCanceled = true;
nsTArray<RefPtr<TaskQueue::CancelPromise>> 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<RefPtr<ShutdownPromise>> promises;
mBackgroundEventTarget->BeginShutdown(promises);
RefPtr<AllPromise> 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);

Просмотреть файл

@ -67,14 +67,6 @@ class nsThreadManager : public nsIThreadManager {
already_AddRefed<nsISerialEventTarget> 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();

Просмотреть файл

@ -762,6 +762,53 @@ void SerialEventTargetGuard::InitTLS() {
}
}
DelayedRunnable::DelayedRunnable(already_AddRefed<nsIEventTarget> aTarget,
already_AddRefed<nsIRunnable> 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<nsIRunnable> r = std::move(mWrappedRunnable);
return r->Run();
}
NS_IMPL_ISUPPORTS_INHERITED(DelayedRunnable, Runnable, nsITimerCallback)
} // namespace mozilla
bool nsIEventTarget::IsOnCurrentThread() {

Просмотреть файл

@ -1941,6 +1941,28 @@ typedef LogTaskBase<dom::FrameRequestCallback> LogFrameRequestCallback;
// If you add new types don't forget to add:
// `template class LogTaskBase<YourType>;` to nsThreadUtils.cpp
class DelayedRunnable : public mozilla::Runnable, public nsITimerCallback {
public:
DelayedRunnable(already_AddRefed<nsIEventTarget> aTarget,
already_AddRefed<nsIRunnable> aRunnable, uint32_t aDelay);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIRUNNABLE
NS_DECL_NSITIMERCALLBACK
nsresult Init();
private:
~DelayedRunnable() = default;
nsresult DoRun();
const nsCOMPtr<nsIEventTarget> mTarget;
nsCOMPtr<nsIRunnable> mWrappedRunnable;
nsCOMPtr<nsITimer> mTimer;
const mozilla::TimeStamp mDelayedFrom;
uint32_t mDelay;
};
} // namespace mozilla
#endif // nsThreadUtils_h__