xpcom/base/nsMessageLoop.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsMessageLoop.h"
     7 #include "mozilla/WeakPtr.h"
     8 #include "base/message_loop.h"
     9 #include "base/task.h"
    10 #include "nsIRunnable.h"
    11 #include "nsITimer.h"
    12 #include "nsCOMPtr.h"
    13 #include "nsAutoPtr.h"
    14 #include "nsComponentManagerUtils.h"
    15 #include "nsThreadUtils.h"
    17 using namespace mozilla;
    19 namespace {
    21 /**
    22  * This Task runs its nsIRunnable when Run() is called, or after
    23  * aEnsureRunsAfterMS milliseconds have elapsed since the object was
    24  * constructed.
    25  *
    26  * Note that the MessageLoop owns this object and will delete it after it calls
    27  * Run().  Tread lightly.
    28  */
    29 class MessageLoopIdleTask
    30   : public Task
    31   , public SupportsWeakPtr<MessageLoopIdleTask>
    32 {
    33 public:
    34   MOZ_DECLARE_REFCOUNTED_TYPENAME(MessageLoopIdleTask)
    35   MessageLoopIdleTask(nsIRunnable* aTask, uint32_t aEnsureRunsAfterMS);
    36   virtual ~MessageLoopIdleTask() {}
    37   virtual void Run();
    39 private:
    40   nsresult Init(uint32_t aEnsureRunsAfterMS);
    42   nsCOMPtr<nsIRunnable> mTask;
    43   nsCOMPtr<nsITimer> mTimer;
    44 };
    46 /**
    47  * This timer callback calls MessageLoopIdleTask::Run() when its timer fires.
    48  * (The timer can't call back into MessageLoopIdleTask directly since that's
    49  * not a refcounted object; it's owned by the MessageLoop.)
    50  *
    51  * We keep a weak reference to the MessageLoopIdleTask, although a raw pointer
    52  * should in theory suffice: When the MessageLoopIdleTask runs (right before
    53  * the MessageLoop deletes it), it cancels its timer.  But the weak pointer
    54  * saves us from worrying about an edge case somehow messing us up here.
    55  */
    56 class MessageLoopTimerCallback
    57   : public nsITimerCallback
    58 {
    59 public:
    60   MessageLoopTimerCallback(MessageLoopIdleTask* aTask);
    61   virtual ~MessageLoopTimerCallback() {};
    63   NS_DECL_ISUPPORTS
    64   NS_DECL_NSITIMERCALLBACK
    66 private:
    67   WeakPtr<MessageLoopIdleTask> mTask;
    68 };
    70 MessageLoopIdleTask::MessageLoopIdleTask(nsIRunnable* aTask,
    71                                          uint32_t aEnsureRunsAfterMS)
    72   : mTask(aTask)
    73 {
    74   // Init() really shouldn't fail, but if it does, we schedule our runnable
    75   // immediately, because it's more important to guarantee that we run the task
    76   // eventually than it is to run the task when we're idle.
    77   nsresult rv = Init(aEnsureRunsAfterMS);
    78   if (NS_FAILED(rv)) {
    79     NS_WARNING("Running idle task early because we couldn't initialize our timer.");
    80     NS_DispatchToCurrentThread(mTask);
    82     mTask = nullptr;
    83     mTimer = nullptr;
    84   }
    85 }
    87 nsresult
    88 MessageLoopIdleTask::Init(uint32_t aEnsureRunsAfterMS)
    89 {
    90   mTimer = do_CreateInstance("@mozilla.org/timer;1");
    91   if (NS_WARN_IF(!mTimer))
    92     return NS_ERROR_UNEXPECTED;
    94   nsRefPtr<MessageLoopTimerCallback> callback =
    95     new MessageLoopTimerCallback(this);
    97   return mTimer->InitWithCallback(callback, aEnsureRunsAfterMS,
    98                                   nsITimer::TYPE_ONE_SHOT);
    99 }
   101 /* virtual */ void
   102 MessageLoopIdleTask::Run()
   103 {
   104   // Null out our pointers because if Run() was called by the timer, this
   105   // object will be kept alive by the MessageLoop until the MessageLoop calls
   106   // Run().
   108   if (mTimer) {
   109     mTimer->Cancel();
   110     mTimer = nullptr;
   111   }
   113   if (mTask) {
   114     mTask->Run();
   115     mTask = nullptr;
   116   }
   117 }
   119 MessageLoopTimerCallback::MessageLoopTimerCallback(MessageLoopIdleTask* aTask)
   120   : mTask(aTask->asWeakPtr())
   121 {}
   123 NS_IMETHODIMP
   124 MessageLoopTimerCallback::Notify(nsITimer* aTimer)
   125 {
   126   // We don't expect to hit the case when the timer fires but mTask has been
   127   // deleted, because mTask should cancel the timer before the mTask is
   128   // deleted.  But you never know...
   129   NS_WARN_IF_FALSE(mTask, "This timer shouldn't have fired.");
   131   if (mTask) {
   132     mTask->Run();
   133   }
   134   return NS_OK;
   135 }
   137 NS_IMPL_ISUPPORTS(MessageLoopTimerCallback, nsITimerCallback)
   139 } // anonymous namespace
   141 NS_IMPL_ISUPPORTS(nsMessageLoop, nsIMessageLoop)
   143 NS_IMETHODIMP
   144 nsMessageLoop::PostIdleTask(nsIRunnable* aTask, uint32_t aEnsureRunsAfterMS)
   145 {
   146   // The message loop owns MessageLoopIdleTask and deletes it after calling
   147   // Run().  Be careful...
   148   MessageLoop::current()->PostIdleTask(FROM_HERE,
   149     new MessageLoopIdleTask(aTask, aEnsureRunsAfterMS));
   150   return NS_OK;
   151 }
   153 nsresult
   154 nsMessageLoopConstructor(nsISupports* aOuter,
   155                          const nsIID& aIID,
   156                          void** aInstancePtr)
   157 {
   158   if (NS_WARN_IF(aOuter))
   159     return NS_ERROR_NO_AGGREGATION;
   160   nsISupports* messageLoop = new nsMessageLoop();
   161   return messageLoop->QueryInterface(aIID, aInstancePtr);
   162 }

mercurial