Bug 545338 - RPCChannel should use events rather than thread messages for NotifyWokerThread. r=bent.

This commit is contained in:
Jim Mathies
2010-03-25 16:53:10 -05:00
parent a2e5b35e61
commit c05a8971ee
4 changed files with 62 additions and 57 deletions

View File

@@ -162,7 +162,7 @@ public:
}
protected:
bool WaitForNotify();
bool SpinInternalEventLoop();
void SpinInternalEventLoop();
static bool WaitNeedsSpinLoop() {
return (IsSpinLoopActive() &&
(sModalEventCount > sInnerEventLoopDepth));

View File

@@ -63,12 +63,19 @@ SyncChannel::SyncChannel(SyncListener* aListener)
mNextSeqno(0),
mTimeoutMs(kNoTimeout)
{
MOZ_COUNT_CTOR(SyncChannel);
MOZ_COUNT_CTOR(SyncChannel);
#ifdef OS_WIN
mEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
NS_ASSERTION(mEvent, "CreateEvent failed! Nothing is going to work!");
#endif
}
SyncChannel::~SyncChannel()
{
MOZ_COUNT_DTOR(SyncChannel);
#ifdef OS_WIN
CloseHandle(mEvent);
#endif
}
// static

View File

@@ -154,6 +154,10 @@ protected:
int32 mTimeoutMs;
#ifdef OS_WIN
HANDLE mEvent;
#endif
private:
bool EventOccurred();
};

View File

