gecko-dev/ipc/mscom/EnsureMTA.h
Aaron Klotz 84c01f8930 Bug 1400344: Rename mscom::MainThreadRuntime to mscom::ProcessRuntime and make it aware of Win32k lockdown and of multiple instantiations; r=Jamie
This patch takes care of a bunch of issues and does some cleanup:

* We rename mscom::MainThreadRuntime to mscom::ProcessRuntime, as the latter
  is a more accurate name going forward.
* We make ProcessRuntime aware of the Win32k Lockdown process mitigation
  policy. When Win32k is disabled, we perform process-wide COM initialization
  in the multi-threaded apartment (since we cannot create an STA window).
* We refactor the mscom apartment region stuff to enable the Win32k lockdown
  pieces in ProcessRuntime.
* We move some Gecko-specific stuff into MOZILLA_INTERNAL_API guards so that
  ProcessRuntime is usable outside of xul.dll (I will be needing it for the
  launcher process).
* Another thing that might happen with the launcher process is that, under
  error conditions in the launcher, we create a ProcessRuntime object on a
  background thread for the purposes of telemetry logging, but we also allow
  the main thread to proceed to start as the browser. This could result in a
  scenario where the main thread, as the browser process, is attempting to
  instantiate its ProcessRuntime and ends up racing with the launcher process's
  telemetry thread which has its own ProcessRuntime. To account for this
  situation, we add mutual exclusion to the process-wide initialization code.
  We host this part inside mozglue since that state is shared between both
  firefox.exe and xul.dll.
* We clean up ProcessRuntime::InitializeSecurity by using Vector to set up
  the EXPLICIT_ACCESS entries.
* We remove mscom::MainThreadClientInfo and replace it with a direct call to
  CoGetCallerTID
* We revise all references to this class to use the new name.

Differential Revision: https://phabricator.services.mozilla.com/D19551

--HG--
rename : ipc/mscom/COMApartmentRegion.h => ipc/mscom/ApartmentRegion.h
rename : ipc/mscom/MainThreadRuntime.cpp => ipc/mscom/ProcessRuntime.cpp
rename : ipc/mscom/MainThreadRuntime.h => ipc/mscom/ProcessRuntime.h
extra : moz-landing-system : lando
2019-02-14 18:56:20 +00:00

142 lines
3.8 KiB
C++

/* -*- 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_EnsureMTA_h
#define mozilla_mscom_EnsureMTA_h
#include "MainThreadUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Unused.h"
#include "mozilla/mscom/Utils.h"
#include "nsCOMPtr.h"
#include "nsIThread.h"
#include "nsThreadUtils.h"
#include "nsWindowsHelpers.h"
#include <windows.h>
namespace mozilla {
namespace mscom {
namespace detail {
// Forward declarations
template <typename T>
struct MTADelete;
template <typename T>
struct MTARelease;
template <typename T>
struct MTAReleaseInChildProcess;
struct PreservedStreamDeleter;
} // namespace detail
// This class is OK to use as a temporary on the stack.
class MOZ_STACK_CLASS EnsureMTA final {
public:
/**
* This constructor just ensures that the MTA thread is up and running.
*/
EnsureMTA() {
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIThread> thread = GetMTAThread();
MOZ_ASSERT(thread);
Unused << thread;
}
template <typename FuncT>
explicit EnsureMTA(const FuncT& aClosure) {
if (IsCurrentThreadMTA()) {
// We're already on the MTA, we can run aClosure directly
aClosure();
return;
}
MOZ_ASSERT(NS_IsMainThread());
// In this case we need to run aClosure on a background thread in the MTA
nsCOMPtr<nsIThread> thread = GetMTAThread();
MOZ_ASSERT(thread);
if (!thread) {
return;
}
// Note that we might reenter the EnsureMTA constructor while we wait on
// this event due to APC dispatch, therefore we need a unique event object
// for each entry. If perf becomes an issue then we will want to maintain
// an array of events where the Nth event is unique to the Nth reentry.
nsAutoHandle event(::CreateEventW(nullptr, FALSE, FALSE, nullptr));
if (!event) {
return;
}
HANDLE eventHandle = event.get();
auto eventSetter = [&aClosure, eventHandle]() -> void {
aClosure();
::SetEvent(eventHandle);
};
nsresult rv = thread->Dispatch(
NS_NewRunnableFunction("EnsureMTA", eventSetter), NS_DISPATCH_NORMAL);
MOZ_ASSERT(NS_SUCCEEDED(rv));
if (NS_FAILED(rv)) {
return;
}
DWORD waitResult;
while ((waitResult = ::WaitForSingleObjectEx(event, INFINITE, TRUE)) ==
WAIT_IO_COMPLETION) {
}
MOZ_ASSERT(waitResult == WAIT_OBJECT_0);
}
private:
static nsCOMPtr<nsIThread> GetMTAThread();
// The following function is private in order to force any consumers to be
// declared as friends of EnsureMTA. The intention is to prevent
// AsyncOperation from becoming some kind of free-for-all mechanism for
// asynchronously executing work on a background thread.
template <typename FuncT>
static void AsyncOperation(const FuncT& aClosure) {
if (IsCurrentThreadMTA()) {
aClosure();
return;
}
nsCOMPtr<nsIThread> thread(GetMTAThread());
MOZ_ASSERT(thread);
if (!thread) {
return;
}
DebugOnly<nsresult> rv = thread->Dispatch(
NS_NewRunnableFunction("mscom::EnsureMTA::AsyncOperation", aClosure),
NS_DISPATCH_NORMAL);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
template <typename T>
friend struct mozilla::mscom::detail::MTADelete;
template <typename T>
friend struct mozilla::mscom::detail::MTARelease;
template <typename T>
friend struct mozilla::mscom::detail::MTAReleaseInChildProcess;
friend struct mozilla::mscom::detail::PreservedStreamDeleter;
};
} // namespace mscom
} // namespace mozilla
#endif // mozilla_mscom_EnsureMTA_h