EnsureMTA.h (3718B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_mscom_EnsureMTA_h 8 #define mozilla_mscom_EnsureMTA_h 9 10 #include "MainThreadUtils.h" 11 #include "mozilla/Attributes.h" 12 #include "mozilla/DebugOnly.h" 13 #include "mozilla/MozPromise.h" 14 #include "mozilla/mscom/AgileReference.h" 15 #include "mozilla/mscom/Utils.h" 16 #include "nsCOMPtr.h" 17 #include "nsIThread.h" 18 #include "nsThreadUtils.h" 19 #include "nsWindowsHelpers.h" 20 21 #include <windows.h> 22 23 namespace mozilla { 24 namespace mscom { 25 namespace detail { 26 27 // Forward declarations 28 template <typename T> 29 struct MTADelete; 30 31 template <typename T> 32 struct MTARelease; 33 34 template <typename T> 35 struct MTAReleaseInChildProcess; 36 37 struct PreservedStreamDeleter; 38 39 } // namespace detail 40 41 class ProcessRuntime; 42 43 // This class is OK to use as a temporary on the stack. 44 class MOZ_STACK_CLASS EnsureMTA final { 45 public: 46 enum class Option { 47 Default, 48 // Forcibly dispatch to the thread returned by GetPersistentMTAThread(), 49 // even if the current thread is already inside a MTA. 50 ForceDispatchToPersistentThread, 51 }; 52 53 /** 54 * Synchronously run |aClosure| on a thread living in the COM multithreaded 55 * apartment. If the current thread lives inside the COM MTA, then it runs 56 * |aClosure| immediately unless |aOpt| == 57 * Option::ForceDispatchToPersistentThread. 58 */ 59 template <typename FuncT> 60 explicit EnsureMTA(FuncT&& aClosure, Option aOpt = Option::Default) { 61 if (aOpt != Option::ForceDispatchToPersistentThread && 62 IsCurrentThreadMTA()) { 63 // We're already on the MTA, we can run aClosure directly 64 aClosure(); 65 return; 66 } 67 68 // In this case we need to run aClosure on a background thread in the MTA 69 nsCOMPtr<nsIRunnable> runnable( 70 NS_NewRunnableFunction("EnsureMTA::EnsureMTA", std::move(aClosure))); 71 SyncDispatch(std::move(runnable), aOpt); 72 } 73 74 private: 75 static nsCOMPtr<nsIThread> GetPersistentMTAThread(); 76 77 static void SyncDispatch(nsCOMPtr<nsIRunnable>&& aRunnable, Option aOpt); 78 static void SyncDispatchToPersistentThread(nsIRunnable* aRunnable); 79 80 // The following function is private in order to force any consumers to be 81 // declared as friends of EnsureMTA. The intention is to prevent 82 // AsyncOperation from becoming some kind of free-for-all mechanism for 83 // asynchronously executing work on a background thread. 84 template <typename FuncT> 85 static void AsyncOperation(FuncT&& aClosure) { 86 if (IsCurrentThreadMTA()) { 87 aClosure(); 88 return; 89 } 90 91 nsCOMPtr<nsIThread> thread(GetPersistentMTAThread()); 92 MOZ_ASSERT(thread); 93 if (!thread) { 94 return; 95 } 96 97 DebugOnly<nsresult> rv = thread->Dispatch( 98 NS_NewRunnableFunction("mscom::EnsureMTA::AsyncOperation", 99 std::move(aClosure)), 100 NS_DISPATCH_NORMAL); 101 MOZ_ASSERT(NS_SUCCEEDED(rv)); 102 } 103 104 /** 105 * This constructor just ensures that the MTA is up and running. This should 106 * only be called by ProcessRuntime. 107 */ 108 EnsureMTA(); 109 110 friend class mozilla::mscom::ProcessRuntime; 111 112 template <typename T> 113 friend struct mozilla::mscom::detail::MTADelete; 114 115 template <typename T> 116 friend struct mozilla::mscom::detail::MTARelease; 117 118 template <typename T> 119 friend struct mozilla::mscom::detail::MTAReleaseInChildProcess; 120 121 friend struct mozilla::mscom::detail::PreservedStreamDeleter; 122 }; 123 124 } // namespace mscom 125 } // namespace mozilla 126 127 #endif // mozilla_mscom_EnsureMTA_h