@@ -103,9 +103,6 @@ using namespace mozilla::ipc::windows;
namespace {
UINT gEventLoopMessage =
RegisterWindowMessage(L"SyncChannel Windows Message Loop Message");
UINT gOOPPSpinNativeLoopEvent =
RegisterWindowMessage(L"SyncChannel Spin Inner Loop Message");
@@ -590,13 +587,17 @@ TimeoutHasExpired(const TimeoutData& aData)
// at the base of the stack. To accomplish this, we use a second counter to
// limit the number of calls to SpinInternalEventLoop() equal to the number
// of modal loops entered.
bool
void
RPCChannel::SpinInternalEventLoop()
{
EnterSpinLoop();
// Nested windows event loop that's triggered when the child enters into modal
// event procedures.
// Nested windows event loop we trigger when the child enters into modal
// event loops.
// Note, when we return, we always reset the notify worker event. So there's
// no need to reset it on return here.
do {
MSG msg = { 0 };
@@ -605,33 +606,21 @@ RPCChannel::SpinInternalEventLoop()
MutexAutoLock lock(mMutex);
if (!Connected()) {
ExitSpinLoop();
return false;
return;
}
}
if (!RPCChannel::IsSpinLoopActive()) {
ExitSpinLoop();
return false;
return;
}
// If a modal loop in the child has exited, we want to disable the spin
// loop. However, we must continue to wait for a response from the last
// rpc call. Returning false here will cause the thread to drop down
// into deferred message processing.
// If a modal loop in the child has exited, disable spin loop and exit.
if (PeekMessageW(&msg, (HWND)-1, gOOPPStopNativeLoopEvent,
gOOPPStopNativeLoopEvent, PM_REMOVE)) {
DecModalLoopCnt();
ExitSpinLoop();
return false;
}
// At whatever depth we currently sit, a reply to the rpc call we were
// waiting for has been received. Exit out of here and respond to it.
// Returning true here causes the WaitForNotify() to return.
if (PeekMessageW(&msg, (HWND)-1, gEventLoopMessage, gEventLoopMessage,
PM_REMOVE)) {
ExitSpinLoop();
return true;
return;
}
// Retrieve window or thread messages
@@ -639,17 +628,13 @@ RPCChannel::SpinInternalEventLoop()
if (msg.message == gOOPPStopNativeLoopEvent) {
DecModalLoopCnt();
ExitSpinLoop();
return false;
return;
}
else if (msg.message == gOOPPSpinNativeLoopEvent) {
// Keep the spin loop counter accurate, multiple plugins can show ui.
IncModalLoopCnt();
continue;
}
else if (msg.message == gEventLoopMessage) {
ExitSpinLoop();
return true;
}
// The child UI should have been destroyed before the app is closed, in
// which case, we should never get this here.
@@ -659,11 +644,22 @@ RPCChannel::SpinInternalEventLoop()
TranslateMessage(&msg);
DispatchMessageW(&msg);
ExitSpinLoop();
return false;
return;
}
} else {
// Block and wait for any posted application messages
WaitMessage();
}
// Note, give dispatching windows events priority over checking if
// mEvent is signaled, otherwise heavy ipc traffic can cause jittery
// playback of video. We'll exit out on each disaptch above, so ipc
// won't get starved.
// Wait for UI events or a signal from the io thread.
DWORD result = MsgWaitForMultipleObjects(1, &mEvent, FALSE, INFINITE,
QS_ALLINPUT);
if (result == WAIT_OBJECT_0) {
// Our NotifyWorkerThread event was signaled
ExitSpinLoop();
return;
}
} while (true);
}
@@ -723,9 +719,14 @@ SyncChannel::WaitForNotify()
// will implicitly have their message queues attached if they are parented
// to one another. This wait call, then, will return for a message
// delivered to *either* thread.
DWORD result = MsgWaitForMultipleObjects(0, NULL, FALSE, INFINITE,
DWORD result = MsgWaitForMultipleObjects(1, &mEvent, FALSE, INFINITE,
QS_ALLINPUT);
if (result != WAIT_OBJECT_0) {
if (result == WAIT_OBJECT_0) {
// Our NotifyWorkerThread event was signaled
ResetEvent(mEvent);
break;
} else
if (result != (WAIT_OBJECT_0 + 1)) {
NS_ERROR("Wait failed!");
break;
}
@@ -752,13 +753,6 @@ SyncChannel::WaitForNotify()
// above. In that case this PeekMessage call won't actually cause any
// mozilla code (or plugin code) to run.
// We check first to see if we should break out of the loop by looking for
// the special message from the IO thread. We pull it out of the queue.
if (PeekMessageW(&msg, (HWND)-1, gEventLoopMessage, gEventLoopMessage,
PM_REMOVE)) {
break;
}
// If the following PeekMessage call fails to return a message for us (and
// returns false) and we didn't run any "nonqueued" messages then we must
// have woken up for a message designated for a window in another thread.
@@ -819,7 +813,8 @@ RPCChannel::WaitForNotify()
if (WaitNeedsSpinLoop()) {
SpinInternalEventLoop();
return true; // bug 545338
ResetEvent(mEvent);
return true;
}
if (++gEventLoopDepth == 1) {
@@ -860,9 +855,14 @@ RPCChannel::WaitForNotify()
}
}
DWORD result = MsgWaitForMultipleObjects(0, NULL, FALSE, INFINITE,
DWORD result = MsgWaitForMultipleObjects(1, &mEvent, FALSE, INFINITE,
QS_ALLINPUT);
if (result != WAIT_OBJECT_0) {
if (result == WAIT_OBJECT_0) {
// Our NotifyWorkerThread event was signaled
ResetEvent(mEvent);
break;
} else
if (result != (WAIT_OBJECT_0 + 1)) {
NS_ERROR("Wait failed!");
break;
}
@@ -907,12 +907,11 @@ RPCChannel::WaitForNotify()
ScheduleDeferredMessageRun();
// Spin the internal dispatch message loop during calls to WaitForNotify
// until the child process tells us the modal loop has closed. A return
// of true indicates gEventLoopMessage was received, exit out of
// WaitForNotify so we can deal with it in RPCChannel.
// until the child process tells us the modal loop has closed.
IncModalLoopCnt();
SpinInternalEventLoop();
return true; // bug 545338
ResetEvent(mEvent);
return true;
}
// If a modal loop in the child has exited, we want to disable the spin
@@ -923,11 +922,6 @@ RPCChannel::WaitForNotify()
break;
}
if (PeekMessageW(&msg, (HWND)-1, gEventLoopMessage, gEventLoopMessage,
PM_REMOVE)) {
break;
}
if (!PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE) &&
!haveSentMessagesPending) {
// Message was for child, we should wait a bit.
@@ -968,9 +962,9 @@ void
SyncChannel::NotifyWorkerThread()
{
mMutex.AssertCurrentThreadOwns();
NS_ASSERTION(gUIThreadId, "This should have been set already!");
if (!PostThreadMessage(gUIThreadId, gEventLoopMessage, 0, 0)) {
NS_WARNING("Failed to post thread message!");
NS_ASSERTION(mEvent, "No signal event to set, this is really bad!");
if (!SetEvent(mEvent)) {
NS_WARNING("Failed to set NotifyWorkerThread event!");
}
}