зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1273635: Enable alertable waits in content process main thread; r=jimm
MozReview-Commit-ID: 2qGdGj41M0n --HG-- extra : rebase_source : 894ec7ef23b18fd2ed72bc909bc2c743aedaf40c
This commit is contained in:
Родитель
b99626af7a
Коммит
85608bd12a
|
@ -644,6 +644,9 @@ ContentChild::Init(MessageLoop* aIOLoop,
|
|||
abortOnError &= !IsNuwaProcess();
|
||||
#endif
|
||||
GetIPCChannel()->SetAbortOnError(abortOnError);
|
||||
#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; }
|
||||
|
@ -255,7 +260,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);
|
||||
|
|
|
@ -1056,6 +1056,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 +1116,12 @@ MessageChannel::WaitForSyncNotify(bool aHandleWindowsMessages)
|
|||
|
||||
MOZ_ASSERT(gUIThreadId, "InitUIThread was not called!");
|
||||
|
||||
#if defined(ACCESSIBILITY)
|
||||
if (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 (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
|
||||
|
|
Загрузка…
Ссылка в новой задаче