Bug 1339945: Refactor mscom::MainThreadInvoker's wait mechanism into a separate class; r=handyman
authorAaron Klotz <aklotz@mozilla.com>
Fri, 10 Feb 2017 11:27:01 -0700
changeset 394413 0ae0446f58c340060db184d6760755a3b289d731
parent 394412 4af8a2761308d415940e367fdffb435b380fd554
child 394414 b5c379a1a3cb4d4303214217d557232b7f0e03db
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershandyman
bugs1339945
milestone54.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 1339945: Refactor mscom::MainThreadInvoker's wait mechanism into a separate class; r=handyman MozReview-Commit-ID: BikO5ng6joM
ipc/mscom/MainThreadInvoker.cpp
ipc/mscom/SpinEvent.cpp
ipc/mscom/SpinEvent.h
ipc/mscom/moz.build
--- a/ipc/mscom/MainThreadInvoker.cpp
+++ b/ipc/mscom/MainThreadInvoker.cpp
@@ -4,100 +4,59 @@
  * 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 "mozilla/mscom/MainThreadInvoker.h"
 
 #include "GeckoProfiler.h"
 #include "MainThreadUtils.h"
 #include "mozilla/Assertions.h"
-#include "mozilla/Atomics.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/HangMonitor.h"
+#include "mozilla/mscom/SpinEvent.h"
 #include "mozilla/RefPtr.h"
-#include "nsServiceManagerUtils.h"
-#include "nsSystemInfo.h"
 #include "private/prpriv.h" // For PR_GetThreadID
 #include "WinUtils.h"
 
