diff --git a/ipc/glue/RPCChannel.h b/ipc/glue/RPCChannel.h index 0cf331eb8a14..3effbdca5270 100644 --- a/ipc/glue/RPCChannel.h +++ b/ipc/glue/RPCChannel.h @@ -162,7 +162,7 @@ public: } protected: bool WaitForNotify(); - bool SpinInternalEventLoop(); + void SpinInternalEventLoop(); static bool WaitNeedsSpinLoop() { return (IsSpinLoopActive() && (sModalEventCount > sInnerEventLoopDepth)); diff --git a/ipc/glue/SyncChannel.cpp b/ipc/glue/SyncChannel.cpp index b8972fc2c35b..1623cc30cc03 100644 --- a/ipc/glue/SyncChannel.cpp +++ b/ipc/glue/SyncChannel.cpp @@ -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 diff --git a/ipc/glue/SyncChannel.h b/ipc/glue/SyncChannel.h index 669b15365a7d..8e3d17fd2e18 100644 --- a/ipc/glue/SyncChannel.h +++ b/ipc/glue/SyncChannel.h @@ -154,6 +154,10 @@ protected: int32 mTimeoutMs; +#ifdef OS_WIN + HANDLE mEvent; +#endif + private: bool EventOccurred(); }; diff --git a/ipc/glue/WindowsMessageLoop.cpp b/ipc/glue/WindowsMessageLoop.cpp index d2e916c08c97..bb4657324cd5 100644 --- a/ipc/glue/WindowsMessageLoop.cpp +++ b/ipc/glue/WindowsMessageLoop.cpp @@ -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!"); } }