Bug 1283193 - Add buffer mechanism in GamepadPlatformService to prevent dispatch failure in Mochitest. r=ted
authorChih-Yi Leu <cleu@mozilla.com>
Sun, 23 Oct 2016 19:32:00 +0200
changeset 319218 dbedfec333961ef77c6016b23932d68a1f39f37a
parent 319217 7eade199cd98fa6334fb466506faeabca76a5407
child 319219 8cb2020d0325cc15def6299cf270ebbdd4c0e31b
push id30865
push usercbook@mozilla.com
push dateTue, 25 Oct 2016 08:31:38 +0000
treeherdermozilla-central@78b863e9fcd9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted
bugs1283193
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1283193 - Add buffer mechanism in GamepadPlatformService to prevent dispatch failure in Mochitest. r=ted
dom/gamepad/GamepadPlatformService.cpp
dom/gamepad/GamepadPlatformService.h
--- a/dom/gamepad/GamepadPlatformService.cpp
+++ b/dom/gamepad/GamepadPlatformService.cpp
@@ -65,16 +65,24 @@ GamepadPlatformService::NotifyGamepadCha
   MOZ_ASSERT(XRE_IsParentProcess());
   MOZ_ASSERT(!NS_IsMainThread());
 
   GamepadChangeEvent e(aInfo);
 
   // mChannelParents may be accessed by background thread in the
   // same time, we use mutex to prevent possible race condtion
   MutexAutoLock autoLock(mMutex);
+
+  // Buffer all events if we have no Channel to dispatch, which
+  // may happen when performing Mochitest.
+  if (mChannelParents.IsEmpty()) {
+    mPendingEvents.AppendElement(e);
+    return;
+  }
+
   for(uint32_t i = 0; i < mChannelParents.Length(); ++i) {
     mChannelParents[i]->DispatchUpdateEvent(e);
   }
 }
 
 uint32_t
 GamepadPlatformService::AddGamepad(const char* aID,
                                    GamepadMappingType aMapping,
@@ -158,16 +166,37 @@ GamepadPlatformService::AddChannelParent
   // is created or removed in Background thread
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aParent);
   MOZ_ASSERT(!mChannelParents.Contains(aParent));
 
   // We use mutex here to prevent race condition with monitor thread
   MutexAutoLock autoLock(mMutex);
   mChannelParents.AppendElement(aParent);
+  FlushPendingEvents();
+}
+
+void
+GamepadPlatformService::FlushPendingEvents()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(!mChannelParents.IsEmpty());
+
+  if (mPendingEvents.IsEmpty()) {
+    return;
+  }
+
+  // NOTE: This method must be called with mMutex held because it accesses
+  // mChannelParents.
+  for (uint32_t i=0; i<mChannelParents.Length(); ++i) {
+    for (uint32_t j=0; j<mPendingEvents.Length();++j) {
+      mChannelParents[i]->DispatchUpdateEvent(mPendingEvents[j]);
+    }
+  }
+  mPendingEvents.Clear();
 }
 
 void
 GamepadPlatformService::RemoveChannelParent(GamepadEventChannelParent* aParent)
 {
   // mChannelParents can only be modified once GamepadEventChannelParent
   // is created or removed in Background thread
   AssertIsOnBackgroundThread();
--- a/dom/gamepad/GamepadPlatformService.h
+++ b/dom/gamepad/GamepadPlatformService.h
@@ -69,27 +69,36 @@ class GamepadPlatformService final
   bool HasGamepadListeners();
 
   void MaybeShutdown();
 
  private:
   GamepadPlatformService();
   ~GamepadPlatformService();
   template<class T> void NotifyGamepadChange(const T& aInfo);
+
+  // Flush all pending events buffered in mPendingEvents, must be called
+  // with mMutex held
+  void FlushPendingEvents();
   void Cleanup();
 
   // mGamepadIndex can only be accessed by monitor thread
   uint32_t mGamepadIndex;
 
   // mChannelParents stores all the GamepadEventChannelParent instances
   // which may be accessed by both background thread and monitor thread
   // simultaneously, so we have a mutex to prevent race condition
   nsTArray<RefPtr<GamepadEventChannelParent>> mChannelParents;
 
   // This mutex protects mChannelParents from race condition
   // between background and monitor thread
   Mutex mMutex;
+
+  // In mochitest, it is possible that the test Events is synthesized
+  // before GamepadEventChannel created, we need to buffer all events
+  // until the channel is created if that happens.
+  nsTArray<GamepadChangeEvent> mPendingEvents;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif