Bug 1213517 - split off MediaTaskUtils.h from MediaUtils.h to shed dependencies. r=jesup
☠☠ backed out by c292ec33315d ☠ ☠
authorJan-Ivar Bruaroey <jib@mozilla.com>
Wed, 18 Nov 2015 22:40:41 -0500
changeset 330303 3764e2fac76589db751cb980b585df99ec7d3556
parent 330302 f22693a94979d311cda86e948e2ef58929e71932
child 330304 015cb0829df5342ea5ec9b4c4d5ca10abba8bb52
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs1213517
milestone50.0a1
Bug 1213517 - split off MediaTaskUtils.h from MediaUtils.h to shed dependencies. r=jesup MozReview-Commit-ID: DQz12SN0SU1
dom/media/MediaManager.cpp
dom/media/systemservices/MediaTaskUtils.h
dom/media/systemservices/MediaUtils.h
dom/media/systemservices/moz.build
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -42,16 +42,17 @@
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/MediaStreamBinding.h"
 #include "mozilla/dom/MediaStreamTrackBinding.h"
 #include "mozilla/dom/GetUserMediaRequestBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/Base64.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/media/MediaChild.h"
+#include "mozilla/media/MediaTaskUtils.h"
 #include "MediaTrackConstraints.h"
 #include "VideoUtils.h"
 #include "Latency.h"
 #include "nsProxyRelease.h"
 #include "nsNullPrincipal.h"
 #include "nsVariant.h"
 
 // For snprintf
copy from dom/media/systemservices/MediaUtils.h
copy to dom/media/systemservices/MediaTaskUtils.h
--- a/dom/media/systemservices/MediaUtils.h
+++ b/dom/media/systemservices/MediaTaskUtils.h
@@ -1,217 +1,30 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et ft=cpp : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef mozilla_MediaUtils_h
-#define mozilla_MediaUtils_h
+#ifndef mozilla_MediaTaskUtils_h
+#define mozilla_MediaTaskUtils_h
 
 #include "nsThreadUtils.h"
