зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1304883: Modify mscom::MainThreadInvoker and Win32 widget to use atomic boolean to flag pending APCs; r=jimm
MozReview-Commit-ID: 7fXoDkBEd2V --HG-- extra : rebase_source : 1960f9bf8294bfea15209554dd7fdc0ce1df5dcc
This commit is contained in:
Родитель
1627aee084
Коммит
96c052cf1f
|
@ -14,8 +14,7 @@
|
|||
#include "mozilla/HangMonitor.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "private/prpriv.h" // For PR_GetThreadID
|
||||
|
||||
#include <winternl.h> // For NTSTATUS and NTAPI
|
||||
#include "WinUtils.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -42,15 +41,12 @@ private:
|
|||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
};
|
||||
|
||||
typedef NTSTATUS (NTAPI* NtTestAlertPtr)(VOID);
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace mozilla {
|
||||
namespace mscom {
|
||||
|
||||
HANDLE MainThreadInvoker::sMainThread = nullptr;
|
||||
StaticRefPtr<nsIRunnable> MainThreadInvoker::sAlertRunnable;
|
||||
|
||||
/* static */ bool
|
||||
MainThreadInvoker::InitStatics()
|
||||
|
@ -67,25 +63,11 @@ MainThreadInvoker::InitStatics()
|
|||
}
|
||||
PRUint32 tid = ::PR_GetThreadID(mainPrThread);
|
||||
sMainThread = ::OpenThread(SYNCHRONIZE | THREAD_SET_CONTEXT, FALSE, tid);
|
||||
if (!sMainThread) {
|
||||
return false;
|
||||
}
|
||||
NtTestAlertPtr NtTestAlert =
|
||||
reinterpret_cast<NtTestAlertPtr>(
|
||||
::GetProcAddress(::GetModuleHandleW(L"ntdll.dll"), "NtTestAlert"));
|
||||
sAlertRunnable = ::NS_NewRunnableFunction([NtTestAlert]() -> void {
|
||||
// We're using NtTestAlert() instead of SleepEx() so that the main thread
|
||||
// never gives up its quantum if there are no APCs pending.
|
||||
NtTestAlert();
|
||||
}).take();
|
||||
if (sAlertRunnable) {
|
||||
ClearOnShutdown(&sAlertRunnable);
|
||||
}
|
||||
return !!sAlertRunnable;
|
||||
return !!sMainThread;
|
||||
}
|
||||
|
||||
MainThreadInvoker::MainThreadInvoker()
|
||||
: mDoneEvent(::CreateEvent(nullptr, FALSE, FALSE, nullptr))
|
||||
: mDoneEvent(::CreateEventW(nullptr, FALSE, FALSE, nullptr))
|
||||
{
|
||||
static const bool gotStatics = InitStatics();
|
||||
MOZ_ASSERT(gotStatics);
|
||||
|
@ -129,11 +111,11 @@ MainThreadInvoker::Invoke(already_AddRefed<nsIRunnable>&& aRunnable,
|
|||
wrappedRunnable->Release();
|
||||
return false;
|
||||
}
|
||||
// We should enqueue a call to NtTestAlert() so that the main thread will
|
||||
// check for APCs during event processing. If we omit this then the main
|
||||
// thread will not check its APC queue until it is idle. Note that failing to
|
||||
// dispatch this event is non-fatal, but it will delay execution of the APC.
|
||||
Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(sAlertRunnable)));
|
||||
// We should ensure a call to NtTestAlert() is made on the main thread so
|
||||
// that the main thread will check for APCs during event processing. If we
|
||||
// omit this then the main thread will not check its APC queue until it is
|
||||
// idle.
|
||||
widget::WinUtils::SetAPCPending();
|
||||
return WaitForCompletion(aTimeout);
|
||||
}
|
||||
|
||||
|
|
|
@ -452,6 +452,11 @@ struct CoTaskMemFreePolicy
|
|||
|
||||
SetThreadDpiAwarenessContextProc WinUtils::sSetThreadDpiAwarenessContext = NULL;
|
||||
EnableNonClientDpiScalingProc WinUtils::sEnableNonClientDpiScaling = NULL;
|
||||
#ifdef ACCESSIBILITY
|
||||
typedef NTSTATUS (NTAPI* NtTestAlertPtr)(VOID);
|
||||
static NtTestAlertPtr sNtTestAlert = nullptr;
|
||||
#endif
|
||||
|
||||
|
||||
/* static */
|
||||
void
|
||||
|
@ -486,6 +491,12 @@ WinUtils::Initialize()
|
|||
::GetProcAddress(user32Dll, "SetThreadDpiAwarenessContext");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
sNtTestAlert = reinterpret_cast<NtTestAlertPtr>(
|
||||
::GetProcAddress(::GetModuleHandleW(L"ntdll.dll"), "NtTestAlert"));
|
||||
MOZ_ASSERT(sNtTestAlert);
|
||||
#endif
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -691,11 +702,31 @@ WinUtils::MonitorFromRect(const gfx::Rect& rect)
|
|||
return ::MonitorFromRect(&globalWindowBounds, MONITOR_DEFAULTTONEAREST);
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
#ifndef STATUS_SUCCESS
|
||||
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
|
||||
#endif
|
||||
|
||||
static Atomic<bool> sAPCPending;
|
||||
|
||||
/* static */
|
||||
void
|
||||
WinUtils::SetAPCPending()
|
||||
{
|
||||
sAPCPending = true;
|
||||
}
|
||||
#endif // ACCESSIBILITY
|
||||
|
||||
/* static */
|
||||
bool
|
||||
WinUtils::PeekMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage,
|
||||
UINT aLastMessage, UINT aOption)
|
||||
{
|
||||
#ifdef ACCESSIBILITY
|
||||
if (NS_IsMainThread() && sAPCPending.exchange(false)) {
|
||||
while (sNtTestAlert() != STATUS_SUCCESS) ;
|
||||
}
|
||||
#endif
|
||||
#ifdef NS_ENABLE_TSF
|
||||
ITfMessagePump* msgPump = TSFTextStore::GetMessagePump();
|
||||
if (msgPump) {
|
||||
|
@ -764,14 +795,21 @@ WinUtils::WaitForMessage(DWORD aTimeoutMs)
|
|||
if (result == WAIT_TIMEOUT) {
|
||||
break;
|
||||
}
|
||||
#if defined(ACCESSIBILITY)
|
||||
if (result == WAIT_IO_COMPLETION) {
|
||||
if (NS_IsMainThread()) {
|
||||
if (sAPCPending.exchange(false)) {
|
||||
// Clear out any pending APCs
|
||||
while (sNtTestAlert() != STATUS_SUCCESS) ;
|
||||
}
|
||||
// We executed an APC that would have woken up the hang monitor. Since
|
||||
// we're now going to sleep again, we should notify the hang monitor.
|
||||
// there are no more APCs pending and we are now going to sleep again,
|
||||
// we should notify the hang monitor.
|
||||
mozilla::HangMonitor::Suspend();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
|
||||
// Sent messages (via SendMessage and friends) are processed differently
|
||||
// than queued messages (via PostMessage); the destination window procedure
|
||||
|
|
|
@ -519,6 +519,10 @@ public:
|
|||
*/
|
||||
static bool GetAppInitDLLs(nsAString& aOutput);
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
static void SetAPCPending();
|
||||
#endif
|
||||
|
||||
private:
|
||||
typedef HRESULT (WINAPI * SHCreateItemFromParsingNamePtr)(PCWSTR pszPath,
|
||||
IBindCtx *pbc,
|
||||
|
|
Загрузка…
Ссылка в новой задаче