Bug 1273635: Enable alertable waits in content process main thread; r=jimm

MozReview-Commit-ID: 2qGdGj41M0n

--HG--
extra : rebase_source : e404ba43a47151d38330052c9ac93e7b252ad0f4
This commit is contained in:
Aaron Klotz 2016-08-03 11:54:35 -06:00
Родитель 0a3f040d19
Коммит 2bbffe8138
4 изменённых файлов: 95 добавлений и 4 удалений

Просмотреть файл

@ -588,6 +588,9 @@ ContentChild::Init(MessageLoop* aIOLoop,
// If communications with the parent have broken down, take the process
// down so it's not hanging around.
GetIPCChannel()->SetAbortOnError(true);
#if defined(XP_WIN) && defined(ACCESSIBILITY)
GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_A11Y_REENTRY);
#endif
#ifdef MOZ_X11
// Send the parent our X socket to act as a proxy reference for our X

Просмотреть файл

@ -127,7 +127,12 @@ class MessageChannel : HasResultCodes
// handling to prevent deadlocks. Should only be used for protocols
// that manage child processes which might create native UI, like
// plugins.
REQUIRE_DEFERRED_MESSAGE_PROTECTION = 1 << 0
REQUIRE_DEFERRED_MESSAGE_PROTECTION = 1 << 0,
// Windows: When this flag is specified, any wait that occurs during
// synchronous IPC will be alertable, thus allowing a11y code in the
// chrome process to reenter content while content is waiting on a
// synchronous call.
REQUIRE_A11Y_REENTRY = 1 << 1,
};
void SetChannelFlags(ChannelFlags aFlags) { mFlags = aFlags; }
ChannelFlags GetChannelFlags() { return mFlags; }
@ -243,7 +248,10 @@ class MessageChannel : HasResultCodes
private:
void SpinInternalEventLoop();
#endif
#if defined(ACCESSIBILITY)
bool WaitForSyncNotifyWithA11yReentry();
#endif // defined(ACCESSIBILITY)
#endif // defined(OS_WIN)
private:
void CommonThreadOpenInit(MessageChannel *aTargetChan, Side aSide);

Просмотреть файл

@ -19,6 +19,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/PaintTracker.h"
#include "mozilla/WindowsVersion.h"
using namespace mozilla;
using namespace mozilla::ipc;
@ -1056,6 +1057,59 @@ SuppressedNeuteringRegion::~SuppressedNeuteringRegion()
bool SuppressedNeuteringRegion::sSuppressNeutering = false;
#if defined(ACCESSIBILITY)
bool
MessageChannel::WaitForSyncNotifyWithA11yReentry()
{
mMonitor->AssertCurrentThreadOwns();
MonitorAutoUnlock unlock(*mMonitor);
const DWORD waitStart = ::GetTickCount();
DWORD elapsed = 0;
DWORD timeout = mTimeoutMs == kNoTimeout ? INFINITE :
static_cast<DWORD>(mTimeoutMs);
bool timedOut = false;
while (true) {
{ // Scope for lock
MonitorAutoLock lock(*mMonitor);
if (!Connected()) {
break;
}
}
if (timeout != static_cast<DWORD>(kNoTimeout)) {
elapsed = ::GetTickCount() - waitStart;
}
if (elapsed >= timeout) {
timedOut = true;
break;
}
DWORD waitResult = 0;
::SetLastError(ERROR_SUCCESS);
HRESULT hr = ::CoWaitForMultipleHandles(COWAIT_ALERTABLE,
timeout - elapsed,
1, &mEvent, &waitResult);
if (hr == RPC_S_CALLPENDING) {
timedOut = true;
break;
}
if (hr == S_OK) {
if (waitResult == 0) {
// mEvent is signaled
break;
}
if (waitResult == WAIT_IO_COMPLETION) {
// APC fired, keep waiting
continue;
}
}
NS_WARN_IF_FALSE(SUCCEEDED(hr), "CoWaitForMultipleHandles failed");
}
return WaitResponse(timedOut);
}
#endif
bool
MessageChannel::WaitForSyncNotify(bool aHandleWindowsMessages)
{
@ -1063,6 +1117,12 @@ MessageChannel::WaitForSyncNotify(bool aHandleWindowsMessages)
MOZ_ASSERT(gUIThreadId, "InitUIThread was not called!");
#if defined(ACCESSIBILITY)
if (IsVistaOrLater() && (mFlags & REQUIRE_A11Y_REENTRY)) {
return WaitForSyncNotifyWithA11yReentry();
}
#endif
// Use a blocking wait if this channel does not require
// Windows message deferral behavior.
if (!(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION) || !aHandleWindowsMessages) {

Просмотреть файл

@ -726,10 +726,28 @@ WinUtils::GetMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage,
return ::GetMessageW(aMsg, aWnd, aFirstMessage, aLastMessage);
}
#if defined(ACCESSIBILITY)
static DWORD
GetWaitFlags()
{
DWORD result = MWMO_INPUTAVAILABLE;
if (IsVistaOrLater() && XRE_IsContentProcess()) {
result |= MWMO_ALERTABLE;
}
return result;
}
#endif
/* static */
void
WinUtils::WaitForMessage(DWORD aTimeoutMs)
{
#if defined(ACCESSIBILITY)
static const DWORD waitFlags = GetWaitFlags();
#else
const DWORD waitFlags = MWMO_INPUTAVAILABLE;
#endif
const DWORD waitStart = ::GetTickCount();
DWORD elapsed = 0;
while (true) {
@ -740,12 +758,14 @@ WinUtils::WaitForMessage(DWORD aTimeoutMs)
break;
}
DWORD result = ::MsgWaitForMultipleObjectsEx(0, NULL, aTimeoutMs - elapsed,
MOZ_QS_ALLEVENT,
MWMO_INPUTAVAILABLE);
MOZ_QS_ALLEVENT, waitFlags);
NS_WARN_IF_FALSE(result != WAIT_FAILED, "Wait failed");
if (result == WAIT_TIMEOUT) {
break;
}
if (result == WAIT_IO_COMPLETION) {
continue;
}
// Sent messages (via SendMessage and friends) are processed differently
// than queued messages (via PostMessage); the destination window procedure