xpcom/base/nsMessageLoop.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/xpcom/base/nsMessageLoop.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,162 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsMessageLoop.h"
    1.10 +#include "mozilla/WeakPtr.h"
    1.11 +#include "base/message_loop.h"
    1.12 +#include "base/task.h"
    1.13 +#include "nsIRunnable.h"
    1.14 +#include "nsITimer.h"
    1.15 +#include "nsCOMPtr.h"
    1.16 +#include "nsAutoPtr.h"
    1.17 +#include "nsComponentManagerUtils.h"
    1.18 +#include "nsThreadUtils.h"
    1.19 +
    1.20 +using namespace mozilla;
    1.21 +
    1.22 +namespace {
    1.23 +
    1.24 +/**
    1.25 + * This Task runs its nsIRunnable when Run() is called, or after
    1.26 + * aEnsureRunsAfterMS milliseconds have elapsed since the object was
    1.27 + * constructed.
    1.28 + *
    1.29 + * Note that the MessageLoop owns this object and will delete it after it calls
    1.30 + * Run().  Tread lightly.
    1.31 + */
    1.32 +class MessageLoopIdleTask
    1.33 +  : public Task
    1.34 +  , public SupportsWeakPtr<MessageLoopIdleTask>
    1.35 +{
    1.36 +public:
    1.37 +  MOZ_DECLARE_REFCOUNTED_TYPENAME(MessageLoopIdleTask)
    1.38 +  MessageLoopIdleTask(nsIRunnable* aTask, uint32_t aEnsureRunsAfterMS);
    1.39 +  virtual ~MessageLoopIdleTask() {}
    1.40 +  virtual void Run();
    1.41 +
    1.42 +private:
    1.43 +  nsresult Init(uint32_t aEnsureRunsAfterMS);
    1.44 +
    1.45 +  nsCOMPtr<nsIRunnable> mTask;
    1.46 +  nsCOMPtr<nsITimer> mTimer;
    1.47 +};
    1.48 +
    1.49 +/**
    1.50 + * This timer callback calls MessageLoopIdleTask::Run() when its timer fires.
    1.51 + * (The timer can't call back into MessageLoopIdleTask directly since that's
    1.52 + * not a refcounted object; it's owned by the MessageLoop.)
    1.53 + *
    1.54 + * We keep a weak reference to the MessageLoopIdleTask, although a raw pointer
    1.55 + * should in theory suffice: When the MessageLoopIdleTask runs (right before
    1.56 + * the MessageLoop deletes it), it cancels its timer.  But the weak pointer
    1.57 + * saves us from worrying about an edge case somehow messing us up here.
    1.58 + */
    1.59 +class MessageLoopTimerCallback
    1.60 +  : public nsITimerCallback
    1.61 +{
    1.62 +public:
    1.63 +  MessageLoopTimerCallback(MessageLoopIdleTask* aTask);
    1.64 +  virtual ~MessageLoopTimerCallback() {};
    1.65 +
    1.66 +  NS_DECL_ISUPPORTS
    1.67 +  NS_DECL_NSITIMERCALLBACK
    1.68 +
    1.69 +private:
    1.70 +  WeakPtr<MessageLoopIdleTask> mTask;
    1.71 +};
    1.72 +
    1.73 +MessageLoopIdleTask::MessageLoopIdleTask(nsIRunnable* aTask,
    1.74 +                                         uint32_t aEnsureRunsAfterMS)
    1.75 +  : mTask(aTask)
    1.76 +{
    1.77 +  // Init() really shouldn't fail, but if it does, we schedule our runnable
    1.78 +  // immediately, because it's more important to guarantee that we run the task
    1.79 +  // eventually than it is to run the task when we're idle.
    1.80 +  nsresult rv = Init(aEnsureRunsAfterMS);
    1.81 +  if (NS_FAILED(rv)) {
    1.82 +    NS_WARNING("Running idle task early because we couldn't initialize our timer.");
    1.83 +    NS_DispatchToCurrentThread(mTask);
    1.84 +
    1.85 +    mTask = nullptr;
    1.86 +    mTimer = nullptr;
    1.87 +  }
    1.88 +}
    1.89 +
    1.90 +nsresult
    1.91 +MessageLoopIdleTask::Init(uint32_t aEnsureRunsAfterMS)
    1.92 +{
    1.93 +  mTimer = do_CreateInstance("@mozilla.org/timer;1");
    1.94 +  if (NS_WARN_IF(!mTimer))
    1.95 +    return NS_ERROR_UNEXPECTED;
    1.96 +
    1.97 +  nsRefPtr<MessageLoopTimerCallback> callback =
    1.98 +    new MessageLoopTimerCallback(this);
    1.99 +
   1.100 +  return mTimer->InitWithCallback(callback, aEnsureRunsAfterMS,
   1.101 +                                  nsITimer::TYPE_ONE_SHOT);
   1.102 +}
   1.103 +
   1.104 +/* virtual */ void
   1.105 +MessageLoopIdleTask::Run()
   1.106 +{
   1.107 +  // Null out our pointers because if Run() was called by the timer, this
   1.108 +  // object will be kept alive by the MessageLoop until the MessageLoop calls
   1.109 +  // Run().
   1.110 +
   1.111 +  if (mTimer) {
   1.112 +    mTimer->Cancel();
   1.113 +    mTimer = nullptr;
   1.114 +  }
   1.115 +
   1.116 +  if (mTask) {
   1.117 +    mTask->Run();
   1.118 +    mTask = nullptr;
   1.119 +  }
   1.120 +}
   1.121 +
   1.122 +MessageLoopTimerCallback::MessageLoopTimerCallback(MessageLoopIdleTask* aTask)
   1.123 +  : mTask(aTask->asWeakPtr())
   1.124 +{}
   1.125 +
   1.126 +NS_IMETHODIMP
   1.127 +MessageLoopTimerCallback::Notify(nsITimer* aTimer)
   1.128 +{
   1.129 +  // We don't expect to hit the case when the timer fires but mTask has been
   1.130 +  // deleted, because mTask should cancel the timer before the mTask is
   1.131 +  // deleted.  But you never know...
   1.132 +  NS_WARN_IF_FALSE(mTask, "This timer shouldn't have fired.");
   1.133 +
   1.134 +  if (mTask) {
   1.135 +    mTask->Run();
   1.136 +  }
   1.137 +  return NS_OK;
   1.138 +}
   1.139 +
   1.140 +NS_IMPL_ISUPPORTS(MessageLoopTimerCallback, nsITimerCallback)
   1.141 +
   1.142 +} // anonymous namespace
   1.143 +
   1.144 +NS_IMPL_ISUPPORTS(nsMessageLoop, nsIMessageLoop)
   1.145 +
   1.146 +NS_IMETHODIMP
   1.147 +nsMessageLoop::PostIdleTask(nsIRunnable* aTask, uint32_t aEnsureRunsAfterMS)
   1.148 +{
   1.149 +  // The message loop owns MessageLoopIdleTask and deletes it after calling
   1.150 +  // Run().  Be careful...
   1.151 +  MessageLoop::current()->PostIdleTask(FROM_HERE,
   1.152 +    new MessageLoopIdleTask(aTask, aEnsureRunsAfterMS));
   1.153 +  return NS_OK;
   1.154 +}
   1.155 +
   1.156 +nsresult
   1.157 +nsMessageLoopConstructor(nsISupports* aOuter,
   1.158 +                         const nsIID& aIID,
   1.159 +                         void** aInstancePtr)
   1.160 +{
   1.161 +  if (NS_WARN_IF(aOuter))
   1.162 +    return NS_ERROR_NO_AGGREGATION;
   1.163 +  nsISupports* messageLoop = new nsMessageLoop();
   1.164 +  return messageLoop->QueryInterface(aIID, aInstancePtr);
   1.165 +}

mercurial