-// This gives us compiler intrinsics for the x86 PAUSE instruction
-#if defined(_MSC_VER)
-#include <intrin.h>
-#pragma intrinsic(_mm_pause)
-#define CPU_PAUSE() _mm_pause()
-#elif defined(__GNUC__) || defined(__clang__)
-#define CPU_PAUSE() __builtin_ia32_pause()
-#endif
-
-static bool sIsMulticore;
-
 namespace {
 
 /**
  * SyncRunnable implements different code paths depending on whether or not
  * we are running on a multiprocessor system. In the multiprocessor case, we
  * leave the thread in a spin loop while waiting for the main thread to execute
  * our runnable. Since spinning is pointless in the uniprocessor case, we block
  * on an event that is set by the main thread once it has finished the runnable.
  */
 class MOZ_RAII SyncRunnable
 {
 public:
   explicit SyncRunnable(already_AddRefed<nsIRunnable>&& aRunnable)
-    : mDoneEvent(sIsMulticore ? nullptr :
-                 ::CreateEventW(nullptr, FALSE, FALSE, nullptr))
-    , mDone(false)
-    , mRunnable(aRunnable)
+    : mRunnable(aRunnable)
   {
-    MOZ_ASSERT(sIsMulticore || mDoneEvent);
     MOZ_ASSERT(mRunnable);
   }
 
-  ~SyncRunnable()
-  {
-    if (mDoneEvent) {
-      ::CloseHandle(mDoneEvent);
-    }
-  }
+  ~SyncRunnable() = default;
 
   void Run()
   {
     mRunnable->Run();
 
-    if (mDoneEvent) {
-      ::SetEvent(mDoneEvent);
-    } else {
-      mDone = true;
-    }
+    mEvent.Signal();
   }
 
   bool WaitUntilComplete()
   {
-    if (mDoneEvent) {
-      HANDLE handles[] = {mDoneEvent,
-                          mozilla::mscom::MainThreadInvoker::GetTargetThread()};
-      DWORD waitResult = ::WaitForMultipleObjects(mozilla::ArrayLength(handles),
-                                                  handles, FALSE, INFINITE);
-      return waitResult == WAIT_OBJECT_0;
-    }
-
-    while (!mDone) {
-      // The PAUSE instruction is a hint to the CPU that we're doing a spin
-      // loop. It is a no-op on older processors that don't support it, so
-      // it is safe to use here without any CPUID checks.
-      CPU_PAUSE();
-    }
-    return true;
+    return mEvent.Wait(mozilla::mscom::MainThreadInvoker::GetTargetThread());
   }
 
 private:
-  HANDLE                mDoneEvent;
-  mozilla::Atomic<bool> mDone;
-  nsCOMPtr<nsIRunnable> mRunnable;
+  nsCOMPtr<nsIRunnable>     mRunnable;
+  mozilla::mscom::SpinEvent mEvent;
 };
 
 } // anonymous namespace
 
 namespace mozilla {
 namespace mscom {
 
 HANDLE MainThreadInvoker::sMainThread = nullptr;
@@ -115,24 +74,16 @@ MainThreadInvoker::InitStatics()
   rv = mainThread->GetPRThread(&mainPrThread);
   if (NS_FAILED(rv)) {
     return false;
   }
 
   PRUint32 tid = ::PR_GetThreadID(mainPrThread);
   sMainThread = ::OpenThread(SYNCHRONIZE | THREAD_SET_CONTEXT, FALSE, tid);
 
-  nsCOMPtr<nsIPropertyBag2> infoService = do_GetService(NS_SYSTEMINFO_CONTRACTID);
-  if (infoService) {
-    uint32_t cpuCount;
-    nsresult rv = infoService->GetPropertyAsUint32(NS_LITERAL_STRING("cpucount"),
-                                                   &cpuCount);
-    sIsMulticore = NS_SUCCEEDED(rv) && cpuCount > 1;
-  }
-
   return !!sMainThread;
 }
 
 MainThreadInvoker::MainThreadInvoker()
 {
   static const bool gotStatics = InitStatics();
   MOZ_ASSERT(gotStatics);
 }
new file mode 100644
--- /dev/null
+++ b/ipc/mscom/SpinEvent.cpp
@@ -0,0 +1,83 @@
+/* -*- 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/. */
+
+#include "mozilla/mscom/SpinEvent.h"
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Assertions.h"
+#include "nsServiceManagerUtils.h"
+#include "nsString.h"
+#include "nsSystemInfo.h"
+
+// This gives us compiler intrinsics for the x86 PAUSE instruction
+#if defined(_MSC_VER)
+#include <intrin.h>
+#pragma intrinsic(_mm_pause)
+#define CPU_PAUSE() _mm_pause()
+#elif defined(__GNUC__) || defined(__clang__)
+#define CPU_PAUSE() __builtin_ia32_pause()
+#endif
+
+namespace mozilla {
+namespace mscom {
+
+SpinEvent::SpinEvent()
+  : mDone(false)
+{
+  static const bool sIsMulticore = []() {
+    nsCOMPtr<nsIPropertyBag2> infoService = do_GetService(NS_SYSTEMINFO_CONTRACTID);
+    if (!infoService) {
+      return false;
+    }
+
+    uint32_t cpuCount;
+    nsresult rv = infoService->GetPropertyAsUint32(NS_LITERAL_STRING("cpucount"),
+                                                   &cpuCount);
+    return NS_SUCCEEDED(rv) && cpuCount > 1;
+  }();
+
+  if (!sIsMulticore) {
+    mDoneEvent.own(::CreateEventW(nullptr, FALSE, FALSE, nullptr));
+    MOZ_ASSERT(mDoneEvent);
+  }
+}
+
+bool
+SpinEvent::Wait(HANDLE aTargetThread)
+{
+  MOZ_ASSERT(aTargetThread);
+  if (!aTargetThread) {
+    return false;
+  }
+
+  if (mDoneEvent) {
+    HANDLE handles[] = {mDoneEvent, aTargetThread};
+    DWORD waitResult = ::WaitForMultipleObjects(mozilla::ArrayLength(handles),
+                                                handles, FALSE, INFINITE);
+    return waitResult == WAIT_OBJECT_0;
+  }
+
+  while (!mDone) {
+    // The PAUSE instruction is a hint to the CPU that we're doing a spin
+    // loop. It is a no-op on older processors that don't support it, so
+    // it is safe to use here without any CPUID checks.
+    CPU_PAUSE();
+  }
+  return true;
+}
+
+void
+SpinEvent::Signal()
+{
+  if (mDoneEvent) {
+    ::SetEvent(mDoneEvent);
+  } else {
+    mDone = true;
+  }
+}
+
+} // namespace mscom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/mscom/SpinEvent.h
@@ -0,0 +1,39 @@
+/* -*- 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_mscom_SpinEvent_h
+#define mozilla_mscom_SpinEvent_h
+
+#include "mozilla/Atomics.h"
+#include "mozilla/Attributes.h"
+#include "nsWindowsHelpers.h"
+
+namespace mozilla {
+namespace mscom {
+
+class MOZ_NON_TEMPORARY_CLASS SpinEvent final
+{
+public:
+  SpinEvent();
+  ~SpinEvent() = default;
+
+  bool Wait(HANDLE aTargetThread);
+  void Signal();
+
+  SpinEvent(const SpinEvent&) = delete;
+  SpinEvent(SpinEvent&&) = delete;
+  SpinEvent& operator=(SpinEvent&&) = delete;
+  SpinEvent& operator=(const SpinEvent&) = delete;
+
+private:
+  Atomic<bool, ReleaseAcquire>  mDone;
+  nsAutoHandle                  mDoneEvent;
+};
+
+} // namespace mscom
+} // namespace mozilla
+
+#endif // mozilla_mscom_SpinEvent_h
--- a/ipc/mscom/moz.build
+++ b/ipc/mscom/moz.build
@@ -29,23 +29,25 @@ if CONFIG['ACCESSIBILITY']:
     EXPORTS.mozilla.mscom += [
         'ActivationContext.h',
         'DispatchForwarder.h',
         'Interceptor.h',
         'InterceptorLog.h',
         'MainThreadHandoff.h',
         'MainThreadInvoker.h',
         'Registration.h',
+        'SpinEvent.h',
         'StructStream.h',
         'WeakRef.h',
     ]
 
     SOURCES += [
         'Interceptor.cpp',
         'Registration.cpp',
+        'SpinEvent.cpp',
         'WeakRef.cpp',
     ]
 
     UNIFIED_SOURCES += [
         'ActivationContext.cpp',
         'DispatchForwarder.cpp',
         'InterceptorLog.cpp',
         'MainThreadHandoff.cpp',