Bug 1686838 [wpt PR 27194] - [webcodecs] Deprecate VideoFrame.destroy()., a=testonly
[gecko.git] / xpcom / base / nsMessageLoop.cpp
blob98e335a9fdb54fe909a67115dd198a9095556c44
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsMessageLoop.h"
8 #include "mozilla/WeakPtr.h"
9 #include "base/message_loop.h"
10 #include "base/task.h"
11 #include "nsINamed.h"
12 #include "nsIRunnable.h"
13 #include "nsITimer.h"
14 #include "nsCOMPtr.h"
15 #include "nsComponentManagerUtils.h"
16 #include "nsThreadUtils.h"
18 using namespace mozilla;
20 namespace {
22 /**
23 * This Task runs its nsIRunnable when Run() is called, or after
24 * aEnsureRunsAfterMS milliseconds have elapsed since the object was
25 * constructed.
27 * Note that the MessageLoop owns this object and will delete it after it calls
28 * Run(). Tread lightly.
30 class MessageLoopIdleTask : public Runnable, public SupportsWeakPtr {
31 public:
32 MessageLoopIdleTask(nsIRunnable* aTask, uint32_t aEnsureRunsAfterMS);
33 NS_IMETHOD Run() override;
35 private:
36 nsresult Init(uint32_t aEnsureRunsAfterMS);
38 nsCOMPtr<nsIRunnable> mTask;
39 nsCOMPtr<nsITimer> mTimer;
41 virtual ~MessageLoopIdleTask() = default;
44 /**
45 * This timer callback calls MessageLoopIdleTask::Run() when its timer fires.
46 * (The timer can't call back into MessageLoopIdleTask directly since that's
47 * not a refcounted object; it's owned by the MessageLoop.)
49 * We keep a weak reference to the MessageLoopIdleTask, although a raw pointer
50 * should in theory suffice: When the MessageLoopIdleTask runs (right before
51 * the MessageLoop deletes it), it cancels its timer. But the weak pointer
52 * saves us from worrying about an edge case somehow messing us up here.
54 class MessageLoopTimerCallback : public nsITimerCallback, public nsINamed {
55 public:
56 explicit MessageLoopTimerCallback(MessageLoopIdleTask* aTask);
58 NS_DECL_ISUPPORTS
59 NS_DECL_NSITIMERCALLBACK
61 NS_IMETHOD GetName(nsACString& aName) override {
62 aName.AssignLiteral("MessageLoopTimerCallback");
63 return NS_OK;
66 private:
67 WeakPtr<MessageLoopIdleTask> mTask;
69 virtual ~MessageLoopTimerCallback() = default;
72 MessageLoopIdleTask::MessageLoopIdleTask(nsIRunnable* aTask,
73 uint32_t aEnsureRunsAfterMS)
74 : mozilla::Runnable("MessageLoopIdleTask"), mTask(aTask) {
75 // Init() really shouldn't fail, but if it does, we schedule our runnable
76 // immediately, because it's more important to guarantee that we run the task
77 // eventually than it is to run the task when we're idle.
78 nsresult rv = Init(aEnsureRunsAfterMS);
79 if (NS_FAILED(rv)) {
80 NS_WARNING(
81 "Running idle task early because we couldn't initialize our timer.");
82 NS_DispatchToCurrentThread(mTask);
84 mTask = nullptr;
85 mTimer = nullptr;
89 nsresult MessageLoopIdleTask::Init(uint32_t aEnsureRunsAfterMS) {
90 RefPtr<MessageLoopTimerCallback> callback =
91 new MessageLoopTimerCallback(this);
92 return NS_NewTimerWithCallback(getter_AddRefs(mTimer), callback,
93 aEnsureRunsAfterMS, nsITimer::TYPE_ONE_SHOT);
96 NS_IMETHODIMP
97 MessageLoopIdleTask::Run() {
98 // Null out our pointers because if Run() was called by the timer, this
99 // object will be kept alive by the MessageLoop until the MessageLoop calls
100 // Run().
102 if (mTimer) {
103 mTimer->Cancel();
104 mTimer = nullptr;
107 if (mTask) {
108 mTask->Run();
109 mTask = nullptr;
112 return NS_OK;
115 MessageLoopTimerCallback::MessageLoopTimerCallback(MessageLoopIdleTask* aTask)
116 : mTask(aTask) {}
118 NS_IMETHODIMP
119 MessageLoopTimerCallback::Notify(nsITimer* aTimer) {
120 // We don't expect to hit the case when the timer fires but mTask has been
121 // deleted, because mTask should cancel the timer before the mTask is
122 // deleted. But you never know...
123 NS_WARNING_ASSERTION(mTask, "This timer shouldn't have fired.");
125 if (mTask) {
126 mTask->Run();
128 return NS_OK;
131 NS_IMPL_ISUPPORTS(MessageLoopTimerCallback, nsITimerCallback, nsINamed)
133 } // namespace
135 NS_IMPL_ISUPPORTS(nsMessageLoop, nsIMessageLoop)
137 NS_IMETHODIMP
138 nsMessageLoop::PostIdleTask(nsIRunnable* aTask, uint32_t aEnsureRunsAfterMS) {
139 // The message loop owns MessageLoopIdleTask and deletes it after calling
140 // Run(). Be careful...
141 RefPtr<MessageLoopIdleTask> idle =
142 new MessageLoopIdleTask(aTask, aEnsureRunsAfterMS);
143 MessageLoop::current()->PostIdleTask(idle.forget());
145 return NS_OK;
148 nsresult nsMessageLoopConstructor(nsISupports* aOuter, const nsIID& aIID,
149 void** aInstancePtr) {
150 if (NS_WARN_IF(aOuter)) {
151 return NS_ERROR_NO_AGGREGATION;
153 nsISupports* messageLoop = new nsMessageLoop();
154 return messageLoop->QueryInterface(aIID, aInstancePtr);