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/. */
6 
7 #include "DelayedRunnable.h"
8 
9 #include "mozilla/ProfilerRunnable.h"
10 
11 namespace mozilla {
12 
DelayedRunnable(already_AddRefed<nsIEventTarget> aTarget,already_AddRefed<nsIRunnable> aRunnable,uint32_t aDelay)13 DelayedRunnable::DelayedRunnable(already_AddRefed<nsIEventTarget> aTarget,
14                                  already_AddRefed<nsIRunnable> aRunnable,
15                                  uint32_t aDelay)
16     : mozilla::Runnable("DelayedRunnable"),
17       mTarget(aTarget),
18       mObserver(do_QueryInterface(mTarget)),
19       mWrappedRunnable(aRunnable),
20       mDelayedFrom(TimeStamp::NowLoRes()),
21       mDelay(aDelay) {
22   MOZ_DIAGNOSTIC_ASSERT(mObserver,
23                         "Target must implement nsIDelayedRunnableObserver");
24 }
25 
Init()26 nsresult DelayedRunnable::Init() {
27   mObserver->OnDelayedRunnableCreated(this);
28   return NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, mDelay,
29                                  nsITimer::TYPE_ONE_SHOT, mTarget);
30 }
31 
CancelTimer()32 void DelayedRunnable::CancelTimer() {
33   MOZ_ASSERT(mTarget->IsOnCurrentThread());
34   mTimer->Cancel();
35 }
36 
Run()37 NS_IMETHODIMP DelayedRunnable::Run() {
38   MOZ_ASSERT(mTimer, "DelayedRunnable without Init?");
39 
40   // Already ran?
41   if (!mWrappedRunnable) {
42     return NS_OK;
43   }
44 
45   // Are we too early?
46   if ((mozilla::TimeStamp::NowLoRes() - mDelayedFrom).ToMilliseconds() <
47       mDelay) {
48     if (mObserver) {
49       mObserver->OnDelayedRunnableScheduled(this);
50     }
51     return NS_OK;  // Let the nsITimer run us.
52   }
53 
54   mTimer->Cancel();
55   return DoRun();
56 }
57 
Notify(nsITimer * aTimer)58 NS_IMETHODIMP DelayedRunnable::Notify(nsITimer* aTimer) {
59   // If we already ran, the timer should have been canceled.
60   MOZ_ASSERT(mWrappedRunnable);
61 
62   if (mObserver) {
63     mObserver->OnDelayedRunnableRan(this);
64   }
65   return DoRun();
66 }
67 
DoRun()68 nsresult DelayedRunnable::DoRun() {
69   nsCOMPtr<nsIRunnable> r = std::move(mWrappedRunnable);
70   AUTO_PROFILE_FOLLOWING_RUNNABLE(r);
71   return r->Run();
72 }
73 
74 NS_IMPL_ISUPPORTS_INHERITED(DelayedRunnable, Runnable, nsITimerCallback)
75 
76 }  // namespace mozilla
77