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"
12 #include "nsIRunnable.h"
15 #include "nsComponentManagerUtils.h"
16 #include "nsThreadUtils.h"
18 using namespace mozilla
;
23 * This Task runs its nsIRunnable when Run() is called, or after
24 * aEnsureRunsAfterMS milliseconds have elapsed since the object was
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
{
32 MessageLoopIdleTask(nsIRunnable
* aTask
, uint32_t aEnsureRunsAfterMS
);
33 NS_IMETHOD
Run() override
;
36 nsresult
Init(uint32_t aEnsureRunsAfterMS
);
38 nsCOMPtr
<nsIRunnable
> mTask
;
39 nsCOMPtr
<nsITimer
> mTimer
;
41 virtual ~MessageLoopIdleTask() = default;
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
{
56 explicit MessageLoopTimerCallback(MessageLoopIdleTask
* aTask
);
59 NS_DECL_NSITIMERCALLBACK
61 NS_IMETHOD
GetName(nsACString
& aName
) override
{
62 aName
.AssignLiteral("MessageLoopTimerCallback");
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
);
81 "Running idle task early because we couldn't initialize our timer.");
82 NS_DispatchToCurrentThread(mTask
);
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
);
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
115 MessageLoopTimerCallback::MessageLoopTimerCallback(MessageLoopIdleTask
* aTask
)
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.");
131 NS_IMPL_ISUPPORTS(MessageLoopTimerCallback
, nsITimerCallback
, nsINamed
)
135 NS_IMPL_ISUPPORTS(nsMessageLoop
, nsIMessageLoop
)
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());
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
);