Bug 1339945: Refactor mscom::MainThreadInvoker's wait mechanism into a separate class; r?handyman draft
authorAaron Klotz <aklotz@mozilla.com>
Fri, 10 Feb 2017 11:27:01 -0700
changeset 484866 5829b0cb2edb454beafcd29f40c68e8649e8bbd7
parent 484862 e6488e3e42ec5db7b9e2689f1844dc8fc6f9ace1
child 484871 c91a9b968e4d3e584fe99b9b6536e75abaad1d9c
push id45572
push useraklotz@mozilla.com
push dateWed, 15 Feb 2017 21:50:05 +0000
reviewershandyman
bugs1339945
milestone54.0a1
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
@@ -30,23 +30,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',