Bug 1396155 - Allow LabeledEventQueue to be used outside the Scheduler (r=froydnj)
authorBill McCloskey <billm@mozilla.com>
Fri, 01 Sep 2017 16:39:13 -0700
changeset 379655 9967ddf61c89b809b0c819019e37ccaeb637ae34
parent 379654 0b295c9c9ffd05a089dd36519cc3000baf469763
child 379656 446245826a3e0f65da037a64f21d64f9f5979720
push id32458
push userarchaeopteryx@coole-files.de
push dateFri, 08 Sep 2017 08:53:53 +0000
treeherdermozilla-central@fd1ab37308c5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1396155
milestone57.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 1396155 - Allow LabeledEventQueue to be used outside the Scheduler (r=froydnj) MozReview-Commit-ID: 4yEX39HXh9W
xpcom/threads/MainThreadQueue.h
xpcom/threads/PrioritizedEventQueue.cpp
xpcom/threads/PrioritizedEventQueue.h
xpcom/threads/Scheduler.cpp
xpcom/threads/Scheduler.h
xpcom/threads/ThreadEventQueue.cpp
xpcom/threads/ThreadEventQueue.h
xpcom/threads/nsThreadManager.cpp
new file mode 100644
--- /dev/null
+++ b/xpcom/threads/MainThreadQueue.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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_MainThreadQueue_h
+#define mozilla_MainThreadQueue_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/EventQueue.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtr.h"
+#include "nsThread.h"
+#include "PrioritizedEventQueue.h"
+
+namespace mozilla {
+
+template<typename SynchronizedQueueT, typename InnerQueueT>
+inline already_AddRefed<nsThread>
+CreateMainThread(nsIIdlePeriod* aIdlePeriod, SynchronizedQueueT** aSynchronizedQueue = nullptr)
+{
+  using MainThreadQueueT = PrioritizedEventQueue<InnerQueueT>;
+
+  auto queue = MakeUnique<MainThreadQueueT>(
+    MakeUnique<InnerQueueT>(),
+    MakeUnique<InnerQueueT>(),
+    MakeUnique<InnerQueueT>(),
+    MakeUnique<InnerQueueT>(),
+    do_AddRef(aIdlePeriod));
+
+  MainThreadQueueT* prioritized = queue.get();
+
+  RefPtr<SynchronizedQueueT> synchronizedQueue = new SynchronizedQueueT(Move(queue));
+
+  prioritized->SetMutexRef(synchronizedQueue->MutexRef());
+
+  // Setup "main" thread
+  RefPtr<nsThread> mainThread = new nsThread(WrapNotNull(synchronizedQueue), nsThread::MAIN_THREAD, 0);
+
+#ifndef RELEASE_OR_BETA
+  prioritized->SetNextIdleDeadlineRef(mainThread->NextIdleDeadlineRef());
+#endif
+
+  if (aSynchronizedQueue) {
+    synchronizedQueue.forget(aSynchronizedQueue);
+  }
+  return mainThread.forget();
+}
+
+} // namespace mozilla
+
+#endif // mozilla_MainThreadQueue_h
--- a/xpcom/threads/PrioritizedEventQueue.cpp
+++ b/xpcom/threads/PrioritizedEventQueue.cpp
@@ -337,9 +337,10 @@ PrioritizedEventQueue<InnerQueueT>::
 ResumeInputEventPrioritization(const MutexAutoLock& aProofOfLock)
 {
   MOZ_ASSERT(mInputQueueState == STATE_SUSPEND);
   mInputQueueState = STATE_ENABLED;
 }
 
 namespace mozilla {
 template class PrioritizedEventQueue<EventQueue>;
+template class PrioritizedEventQueue<LabeledEventQueue>;
 }
--- a/xpcom/threads/PrioritizedEventQueue.h
+++ b/xpcom/threads/PrioritizedEventQueue.h
@@ -120,12 +120,13 @@ private:
     STATE_SUSPEND,
     STATE_ENABLED
   };
   InputEventQueueState mInputQueueState = STATE_DISABLED;
 };
 
 class EventQueue;
 extern template class PrioritizedEventQueue<EventQueue>;
+extern template class PrioritizedEventQueue<LabeledEventQueue>;
 
 } // namespace mozilla
 
 #endif // mozilla_PrioritizedEventQueue_h
--- a/xpcom/threads/Scheduler.cpp
+++ b/xpcom/threads/Scheduler.cpp
@@ -4,16 +4,17 @@
  * 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/. */
 
 #include "Scheduler.h"
 
 #include "jsfriendapi.h"
 #include "LabeledEventQueue.h"
 #include "LeakRefPtr.h"
+#include "MainThreadQueue.h"
 #include "mozilla/CooperativeThreadPool.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/SchedulerGroup.h"
 #include "nsCycleCollector.h"
 #include "nsIThread.h"
 #include "nsPrintfCString.h"
 #include "nsThread.h"
