| Index: base/message_loop/message_pump_win.cc
|
| diff --git a/base/message_loop/message_pump_win.cc b/base/message_loop/message_pump_win.cc
|
| index da4140f51e9beaf2a9b0ed144b1da14b2dfba263..ac54788539cb062da639e4338fe7b430c85b4449 100644
|
| --- a/base/message_loop/message_pump_win.cc
|
| +++ b/base/message_loop/message_pump_win.cc
|
| @@ -9,6 +9,8 @@
|
|
|
| #include <limits>
|
|
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/message_loop/message_loop.h"
|
| #include "base/metrics/histogram.h"
|
| #include "base/strings/stringprintf.h"
|
| #include "base/trace_event/trace_event.h"
|
| @@ -34,6 +36,9 @@ static const wchar_t kWndClassFormat[] = L"Chrome_MessagePumpWindow_%p";
|
| // task (a series of such messages creates a continuous task pump).
|
| static const int kMsgHaveWork = WM_USER + 1;
|
|
|
| +// The application-defined code passed to the hook procedure.
|
| +static const int kMessageFilterCode = 0x5001;
|
| +
|
| //-----------------------------------------------------------------------------
|
| // MessagePumpWin public:
|
|
|
| @@ -96,7 +101,7 @@ MessagePumpForUI::~MessagePumpForUI() {
|
| }
|
|
|
| void MessagePumpForUI::ScheduleWork() {
|
| - if (InterlockedExchange(&have_work_, 1))
|
| + if (InterlockedExchange(&work_state_, HAVE_WORK) != READY)
|
| return; // Someone else continued the pumping.
|
|
|
| // Make sure the MessagePump does some work for us.
|
| @@ -113,7 +118,9 @@ void MessagePumpForUI::ScheduleWork() {
|
| // common (queue is full, of about 2000 messages), so we'll do a near-graceful
|
| // recovery. Nested loops are pretty transient (we think), so this will
|
| // probably be recoverable.
|
| - InterlockedExchange(&have_work_, 0); // Clarify that we didn't really insert.
|
| +
|
| + // Clarify that we didn't really insert.
|
| + InterlockedExchange(&work_state_, READY);
|
| UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR,
|
| MESSAGE_LOOP_PROBLEM_MAX);
|
| state_->schedule_work_error_count++;
|
| @@ -267,7 +274,7 @@ void MessagePumpForUI::HandleWorkMessage() {
|
| // sort.
|
| if (!state_) {
|
| // Since we handled a kMsgHaveWork message, we must still update this flag.
|
| - InterlockedExchange(&have_work_, 0);
|
| + InterlockedExchange(&work_state_, READY);
|
| return;
|
| }
|
|
|
| @@ -401,8 +408,8 @@ bool MessagePumpForUI::ProcessPumpReplacementMessage() {
|
| msg.hwnd != message_hwnd_);
|
|
|
| // Since we discarded a kMsgHaveWork message, we must update the flag.
|
| - int old_have_work = InterlockedExchange(&have_work_, 0);
|
| - DCHECK(old_have_work);
|
| + int old_work_state_ = InterlockedExchange(&work_state_, READY);
|
| + DCHECK_EQ(HAVE_WORK, old_work_state_);
|
|
|
| // We don't need a special time slice if we didn't have_message to process.
|
| if (!have_message)
|
| @@ -417,6 +424,140 @@ bool MessagePumpForUI::ProcessPumpReplacementMessage() {
|
| }
|
|
|
| //-----------------------------------------------------------------------------
|
| +// MessagePumpForGpu public:
|
| +
|
| +MessagePumpForGpu::MessagePumpForGpu()
|
| + : event_(CreateEvent(nullptr, FALSE, FALSE, nullptr)) {}
|
| +
|
| +MessagePumpForGpu::~MessagePumpForGpu() {
|
| + CloseHandle(event_);
|
| +}
|
| +
|
| +// static
|
| +void MessagePumpForGpu::InitFactory() {
|
| + bool init_result = MessageLoop::InitMessagePumpForUIFactory(
|
| + &MessagePumpForGpu::CreateMessagePumpForGpu);
|
| + DCHECK(init_result);
|
| +}
|
| +
|
| +// static
|
| +std::unique_ptr<MessagePump> MessagePumpForGpu::CreateMessagePumpForGpu() {
|
| + return WrapUnique<MessagePump>(new MessagePumpForGpu);
|
| +}
|
| +
|
| +void MessagePumpForGpu::ScheduleWork() {
|
| + if (InterlockedExchange(&work_state_, HAVE_WORK) != READY)
|
| + return; // Someone else continued the pumping.
|
| +
|
| + // Make sure the MessagePump does some work for us.
|
| + SetEvent(event_);
|
| +}
|
| +
|
| +void MessagePumpForGpu::ScheduleDelayedWork(
|
| + const TimeTicks& delayed_work_time) {
|
| + // We know that we can't be blocked right now since this method can only be
|
| + // called on the same thread as Run, so we only need to update our record of
|
| + // how long to sleep when we do sleep.
|
| + delayed_work_time_ = delayed_work_time;
|
| +}
|
| +
|
| +//-----------------------------------------------------------------------------
|
| +// MessagePumpForGpu private:
|
| +
|
| +void MessagePumpForGpu::DoRunLoop() {
|
| + while (!state_->should_quit) {
|
| + // Indicate that the loop is handling the work.
|
| + // If there is a race condition between switching to WORKING state here and
|
| + // the producer thread setting the HAVE_WORK state after exiting the wait,
|
| + // the event might remain in the signalled state. That might be less than
|
| + // optimal but wouldn't result in failing to handle the work.
|
| + InterlockedExchange(&work_state_, WORKING);
|
| +
|
| + bool more_work_is_plausible = ProcessNextMessage();
|
| + if (state_->should_quit)
|
| + break;
|
| +
|
| + more_work_is_plausible |= state_->delegate->DoWork();
|
| + if (state_->should_quit)
|
| + break;
|
| +
|
| + more_work_is_plausible |=
|
| + state_->delegate->DoDelayedWork(&delayed_work_time_);
|
| + if (state_->should_quit)
|
| + break;
|
| +
|
| + if (more_work_is_plausible)
|
| + continue;
|
| +
|
| + more_work_is_plausible = state_->delegate->DoIdleWork();
|
| + if (state_->should_quit)
|
| + break;
|
| +
|
| + if (more_work_is_plausible)
|
| + continue;
|
| +
|
| + // Switch that working state to READY to indicate that the loop is
|
| + // waiting for accepting new work if it is still in WORKING state and hasn't
|
| + // been signalled. Otherwise if it is in HAVE_WORK state skip the wait
|
| + // and proceed to handing the work.
|
| + if (InterlockedCompareExchange(&work_state_, READY, WORKING) == HAVE_WORK)
|
| + continue; // Skip wait, more work was requested.
|
| +
|
| + WaitForWork(); // Wait (sleep) until we have work to do again.
|
| + }
|
| +}
|
| +
|
| +void MessagePumpForGpu::WaitForWork() {
|
| + // Wait until a message is available, up to the time needed by the timer
|
| + // manager to fire the next set of timers.
|
| + int delay;
|
| +
|
| + // The while loop handles the situation where on Windows 7 and later versions
|
| + // MsgWaitForMultipleObjectsEx might time out slightly earlier (less than one
|
| + // ms) than the specified |delay|. In that situation it is more optimal to
|
| + // just wait again rather than waste a DoRunLoop cycle.
|
| + while ((delay = GetCurrentDelay()) != 0) {
|
| + if (delay < 0) // Negative value means no timers waiting.
|
| + delay = INFINITE;
|
| +
|
| + DWORD result =
|
| + MsgWaitForMultipleObjectsEx(1, &event_, delay, QS_ALLINPUT, 0);
|
| + if (result == WAIT_OBJECT_0) {
|
| + // Work available.
|
| + return;
|
| + } else if (result == WAIT_OBJECT_0 + 1) {
|
| + // Message available. Keep waiting if this message isn't for this thread.
|
| + MSG msg;
|
| + if (PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE))
|
| + return;
|
| + }
|
| +
|
| + DCHECK_NE(WAIT_FAILED, result) << GetLastError();
|
| + }
|
| +}
|
| +
|
| +bool MessagePumpForGpu::ProcessNextMessage() {
|
| + MSG msg;
|
| + if (!PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
|
| + return false;
|
| +
|
| + if (msg.message == WM_QUIT) {
|
| + // Repost the QUIT message so that it will be retrieved by the primary
|
| + // GetMessage() loop.
|
| + state_->should_quit = true;
|
| + PostQuitMessage(static_cast<int>(msg.wParam));
|
| + return false;
|
| + }
|
| +
|
| + if (!CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode)) {
|
| + TranslateMessage(&msg);
|
| + DispatchMessage(&msg);
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +//-----------------------------------------------------------------------------
|
| // MessagePumpForIO public:
|
|
|
| MessagePumpForIO::IOContext::IOContext() {
|
| @@ -431,7 +572,7 @@ MessagePumpForIO::MessagePumpForIO() {
|
| MessagePumpForIO::~MessagePumpForIO() = default;
|
|
|
| void MessagePumpForIO::ScheduleWork() {
|
| - if (InterlockedExchange(&have_work_, 1))
|
| + if (InterlockedExchange(&work_state_, HAVE_WORK) != READY)
|
| return; // Someone else continued the pumping.
|
|
|
| // Make sure the MessagePump does some work for us.
|
| @@ -442,7 +583,7 @@ void MessagePumpForIO::ScheduleWork() {
|
| return; // Post worked perfectly.
|
|
|
| // See comment in MessagePumpForUI::ScheduleWork() for this error recovery.
|
| - InterlockedExchange(&have_work_, 0); // Clarify that we didn't succeed.
|
| + InterlockedExchange(&work_state_, READY); // Clarify that we didn't succeed.
|
| UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR,
|
| MESSAGE_LOOP_PROBLEM_MAX);
|
| state_->schedule_work_error_count++;
|
| @@ -573,7 +714,7 @@ bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) {
|
| reinterpret_cast<void*>(this) == reinterpret_cast<void*>(item.handler)) {
|
| // This is our internal completion.
|
| DCHECK(!item.bytes_transfered);
|
| - InterlockedExchange(&have_work_, 0);
|
| + InterlockedExchange(&work_state_, READY);
|
| return true;
|
| }
|
| return false;
|
|
|