mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-14 13:55:43 +00:00
81720f1abb
When removing our Windows message loop pumping code in the content process, a11y code on the MTA thread must have some way to wake up the main thread. The main thread could be blocked either on a conditional variable waiting for a Gecko event, or it could be blocked waiting on a Windows HANDLE in IPC code (doing a sync message send). In the former case, we wake it up by posting an event to the main thread. In the latter case, we continue to use the asynchronous procedure call mechanism. MozReview-Commit-ID: FN6KWaGo9Zl
140 lines
3.5 KiB
C++
140 lines
3.5 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/. */
|
|
|
|
#include "mozilla/mscom/MainThreadInvoker.h"
|
|
|
|
#include "GeckoProfiler.h"
|
|
#include "MainThreadUtils.h"
|
|
#include "mozilla/Assertions.h"
|
|
#include "mozilla/ClearOnShutdown.h"
|
|
#include "mozilla/DebugOnly.h"
|
|
#include "mozilla/HangMonitor.h"
|
|
#include "mozilla/mscom/SpinEvent.h"
|
|
#include "mozilla/RefPtr.h"
|
|
#include "private/prpriv.h" // For PR_GetThreadID
|
|
#include "WinUtils.h"
|
|
|
|
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 SyncRunnable : public mozilla::Runnable
|
|
{
|
|
public:
|
|
explicit SyncRunnable(already_AddRefed<nsIRunnable> aRunnable)
|
|
: mozilla::Runnable("MainThreadInvoker")
|
|
, mRunnable(aRunnable)
|
|
{}
|
|
|
|
~SyncRunnable() = default;
|
|
|
|
NS_IMETHOD Run()
|
|
{
|
|
if (mHasRun) {
|
|
return NS_OK;
|
|
}
|
|
mHasRun = true;
|
|
|
|
mRunnable->Run();
|
|
|
|
mEvent.Signal();
|
|
return NS_OK;
|
|
}
|
|
|
|
bool WaitUntilComplete()
|
|
{
|
|
return mEvent.Wait(mozilla::mscom::MainThreadInvoker::GetTargetThread());
|
|
}
|
|
|
|
private:
|
|
bool mHasRun = false;
|
|
nsCOMPtr<nsIRunnable> mRunnable;
|
|
mozilla::mscom::SpinEvent mEvent;
|
|
};
|
|
|
|
} // anonymous namespace
|
|
|
|
namespace mozilla {
|
|
namespace mscom {
|
|
|
|
HANDLE MainThreadInvoker::sMainThread = nullptr;
|
|
|
|
/* static */ bool
|
|
MainThreadInvoker::InitStatics()
|
|
{
|
|
nsCOMPtr<nsIThread> mainThread;
|
|
nsresult rv = ::NS_GetMainThread(getter_AddRefs(mainThread));
|
|
if (NS_FAILED(rv)) {
|
|
return false;
|
|
}
|
|
|
|
PRThread* mainPrThread = nullptr;
|
|
rv = mainThread->GetPRThread(&mainPrThread);
|
|
if (NS_FAILED(rv)) {
|
|
return false;
|
|
}
|
|
|
|
PRUint32 tid = ::PR_GetThreadID(mainPrThread);
|
|
sMainThread = ::OpenThread(SYNCHRONIZE | THREAD_SET_CONTEXT, FALSE, tid);
|
|
|
|
return !!sMainThread;
|
|
}
|
|
|
|
MainThreadInvoker::MainThreadInvoker()
|
|
{
|
|
static const bool gotStatics = InitStatics();
|
|
MOZ_ASSERT(gotStatics);
|
|
}
|
|
|
|
bool
|
|
MainThreadInvoker::Invoke(already_AddRefed<nsIRunnable>&& aRunnable)
|
|
{
|
|
nsCOMPtr<nsIRunnable> runnable(Move(aRunnable));
|
|
if (!runnable) {
|
|
return false;
|
|
}
|
|
|
|
if (NS_IsMainThread()) {
|
|
runnable->Run();
|
|
return true;
|
|
}
|
|
|
|
RefPtr<SyncRunnable> syncRunnable = new SyncRunnable(runnable.forget());
|
|
|
|
if (NS_FAILED(NS_DispatchToMainThread(syncRunnable, nsIEventTarget::DISPATCH_NORMAL))) {
|
|
return false;
|
|
}
|
|
|
|
// This ref gets released in MainThreadAPC when it runs.
|
|
SyncRunnable* syncRunnableRef = syncRunnable.get();
|
|
NS_ADDREF(syncRunnableRef);
|
|
if (!::QueueUserAPC(&MainThreadAPC, sMainThread,
|
|
reinterpret_cast<UINT_PTR>(syncRunnableRef))) {
|
|
return false;
|
|
}
|
|
|
|
return syncRunnable->WaitUntilComplete();
|
|
}
|
|
|
|
/* static */ VOID CALLBACK
|
|
MainThreadInvoker::MainThreadAPC(ULONG_PTR aParam)
|
|
{
|
|
AutoProfilerThreadWake wake;
|
|
mozilla::HangMonitor::NotifyActivity(mozilla::HangMonitor::kGeneralActivity);
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
auto runnable = reinterpret_cast<SyncRunnable*>(aParam);
|
|
runnable->Run();
|
|
NS_RELEASE(runnable);
|
|
}
|
|
|
|
} // namespace mscom
|
|
} // namespace mozilla
|