Bug 1360423 - backout P5 and P2 from bug 1281090. draft
authorJW Wang <jwwang@mozilla.com>
Fri, 28 Apr 2017 11:28:13 +0800
changeset 570750 ef38d8187aeaf9b936d346a68447e38b80488093
parent 570749 1f225d7ba700a1b87b846973640d45d480447276
child 626559 6b98e51144432749b3650f311a11a67efe0be799
push id56566
push userjwwang@mozilla.com
push dateSun, 30 Apr 2017 13:38:48 +0000
bugs1360423, 1281090
milestone55.0a1
Bug 1360423 - backout P5 and P2 from bug 1281090. It turns out that sync notification is a bad idea which is easy to be misused and could results in unexpected reentrant call flow. Since it has no users after the mass media code refactoring, it is good to remove it now to prevent future users. Backed out changeset fb5b05298007 Backed out changeset 9e1fb308cf51 MozReview-Commit-ID: 9WGvRCbvJhQ
dom/media/MediaEventSource.h
--- a/dom/media/MediaEventSource.h
+++ b/dom/media/MediaEventSource.h
@@ -53,21 +53,16 @@ enum class ListenerPolicy : int8_t {
   // Allow at most one listener. Move will be used when possible
   // to pass the event data to save copy.
   Exclusive,
   // Allow multiple listeners. Event data will always be copied when passed
   // to the listeners.
   NonExclusive
 };
 
