$OpenBSD$ index fbb3514..61bd08c 100644 --- ipc/glue/WindowsMessageLoop.cpp.orig Fri Feb 20 15:40:37 2015 +++ ipc/glue/WindowsMessageLoop.cpp Fri Feb 20 15:40:37 2015 @@ -540,19 +540,6 @@ UnhookNeuteredWindows() gNeuteredWindows->Clear(); } -void -Init() -{ - // If we aren't setup before a call to NotifyWorkerThread, we'll hang - // on startup. - if (!gUIThreadId) { - gUIThreadId = GetCurrentThreadId(); - } - NS_ASSERTION(gUIThreadId, "ThreadId should not be 0!"); - NS_ASSERTION(gUIThreadId == GetCurrentThreadId(), - "Running on different threads!"); -} - // This timeout stuff assumes a sane value of mTimeoutMs (less than the overflow // value for GetTickCount(), which is something like 50 days). It uses the // cheapest (and least accurate) method supported by Windows 2000. @@ -594,6 +581,28 @@ TimeoutHasExpired(const TimeoutData& aData) } // anonymous namespace +namespace mozilla { +namespace ipc { +namespace windows { + +void +InitUIThread() +{ + // If we aren't setup before a call to NotifyWorkerThread, we'll hang + // on startup. + if (!gUIThreadId) { + gUIThreadId = GetCurrentThreadId(); + } + MOZ_ASSERT(gUIThreadId); + MOZ_ASSERT(gUIThreadId == GetCurrentThreadId(), + "Called InitUIThread multiple times on different threads!"); +} + +} // namespace windows +} // namespace ipc +} // namespace mozilla + +// See SpinInternalEventLoop below MessageChannel::SyncStackFrame::SyncStackFrame(MessageChannel* channel, bool interrupt) : mInterrupt(interrupt) , mSpinNestedEvents(false) @@ -602,6 +611,12 @@ MessageChannel::SyncStackFrame::SyncStackFrame(MessageChannel* channel, bool int , mPrev(mChannel->mTopFrame) , mStaticPrev(sStaticTopFrame) { + // Only track stack frames when Windows message deferral behavior + // is request for the channel. + if (!(mChannel->GetChannelFlags() & REQUIRE_DEFERRED_MESSAGE_PROTECTION)) { + return; + } + mChannel->mTopFrame = this; sStaticTopFrame = this; @@ -614,6 +629,10 @@ MessageChannel::SyncStackFrame::SyncStackFrame(MessageChannel* channel, bool int MessageChannel::SyncStackFrame::~SyncStackFrame() { + if (!(mChannel->GetChannelFlags() & REQUIRE_DEFERRED_MESSAGE_PROTECTION)) { + return; + } + NS_ASSERTION(this == mChannel->mTopFrame, "Mismatched interrupt stack frames"); NS_ASSERTION(this == sStaticTopFrame, @@ -652,6 +671,8 @@ MessageChannel::NotifyGeckoEventDispatch() void MessageChannel::ProcessNativeEventsInInterruptCall() { + NS_ASSERTION(GetCurrentThreadId() == gUIThreadId, + "Shouldn't be on a non-main thread in here!"); if (!mTopFrame) { NS_ERROR("Spin logic error: no Interrupt frame"); return; @@ -721,14 +742,47 @@ MessageChannel::SpinInternalEventLoop() } while (true); } +static inline bool +IsTimeoutExpired(PRIntervalTime aStart, PRIntervalTime aTimeout) +{ + return (aTimeout != PR_INTERVAL_NO_TIMEOUT) && + (aTimeout <= (PR_IntervalNow() - aStart)); +} + bool MessageChannel::WaitForSyncNotify() { mMonitor->AssertCurrentThreadOwns(); - // Initialize global objects used in deferred messaging. - Init(); + MOZ_ASSERT(gUIThreadId, "InitUIThread was not called!"); + + // Use a blocking wait if this channel does not require + // Windows message deferral behavior. + if (!(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION)) { + PRIntervalTime timeout = (kNoTimeout == mTimeoutMs) ? + PR_INTERVAL_NO_TIMEOUT : + PR_MillisecondsToInterval(mTimeoutMs); + // XXX could optimize away this syscall for "no timeout" case if desired + PRIntervalTime waitStart = 0; + + if (timeout != PR_INTERVAL_NO_TIMEOUT) { + waitStart = PR_IntervalNow(); + } + + mIsSyncWaitingOnNonMainThread = true; + + mMonitor->Wait(timeout); + mIsSyncWaitingOnNonMainThread = false; + + // If the timeout didn't expire, we know we received an event. The + // converse is not true. + return WaitResponse(timeout == PR_INTERVAL_NO_TIMEOUT ? + false : IsTimeoutExpired(waitStart, timeout)); + } + + NS_ASSERTION(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION, + "Shouldn't be here for channels that don't use message deferral!"); NS_ASSERTION(mTopFrame && !mTopFrame->mInterrupt, "Top frame is not a sync frame!"); @@ -848,14 +902,21 @@ MessageChannel::WaitForInterruptNotify() { mMonitor->AssertCurrentThreadOwns(); + MOZ_ASSERT(gUIThreadId, "InitUIThread was not called!"); + + // Re-use sync notification wait code if this channel does not require + // Windows message deferral behavior. + if (!(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION)) { + return WaitForSyncNotify(); + } + if (!InterruptStackDepth()) { // There is currently no way to recover from this condition. NS_RUNTIMEABORT("StackDepth() is 0 in call to MessageChannel::WaitForNotify!"); } - // Initialize global objects used in deferred messaging. - Init(); - + NS_ASSERTION(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION, + "Shouldn't be here for channels that don't use message deferral!"); NS_ASSERTION(mTopFrame && mTopFrame->mInterrupt, "Top frame is not a sync frame!"); @@ -987,6 +1048,12 @@ void MessageChannel::NotifyWorkerThread() { mMonitor->AssertCurrentThreadOwns(); + + if (mIsSyncWaitingOnNonMainThread) { + mMonitor->Notify(); + return; + } + NS_ASSERTION(mEvent, "No signal event to set, this is really bad!"); if (!SetEvent(mEvent)) { NS_WARNING("Failed to set NotifyWorkerThread event!");