@@ -86,19 +87,16 @@ private:
 
 using mozilla::detail::SchedulerEventQueue;
 
 class mozilla::SchedulerImpl
 {
 public:
   explicit SchedulerImpl(SchedulerEventQueue* aQueue);
 
-  static already_AddRefed<SchedulerEventQueue>
-  CreateQueue(nsIIdlePeriod* aIdlePeriod, nsThread** aThread);
-
   void Start();
   void Shutdown();
 
   void Dispatch(already_AddRefed<nsIRunnable> aEvent);
 
   void Yield();
 
   static void EnterNestedEventLoop(Scheduler::EventLoopActivation& aOuterActivation);
@@ -437,59 +435,16 @@ SchedulerImpl::Switcher()
 }
 
 /* static */ void
 SchedulerImpl::SwitcherThread(void* aData)
 {
   static_cast<SchedulerImpl*>(aData)->Switcher();
 }
 
-/* static */ already_AddRefed<SchedulerEventQueue>
-SchedulerImpl::CreateQueue(nsIIdlePeriod* aIdlePeriod, nsThread** aThread)
-{
-  UniquePtr<AbstractEventQueue> queue;
-  RefPtr<nsThread> mainThread;
-
-  if (sPrefUseMultipleQueues) {
-    using MainThreadQueueT = PrioritizedEventQueue<LabeledEventQueue>;
-
-    queue = MakeUnique<MainThreadQueueT>(
-      MakeUnique<LabeledEventQueue>(),
-      MakeUnique<LabeledEventQueue>(),
-      MakeUnique<LabeledEventQueue>(),
-      MakeUnique<LabeledEventQueue>(),
-      do_AddRef(aIdlePeriod));
-  } else {
-    using MainThreadQueueT = PrioritizedEventQueue<EventQueue>;
-
-    queue = MakeUnique<MainThreadQueueT>(
-      MakeUnique<EventQueue>(),
-      MakeUnique<EventQueue>(),
-      MakeUnique<EventQueue>(),
-      MakeUnique<EventQueue>(),
-      do_AddRef(aIdlePeriod));
-  }
-
-  auto prioritized = static_cast<PrioritizedEventQueue<AbstractEventQueue>*>(queue.get());
-
-  RefPtr<SchedulerEventQueue> synchronizedQueue = new SchedulerEventQueue(Move(queue));
-
-  prioritized->SetMutexRef(synchronizedQueue->MutexRef());
-
-  // Setup "main" thread
-  mainThread = new nsThread(WrapNotNull(synchronizedQueue), nsThread::MAIN_THREAD, 0);
-
-#ifndef RELEASE_OR_BETA
-  prioritized->SetNextIdleDeadlineRef(mainThread->NextIdleDeadlineRef());
-#endif
-
-  mainThread.forget(aThread);
-  return synchronizedQueue.forget();
-}
-
 void
 SchedulerImpl::Start()
 {
   NS_DispatchToMainThread(NS_NewRunnableFunction("Scheduler::Start", [this]() -> void {
     // Let's pretend the runnable here isn't actually running.
     MOZ_ASSERT(sUnlabeledEventRunning);
     sUnlabeledEventRunning = false;
     MOZ_ASSERT(sNumThreadsRunning == 1);
@@ -733,18 +688,24 @@ SchedulerImpl::Yield()
   CooperativeThreadPool::Yield(nullptr, lock);
 }
 
 /* static */ already_AddRefed<nsThread>
 Scheduler::Init(nsIIdlePeriod* aIdlePeriod)
 {
   MOZ_ASSERT(!sScheduler);
 
+  RefPtr<SchedulerEventQueue> queue;
   RefPtr<nsThread> mainThread;
-  RefPtr<SchedulerEventQueue> queue = SchedulerImpl::CreateQueue(aIdlePeriod, getter_AddRefs(mainThread));
+  if (Scheduler::UseMultipleQueues()) {
+    mainThread = CreateMainThread<SchedulerEventQueue, LabeledEventQueue>(aIdlePeriod, getter_AddRefs(queue));
+  } else {
+    mainThread = CreateMainThread<SchedulerEventQueue, EventQueue>(aIdlePeriod, getter_AddRefs(queue));
+  }
+
   sScheduler = MakeUnique<SchedulerImpl>(queue);
   return mainThread.forget();
 }
 
 /* static */ void
 Scheduler::Start()
 {
   sScheduler->Start();
@@ -802,16 +763,22 @@ Scheduler::SetPrefs(const char* aPrefs)
 
 /* static */ bool
 Scheduler::IsSchedulerEnabled()
 {
   return SchedulerImpl::sPrefScheduler;
 }
 
 /* static */ bool
+Scheduler::UseMultipleQueues()
+{
+  return SchedulerImpl::sPrefUseMultipleQueues;
+}
+
+/* static */ bool
 Scheduler::IsCooperativeThread()
 {
   return CooperativeThreadPool::IsCooperativeThread();
 }
 
 /* static */ void
 Scheduler::Yield()
 {
--- a/xpcom/threads/Scheduler.h
+++ b/xpcom/threads/Scheduler.h
@@ -57,16 +57,17 @@ public:
   static void Shutdown();
 
   // Scheduler prefs need to be handled differently because the scheduler needs
   // to start up in the content process before the normal preferences service.
   static nsCString GetPrefs();
   static void SetPrefs(const char* aPrefs);
 
   static bool IsSchedulerEnabled();
+  static bool UseMultipleQueues();
 
   static bool IsCooperativeThread();
 
   static void Yield();
 
   static bool UnlabeledEventRunning();
   static bool AnyEventRunning();
 
--- a/xpcom/threads/ThreadEventQueue.cpp
+++ b/xpcom/threads/ThreadEventQueue.cpp
@@ -264,9 +264,10 @@ ThreadEventQueue<InnerQueueT>::SetObserv
 {
   MutexAutoLock lock(mLock);
   mObserver = aObserver;
 }
 
 namespace mozilla {
 template class ThreadEventQueue<EventQueue>;
 template class ThreadEventQueue<PrioritizedEventQueue<EventQueue>>;
+template class ThreadEventQueue<PrioritizedEventQueue<LabeledEventQueue>>;
 }
--- a/xpcom/threads/ThreadEventQueue.h
+++ b/xpcom/threads/ThreadEventQueue.h
@@ -19,16 +19,18 @@ class nsIThreadObserver;
 
 namespace mozilla {
 
 class EventQueue;
 
 template<typename InnerQueueT>
 class PrioritizedEventQueue;
 
+class LabeledEventQueue;
+
 class ThreadEventTarget;
 
 // A ThreadEventQueue implements normal monitor-style synchronization over the
 // InnerQueueT AbstractEventQueue. It also implements PushEventQueue and
 // PopEventQueue for workers (see the documentation below for an explanation of
 // those). All threads use a ThreadEventQueue as their event queue. InnerQueueT
 // is a template parameter to avoid virtual dispatch overhead.
 template<class InnerQueueT>
@@ -110,12 +112,13 @@ private:
   CondVar mEventsAvailable;
 
   bool mEventsAreDoomed = false;
   nsCOMPtr<nsIThreadObserver> mObserver;
 };
 
 extern template class ThreadEventQueue<EventQueue>;
 extern template class ThreadEventQueue<PrioritizedEventQueue<EventQueue>>;
+extern template class ThreadEventQueue<PrioritizedEventQueue<LabeledEventQueue>>;
 
 }; // namespace mozilla
 
 #endif // mozilla_ThreadEventQueue_h
--- a/xpcom/threads/nsThreadManager.cpp
+++ b/xpcom/threads/nsThreadManager.cpp
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsThreadManager.h"
 #include "nsThread.h"
 #include "nsThreadUtils.h"
 #include "nsIClassInfoImpl.h"
 #include "nsTArray.h"
 #include "nsAutoPtr.h"
+#include "LabeledEventQueue.h"
+#include "MainThreadQueue.h"
 #include "mozilla/AbstractThread.h"
 #include "mozilla/EventQueue.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Scheduler.h"
 #include "mozilla/SystemGroup.h"
 #include "mozilla/ThreadEventQueue.h"
 #include "mozilla/ThreadLocal.h"
 #include "PrioritizedEventQueue.h"
@@ -129,37 +131,21 @@ nsThreadManager::Init()
 
   nsCOMPtr<nsIIdlePeriod> idlePeriod = new MainThreadIdlePeriod();
 
   bool startScheduler = false;
   if (XRE_IsContentProcess() && Scheduler::IsSchedulerEnabled()) {
     mMainThread = Scheduler::Init(idlePeriod);
     startScheduler = true;
   } else {
-    using MainThreadQueueT = PrioritizedEventQueue<EventQueue>;
-
-    auto prioritized = MakeUnique<MainThreadQueueT>(MakeUnique<EventQueue>(),
-                                                    MakeUnique<EventQueue>(),
-                                                    MakeUnique<EventQueue>(),
-                                                    MakeUnique<EventQueue>(),
-                                                    idlePeriod.forget());
-
-    // Save a copy temporarily so we can set some state on it.
-    MainThreadQueueT* prioritizedRef = prioritized.get();
-    RefPtr<ThreadEventQueue<MainThreadQueueT>> queue =
-      new ThreadEventQueue<MainThreadQueueT>(Move(prioritized));
-
-    prioritizedRef->SetMutexRef(queue->MutexRef());
-
-    // Setup "main" thread
-    mMainThread = new nsThread(WrapNotNull(queue), nsThread::MAIN_THREAD, 0);
-
-#ifndef RELEASE_OR_BETA
-    prioritizedRef->SetNextIdleDeadlineRef(mMainThread->NextIdleDeadlineRef());
-#endif
+    if (XRE_IsContentProcess() && Scheduler::UseMultipleQueues()) {
+      mMainThread = CreateMainThread<ThreadEventQueue<PrioritizedEventQueue<LabeledEventQueue>>, LabeledEventQueue>(idlePeriod);
+    } else {
+      mMainThread = CreateMainThread<ThreadEventQueue<PrioritizedEventQueue<EventQueue>>, EventQueue>(idlePeriod);
+    }
   }
 
   nsresult rv = mMainThread->InitCurrentThread();
   if (NS_FAILED(rv)) {
     mMainThread = nullptr;
     return rv;
   }