-#include "nsIAsyncShutdown.h"
-#include "mozilla/UniquePtr.h"
+
+// The main reason this file is separate from MediaUtils.h
 #include "base/task.h"
 
 namespace mozilla {
 namespace media {
 
-/*
- * media::Pledge - A promise-like pattern for c++ that takes lambda functions.
- *
- * Asynchronous APIs that proxy to another thread or to the chrome process and
- * back may find it useful to return a pledge to callers who then use
- * pledge.Then(func) to specify a lambda function to be invoked with the result
- * later back on this same thread.
- *
- * Callers will enjoy that lambdas allow "capturing" of local variables, much
- * like closures in JavaScript (safely by-copy by default).
+/* media::NewTaskFrom() - Create a Task from a lambda.
  *
- * Callers will also enjoy that they do not need to be thread-safe (their code
- * runs on the same thread after all).
- *
- * Advantageously, pledges are non-threadsafe by design (because locking and
- * event queues are redundant). This means none of the lambdas you pass in,
- * or variables you lambda-capture into them, need be threasafe or support
- * threadsafe refcounting. After all, they'll run later on the same thread.
- *
- *   RefPtr<media::Pledge<Foo>> p = GetFooAsynchronously(); // returns a pledge
- *   p->Then([](const Foo& foo) {
- *     // use foo here (same thread. Need not be thread-safe!)
- *   });
- *
- * See media::CoatCheck below for an example of GetFooAsynchronously().
+ * Similar to media::NewRunnableFrom() - Create an nsRunnable from a lambda.
  */
 
-class PledgeBase
-{
-public:
-  NS_INLINE_DECL_REFCOUNTING(PledgeBase);
-protected:
-  virtual ~PledgeBase() {};
-};
-
-template<typename ValueType, typename ErrorType = nsresult>
-class Pledge : public PledgeBase
-{
-  // TODO: Remove workaround once mozilla allows std::function from <functional>
-  // wo/std::function support, do template + virtual trick to accept lambdas
-  class FunctorsBase
-  {
-  public:
-    FunctorsBase() {}
-    virtual void Succeed(ValueType& result) = 0;
-    virtual void Fail(ErrorType& error) = 0;
-    virtual ~FunctorsBase() {};
-  };
-
-public:
-  explicit Pledge() : mDone(false), mRejected(false) {}
-  Pledge(const Pledge& aOther) = delete;
-  Pledge& operator = (const Pledge&) = delete;
-
-  template<typename OnSuccessType>
-  void Then(OnSuccessType&& aOnSuccess)
-  {
-    Then(Forward<OnSuccessType>(aOnSuccess), [](ErrorType&){});
-  }
-
-  template<typename OnSuccessType, typename OnFailureType>
-  void Then(OnSuccessType&& aOnSuccess, OnFailureType&& aOnFailure)
-  {
-    class Functors : public FunctorsBase
-    {
-    public:
-      Functors(OnSuccessType&& aOnSuccessRef, OnFailureType&& aOnFailureRef)
-        : mOnSuccess(Move(aOnSuccessRef)), mOnFailure(Move(aOnFailureRef)) {}
-
-      void Succeed(ValueType& result)
-      {
-        mOnSuccess(result);
-      }
-      void Fail(ErrorType& error)
-      {
-        mOnFailure(error);
-      };
-
-      OnSuccessType mOnSuccess;
-      OnFailureType mOnFailure;
-    };
-    mFunctors = MakeUnique<Functors>(Forward<OnSuccessType>(aOnSuccess),
-                                     Forward<OnFailureType>(aOnFailure));
-    if (mDone) {
-      if (!mRejected) {
-        mFunctors->Succeed(mValue);
-      } else {
-        mFunctors->Fail(mError);
-      }
-    }
-  }
-
-  void Resolve(const ValueType& aValue)
-  {
-    mValue = aValue;
-    Resolve();
-  }
-
-  void Reject(ErrorType rv)
-  {
-    if (!mDone) {
-      mDone = mRejected = true;
-      mError = rv;
-      if (mFunctors) {
-        mFunctors->Fail(mError);
-      }
-    }
-  }
-
-protected:
-  void Resolve()
-  {
-    if (!mDone) {
-      mDone = true;
-      MOZ_ASSERT(!mRejected);
-      if (mFunctors) {
-        mFunctors->Succeed(mValue);
-      }
-    }
-  }
-
-  ValueType mValue;
-private:
-  ~Pledge() {};
-  bool mDone;
-  bool mRejected;
-  ErrorType mError;
-  UniquePtr<FunctorsBase> mFunctors;
-};
-
-/* media::NewRunnableFrom() - Create a Runnable from a lambda.
- * media::NewTaskFrom()     - Create a Task from a lambda.
- *
- * Passing variables (closures) to an async function is clunky with Runnable:
- *
- *   void Foo()
- *   {
- *     class FooRunnable : public Runnable
- *     {
- *     public:
- *       FooRunnable(const Bar &aBar) : mBar(aBar) {}
- *       NS_IMETHOD Run()
- *       {
- *         // Use mBar
- *       }
- *     private:
- *       RefPtr<Bar> mBar;
- *     };
- *
- *     RefPtr<Bar> bar = new Bar();
- *     NS_DispatchToMainThread(new FooRunnable(bar);
- *   }
- *
- * It's worse with more variables. Lambdas have a leg up with variable capture:
- *
- *   void Foo()
- *   {
- *     RefPtr<Bar> bar = new Bar();
- *     NS_DispatchToMainThread(media::NewRunnableFrom([bar]() mutable {
- *       // use bar
- *     });
- *   }
- *
- * Capture is by-copy by default, so the nsRefPtr 'bar' is safely copied for
- * access on the other thread (threadsafe refcounting in bar is assumed).
- *
- * The 'mutable' keyword is only needed for non-const access to bar.
- */
-
-template<typename OnRunType>
-class LambdaRunnable : public Runnable
-{
-public:
-  explicit LambdaRunnable(OnRunType&& aOnRun) : mOnRun(Move(aOnRun)) {}
-private:
-  NS_IMETHODIMP
-  Run()
-  {
-    return mOnRun();
-  }
-  OnRunType mOnRun;
-};
-
-template<typename OnRunType>
-already_AddRefed<LambdaRunnable<OnRunType>>
-NewRunnableFrom(OnRunType&& aOnRun)
-{
-  typedef LambdaRunnable<OnRunType> LambdaType;
-  RefPtr<LambdaType> lambda = new LambdaType(Forward<OnRunType>(aOnRun));
-  return lambda.forget();
-}
-
 template<typename OnRunType>
 class LambdaTask : public Runnable
 {
 public:
   explicit LambdaTask(OnRunType&& aOnRun) : mOnRun(Move(aOnRun)) {}
 private:
   NS_IMETHOD
   Run() override
@@ -226,174 +39,12 @@ template<typename OnRunType>
 already_AddRefed<LambdaTask<OnRunType>>
 NewTaskFrom(OnRunType&& aOnRun)
 {
   typedef LambdaTask<OnRunType> LambdaType;
   RefPtr<LambdaType> lambda = new LambdaType(Forward<OnRunType>(aOnRun));
   return lambda.forget();
 }
 
-/* media::CoatCheck - There and back again. Park an object in exchange for an id.
- *
- * A common problem with calling asynchronous functions that do work on other
- * threads or processes is how to pass in a heap object for use once the
- * function completes, without requiring that object to have threadsafe
- * refcounting, contain mutexes, be marshaled, or leak if things fail
- * (or worse, intermittent use-after-free because of lifetime issues).
- *
- * One solution is to set up a coat-check on the caller side, park your object
- * in exchange for an id, and send the id. Common in IPC, but equally useful
- * for same-process thread-hops, because by never leaving the thread there's
- * no need for objects to be threadsafe or use threadsafe refcounting. E.g.
- *
- *   class FooDoer
- *   {
- *     CoatCheck<Foo> mOutstandingFoos;
- *
- *   public:
- *     void DoFoo()
- *     {
- *       RefPtr<Foo> foo = new Foo();
- *       uint32_t requestId = mOutstandingFoos.Append(*foo);
- *       sChild->SendFoo(requestId);
- *     }
- *
- *     void RecvFooResponse(uint32_t requestId)
- *     {
- *       RefPtr<Foo> foo = mOutstandingFoos.Remove(requestId);
- *       if (foo) {
- *         // use foo
- *       }
- *     }
- *   };
- *
- * If you read media::Pledge earlier, here's how this is useful for pledges:
- *
- *   class FooGetter
- *   {
- *     CoatCheck<Pledge<Foo>> mOutstandingPledges;
- *
- *   public:
- *     already_addRefed<Pledge<Foo>> GetFooAsynchronously()
- *     {
- *       RefPtr<Pledge<Foo>> p = new Pledge<Foo>();
- *       uint32_t requestId = mOutstandingPledges.Append(*p);
- *       sChild->SendFoo(requestId);
- *       return p.forget();
- *     }
- *
- *     void RecvFooResponse(uint32_t requestId, const Foo& fooResult)
- *     {
- *       RefPtr<Foo> p = mOutstandingPledges.Remove(requestId);
- *       if (p) {
- *         p->Resolve(fooResult);
- *       }
- *     }
- *   };
- *
- * This helper is currently optimized for very small sets (i.e. not optimized).
- * It is also not thread-safe as the whole point is to stay on the same thread.
- */
-
-template<class T>
-class CoatCheck
-{
-public:
-  typedef std::pair<uint32_t, RefPtr<T>> Element;
-
-  uint32_t Append(T& t)
-  {
-    uint32_t id = GetNextId();
-    mElements.AppendElement(Element(id, RefPtr<T>(&t)));
-    return id;
-  }
-
-  already_AddRefed<T> Remove(uint32_t aId)
-  {
-    for (auto& element : mElements) {
-      if (element.first == aId) {
-        RefPtr<T> ref;
-        ref.swap(element.second);
-        mElements.RemoveElement(element);
-        return ref.forget();
-      }
-    }
-    MOZ_ASSERT_UNREACHABLE("Received id with no matching parked object!");
-    return nullptr;
-  }
-
-private:
-  static uint32_t GetNextId()
-  {
-    static uint32_t counter = 0;
-    return ++counter;
-  };
-  AutoTArray<Element, 3> mElements;
-};
-
-/* media::Refcountable - Add threadsafe ref-counting to something that isn't.
- *
- * Often, reference counting is the most practical way to share an object with
- * another thread without imposing lifetime restrictions, even if there's
- * otherwise no concurrent access happening on the object.  For instance, an
- * algorithm on another thread may find it more expedient to modify a passed-in
- * object, rather than pass expensive copies back and forth.
- *
- * Lists in particular often aren't ref-countable, yet are expensive to copy,
- * e.g. nsTArray<RefPtr<Foo>>. Refcountable can be used to make such objects
- * (or owning smart-pointers to such objects) refcountable.
- *
- * Technical limitation: A template specialization is needed for types that take
- * a constructor. Please add below (UniquePtr covers a lot of ground though).
- */
-
-template<typename T>
-class Refcountable : public T
-{
-public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Refcountable<T>)
-private:
-  ~Refcountable<T>() {}
-};
-
-template<typename T>
-class Refcountable<UniquePtr<T>> : public UniquePtr<T>
-{
-public:
-  explicit Refcountable<UniquePtr<T>>(T* aPtr) : UniquePtr<T>(aPtr) {}
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Refcountable<T>)
-private:
-  ~Refcountable<UniquePtr<T>>() {}
-};
-
-/* media::ShutdownBlocker - Async shutdown helper.
- */
-
-class ShutdownBlocker : public nsIAsyncShutdownBlocker
-{
-public:
-  ShutdownBlocker(const nsString& aName) : mName(aName) {}
-
-  NS_IMETHOD
-  BlockShutdown(nsIAsyncShutdownClient* aProfileBeforeChange) override = 0;
-
-  NS_IMETHOD GetName(nsAString& aName) override
-  {
-    aName = mName;
-    return NS_OK;
-  }
-
-  NS_IMETHOD GetState(nsIPropertyBag**) override
-  {
-    return NS_OK;
-  }
-
-  NS_DECL_ISUPPORTS
-protected:
-  virtual ~ShutdownBlocker() {}
-private:
-  const nsString mName;
-};
-
 } // namespace media
 } // namespace mozilla
 
-#endif // mozilla_MediaUtils_h
+#endif // mozilla_MediaTaskUtils_h
--- a/dom/media/systemservices/MediaUtils.h
+++ b/dom/media/systemservices/MediaUtils.h
@@ -5,17 +5,16 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_MediaUtils_h
 #define mozilla_MediaUtils_h
 
 #include "nsThreadUtils.h"
 #include "nsIAsyncShutdown.h"
 #include "mozilla/UniquePtr.h"
-#include "base/task.h"
 
 namespace mozilla {
 namespace media {
 
 /*
  * media::Pledge - A promise-like pattern for c++ that takes lambda functions.
  *
  * Asynchronous APIs that proxy to another thread or to the chrome process and
@@ -141,17 +140,16 @@ private:
   ~Pledge() {};
   bool mDone;
   bool mRejected;
   ErrorType mError;
   UniquePtr<FunctorsBase> mFunctors;
 };
 
 /* media::NewRunnableFrom() - Create a Runnable from a lambda.
- * media::NewTaskFrom()     - Create a Task from a lambda.
  *
  * Passing variables (closures) to an async function is clunky with Runnable:
  *
  *   void Foo()
  *   {
  *     class FooRunnable : public Runnable
  *     {
  *     public:
@@ -202,40 +200,16 @@ template<typename OnRunType>
 already_AddRefed<LambdaRunnable<OnRunType>>
 NewRunnableFrom(OnRunType&& aOnRun)
 {
   typedef LambdaRunnable<OnRunType> LambdaType;
   RefPtr<LambdaType> lambda = new LambdaType(Forward<OnRunType>(aOnRun));
   return lambda.forget();
 }
 
-template<typename OnRunType>
-class LambdaTask : public Runnable
-{
-public:
-  explicit LambdaTask(OnRunType&& aOnRun) : mOnRun(Move(aOnRun)) {}
-private:
-  NS_IMETHOD
-  Run() override
-  {
-    mOnRun();
-    return NS_OK;
-  }
-  OnRunType mOnRun;
-};
-
-template<typename OnRunType>
-already_AddRefed<LambdaTask<OnRunType>>
-NewTaskFrom(OnRunType&& aOnRun)
-{
-  typedef LambdaTask<OnRunType> LambdaType;
-  RefPtr<LambdaType> lambda = new LambdaType(Forward<OnRunType>(aOnRun));
-  return lambda.forget();
-}
-
 /* media::CoatCheck - There and back again. Park an object in exchange for an id.
  *
  * A common problem with calling asynchronous functions that do work on other
  * threads or processes is how to pass in a heap object for use once the
  * function completes, without requiring that object to have threadsafe
  * refcounting, contain mutexes, be marshaled, or leak if things fail
  * (or worse, intermittent use-after-free because of lifetime issues).
  *
--- a/dom/media/systemservices/moz.build
+++ b/dom/media/systemservices/moz.build
@@ -66,16 +66,17 @@ EXPORTS.mozilla.media += ['MediaChild.h'
                           'MediaParent.h',
                           'MediaSystemResourceClient.h',
                           'MediaSystemResourceManager.h',
                           'MediaSystemResourceManagerChild.h',
                           'MediaSystemResourceManagerParent.h',
                           'MediaSystemResourceMessageUtils.h',
                           'MediaSystemResourceService.h',
                           'MediaSystemResourceTypes.h',
+                          'MediaTaskUtils.h',
                           'MediaUtils.h',
 ]
 UNIFIED_SOURCES += [
     'MediaChild.cpp',
     'MediaParent.cpp',
     'MediaSystemResourceClient.cpp',
     'MediaSystemResourceManager.cpp',
     'MediaSystemResourceManagerChild.cpp',