tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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