-enum class DispatchPolicy : int8_t {
-  Sync, // Events are passed synchronously to the listeners.
-  Async // Events are passed asynchronously to the listeners.
-};
-
 namespace detail {
 
 /**
  * Define how an event type is passed internally in MediaEventSource and to the
  * listeners. Specialized for the void type to pass a dummy bool instead.
  */
 template <typename T>
 struct EventTypeTraits {
@@ -92,59 +87,34 @@ class TakeArgsHelper {
   static TrueType test(...);
 public:
   typedef decltype(test(DeclVal<T>(), 0)) Type;
 };
 
 template <typename T>
 struct TakeArgs : public TakeArgsHelper<T>::Type {};
 
-template <DispatchPolicy Dp, typename T> struct EventTarget;
+template <typename T> struct EventTarget;
 
 template <>
-struct EventTarget<DispatchPolicy::Async, nsIEventTarget> {
+struct EventTarget<nsIEventTarget> {
   static void
   Dispatch(nsIEventTarget* aTarget, already_AddRefed<nsIRunnable> aTask) {
     aTarget->Dispatch(Move(aTask), NS_DISPATCH_NORMAL);
   }
 };
 
 template <>
-struct EventTarget<DispatchPolicy::Async, AbstractThread> {
+struct EventTarget<AbstractThread> {
   static void
   Dispatch(AbstractThread* aTarget, already_AddRefed<nsIRunnable> aTask) {
     aTarget->Dispatch(Move(aTask), AbstractThread::DontAssertDispatchSuccess);
   }
 };
 
-template <>
-struct EventTarget<DispatchPolicy::Sync, nsIEventTarget> {
-  static bool IsOnCurrentThread(nsIEventTarget* aTarget) {
-    bool current = false;
-    auto rv = aTarget->IsOnCurrentThread(&current);
-    return NS_SUCCEEDED(rv) && current;
-  }
-  static void
-  Dispatch(nsIEventTarget* aTarget, already_AddRefed<nsIRunnable> aTask) {
-    MOZ_ASSERT(IsOnCurrentThread(aTarget));
-    nsCOMPtr<nsIRunnable> r = aTask;
-    r->Run();
-  }
-};
-
-template <>
-struct EventTarget<DispatchPolicy::Sync, AbstractThread> {
-  static void
-  Dispatch(AbstractThread* aTarget, already_AddRefed<nsIRunnable> aTask) {
-    MOZ_ASSERT(aTarget->IsCurrentThreadIn());
-    nsCOMPtr<nsIRunnable> r = aTask;
-    r->Run();
-  }
-};
-
 /**
  * Encapsulate a raw pointer to be captured by a lambda without causing
  * static-analysis errors.
  */
 template <typename T>
 class RawPtr {
 public:
   explicit RawPtr(T* aPtr) : mPtr(aPtr) {}
@@ -152,17 +122,17 @@ public:
 private:
   T* const mPtr;
 };
 
 /**
  * A helper class to pass event data to the listeners. Optimized to save
  * copy when Move is possible or |Function| takes no arguments.
  */
-template<DispatchPolicy Dp, typename Target, typename Function>
+template<typename Target, typename Function>
 class ListenerHelper {
   // Define our custom runnable to minimize copy of the event data.
   // NS_NewRunnableFunction will result in 2 copies of the event data.
   // One is captured by the lambda and the other is the copy of the lambda.
   template <typename... Ts>
   class R : public Runnable {
   public:
     template <typename... Us>
@@ -199,31 +169,31 @@ public:
     : mToken(aToken), mTarget(aTarget), mFunction(aFunc) {}
 
   // |F| takes one or more arguments.
   template <typename F, typename... Ts>
   typename EnableIf<TakeArgs<F>::value, void>::Type
   DispatchHelper(const F& aFunc, Ts&&... aEvents) {
     nsCOMPtr<nsIRunnable> r =
       new R<Ts...>(mToken, aFunc, Forward<Ts>(aEvents)...);
-    EventTarget<Dp, Target>::Dispatch(mTarget.get(), r.forget());
+    EventTarget<Target>::Dispatch(mTarget.get(), r.forget());
   }
 
   // |F| takes no arguments. Don't bother passing aEvent.
   template <typename F, typename... Ts>
   typename EnableIf<!TakeArgs<F>::value, void>::Type
   DispatchHelper(const F& aFunc, Ts&&...) {
     const RefPtr<RevocableToken>& token = mToken;
     nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
       // Don't call the listener if it is disconnected.
       if (!token->IsRevoked()) {
         aFunc();
       }
     });
-    EventTarget<Dp, Target>::Dispatch(mTarget.get(), r.forget());
+    EventTarget<Target>::Dispatch(mTarget.get(), r.forget());
   }
 
   template <typename... Ts>
   void Dispatch(Ts&&... aEvents) {
     DispatchHelper(mFunction, Forward<Ts>(aEvents)...);
   }
 
 private:
@@ -274,40 +244,39 @@ public:
   virtual ~Listener() {}
   virtual void Dispatch(As... aEvents) = 0;
 };
 
 /**
  * Store the registered target thread and function so it knows where and to
  * whom to send the event data.
  */
-template <DispatchPolicy Dp, typename Target,
-          typename Function, EventPassMode, typename... As>
+template <typename Target, typename Function, EventPassMode, typename... As>
 class ListenerImpl : public Listener<EventPassMode::Copy, As...> {
 public:
   ListenerImpl(Target* aTarget, const Function& aFunction)
     : mHelper(ListenerBase::Token(), aTarget, aFunction) {}
   void Dispatch(const As&... aEvents) override {
     mHelper.Dispatch(aEvents...);
   }
 private:
-  ListenerHelper<Dp, Target, Function> mHelper;
+  ListenerHelper<Target, Function> mHelper;
 };
 
-template <DispatchPolicy Dp, typename Target, typename Function, typename... As>
-class ListenerImpl<Dp, Target, Function, EventPassMode::Move, As...>
+template <typename Target, typename Function, typename... As>
+class ListenerImpl<Target, Function, EventPassMode::Move, As...>
   : public Listener<EventPassMode::Move, As...> {
 public:
   ListenerImpl(Target* aTarget, const Function& aFunction)
     : mHelper(ListenerBase::Token(), aTarget, aFunction) {}
   void Dispatch(As... aEvents) override {
     mHelper.Dispatch(Move(aEvents)...);
   }
 private:
-  ListenerHelper<Dp, Target, Function> mHelper;
+  ListenerHelper<Target, Function> mHelper;
 };
 
 /**
  * Select EventPassMode based on ListenerPolicy.
  *
  * @Copy Selected when ListenerPolicy is NonExclusive because each listener
  * must get a copy.
  *
@@ -332,27 +301,26 @@ struct IsAnyReference {
 
 template <typename T>
 struct IsAnyReference<T> {
   static const bool value = IsReference<T>::value;
 };
 
 } // namespace detail
 
-template <DispatchPolicy, ListenerPolicy, typename... Ts>
-class MediaEventSourceImpl;
+template <ListenerPolicy, typename... Ts> class MediaEventSourceImpl;
 
 /**
  * Not thread-safe since this is not meant to be shared and therefore only
  * move constructor is provided. Used to hold the result of
  * MediaEventSource<T>::Connect() and call Disconnect() to disconnect the
  * listener from an event source.
  */
 class MediaEventListener {
-  template <DispatchPolicy, ListenerPolicy, typename... Ts>
+  template <ListenerPolicy, typename... Ts>
   friend class MediaEventSourceImpl;
 
 public:
   MediaEventListener() {}
 
   MediaEventListener(MediaEventListener&& aOther)
     : mToken(Move(aOther.mToken)) {}
 
@@ -382,32 +350,32 @@ private:
   // listeners can be disconnected in a controlled manner.
   explicit MediaEventListener(RevocableToken* aToken) : mToken(aToken) {}
   RefPtr<RevocableToken> mToken;
 };
 
 /**
  * A generic and thread-safe class to implement the observer pattern.
  */
-template <DispatchPolicy Dp, ListenerPolicy Lp, typename... Es>
+template <ListenerPolicy Lp, typename... Es>
 class MediaEventSourceImpl {
   static_assert(!detail::IsAnyReference<Es...>::value,
                 "Ref-type not supported!");
 
   template <typename T>
   using ArgType = typename detail::EventTypeTraits<T>::ArgType;
 
   static const detail::EventPassMode PassMode =
     detail::PassModePicker<Lp>::Value;
 
   typedef detail::Listener<PassMode, ArgType<Es>...> Listener;
 
   template<typename Target, typename Func>
   using ListenerImpl =
-    detail::ListenerImpl<Dp, Target, Func, PassMode, ArgType<Es>...>;
+    detail::ListenerImpl<Target, Func, PassMode, ArgType<Es>...>;
 
   template <typename Method>
   using TakeArgs = detail::TakeArgs<Method>;
 
   void PruneListeners() {
     int32_t last = static_cast<int32_t>(mListeners.Length()) - 1;
     for (int32_t i = last; i >= 0; --i) {
       if (mListeners[i]->Token()->IsRevoked()) {
@@ -491,128 +459,78 @@ public:
   MediaEventListener
   Connect(nsIEventTarget* aTarget, This* aThis, Method aMethod) {
     return ConnectInternal(aTarget, aThis, aMethod);
   }
 
 protected:
   MediaEventSourceImpl() : mMutex("MediaEventSourceImpl::mMutex") {}
 
-  template <DispatchPolicy P, typename... Ts>
-  typename EnableIf<P == DispatchPolicy::Async, void>::Type
-  NotifyInternal(IntegralConstant<DispatchPolicy, P>, Ts&&... aEvents) {
+  template <typename... Ts>
+  void NotifyInternal(Ts&&... aEvents) {
     MutexAutoLock lock(mMutex);
     int32_t last = static_cast<int32_t>(mListeners.Length()) - 1;
     for (int32_t i = last; i >= 0; --i) {
       auto&& l = mListeners[i];
       // Remove disconnected listeners.
       // It is not optimal but is simple and works well.
       if (l->Token()->IsRevoked()) {
         mListeners.RemoveElementAt(i);
         continue;
       }
       l->Dispatch(Forward<Ts>(aEvents)...);
     }
   }
 
-  template <DispatchPolicy P, typename... Ts>
-  typename EnableIf<P == DispatchPolicy::Sync, void>::Type
-  NotifyInternal(IntegralConstant<DispatchPolicy, P>, Ts&&... aEvents) {
-    // Move |mListeners| to a new container before iteration to prevent
-    // |mListeners| from being disrupted if the listener calls Connect() to
-    // modify |mListeners| in the callback function.
-    nsTArray<UniquePtr<Listener>> listeners;
-    listeners.SwapElements(mListeners);
-    for (auto&& l : listeners) {
-      l->Dispatch(Forward<Ts>(aEvents)...);
-    }
-    PruneListeners();
-    // Move remaining listeners back to |mListeners|.
-    for (auto&& l : listeners) {
-      if (!l->Token()->IsRevoked()) {
-        mListeners.AppendElement(Move(l));
-      }
-    }
-    // Perform sanity checks.
-    MOZ_ASSERT(Lp == ListenerPolicy::NonExclusive || mListeners.Length() <= 1);
-  }
-
-  template <typename... Ts>
-  void Notify(Ts&&... aEvents) {
-    NotifyInternal(IntegralConstant<DispatchPolicy, Dp>(),
-                   Forward<Ts>(aEvents)...);
-  }
-
 private:
   Mutex mMutex;
   nsTArray<UniquePtr<Listener>> mListeners;
 };
 
 template <typename... Es>
 using MediaEventSource =
-  MediaEventSourceImpl<DispatchPolicy::Async,
-                       ListenerPolicy::NonExclusive, Es...>;
+  MediaEventSourceImpl<ListenerPolicy::NonExclusive, Es...>;
 
 template <typename... Es>
 using MediaEventSourceExc =
-  MediaEventSourceImpl<DispatchPolicy::Async, ListenerPolicy::Exclusive, Es...>;
+  MediaEventSourceImpl<ListenerPolicy::Exclusive, Es...>;
 
 /**
  * A class to separate the interface of event subject (MediaEventSource)
  * and event publisher. Mostly used as a member variable to publish events
  * to the listeners.
  */
 template <typename... Es>
 class MediaEventProducer : public MediaEventSource<Es...> {
 public:
-  using MediaEventSource<Es...>::Notify;
+  template <typename... Ts>
+  void Notify(Ts&&... aEvents) {
+    this->NotifyInternal(Forward<Ts>(aEvents)...);
+  }
 };
 
 /**
  * Specialization for void type. A dummy bool is passed to NotifyInternal
  * since there is no way to pass a void value.
  */
 template <>
 class MediaEventProducer<void> : public MediaEventSource<void> {
 public:
   void Notify() {
-    MediaEventSource<void>::Notify(false /* dummy */);
+    this->NotifyInternal(true /* dummy */);
   }
 };
 
 /**
  * A producer allowing at most one listener.
  */
 template <typename... Es>
 class MediaEventProducerExc : public MediaEventSourceExc<Es...> {
 public:
-  using MediaEventSourceExc<Es...>::Notify;
-};
-
-/**
- * Events are passed directly to the callback function of the listeners without
- * dispatching. Note this class is not thread-safe. Both Connect() and Notify()
- * must be called on the same thread.
- */
-template <typename... Es>
-class MediaCallback
-  : public MediaEventSourceImpl<DispatchPolicy::Sync,
-                                ListenerPolicy::NonExclusive, Es...> {
-public:
-  using MediaEventSourceImpl<DispatchPolicy::Sync,
-                             ListenerPolicy::NonExclusive, Es...>::Notify;
-};
-
-/**
- * A special version of MediaCallback which allows at most one listener.
- */
-template <typename... Es>
-class MediaCallbackExc
-  : public MediaEventSourceImpl<DispatchPolicy::Sync,
-                                ListenerPolicy::Exclusive, Es...> {
-public:
-  using MediaEventSourceImpl<DispatchPolicy::Sync,
-                             ListenerPolicy::Exclusive, Es...>::Notify;
+  template <typename... Ts>
+  void Notify(Ts&&... aEvents) {
+    this->NotifyInternal(Forward<Ts>(aEvents)...);
+  }
 };
 
 } // namespace mozilla
 
 #endif //MediaEventSource_h_