summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/message_loop/incoming_task_queue.cc5
-rw-r--r--base/message_loop/incoming_task_queue.h3
-rw-r--r--base/message_loop/message_loop.cc4
-rw-r--r--base/message_loop/message_loop.h1
-rw-r--r--base/message_loop/message_pump.h3
-rw-r--r--base/message_loop/message_pump_win.cc138
-rw-r--r--base/message_loop/message_pump_win.h31
-rw-r--r--content/gpu/gpu_main.cc15
8 files changed, 56 insertions, 144 deletions
diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc
index 642222e..5e9a461 100644
--- a/base/message_loop/incoming_task_queue.cc
+++ b/base/message_loop/incoming_task_queue.cc
@@ -119,11 +119,6 @@ void IncomingTaskQueue::StartScheduling() {
ScheduleWork();
}
-TimeTicks IncomingTaskQueue::GetNewlyAddedTaskDelay() {
- return !incoming_queue_.empty() ? incoming_queue_.front().delayed_run_time :
- TimeTicks();
-}
-
IncomingTaskQueue::~IncomingTaskQueue() {
// Verify that WillDestroyCurrentMessageLoop() has been called.
DCHECK(!message_loop_);
diff --git a/base/message_loop/incoming_task_queue.h b/base/message_loop/incoming_task_queue.h
index 544f3e9..7dd1e82 100644
--- a/base/message_loop/incoming_task_queue.h
+++ b/base/message_loop/incoming_task_queue.h
@@ -57,9 +57,6 @@ class BASE_EXPORT IncomingTaskQueue
// scheduling work.
void StartScheduling();
- // Returns the delay for the most recently added task.
- TimeTicks GetNewlyAddedTaskDelay();
-
private:
friend class RefCountedThreadSafe<IncomingTaskQueue>;
virtual ~IncomingTaskQueue();
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index b3c895c..4222c77 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -640,10 +640,6 @@ bool MessageLoop::DoIdleWork() {
return false;
}
-TimeTicks MessageLoop::GetNewlyAddedTaskDelay() {
- return incoming_task_queue_->GetNewlyAddedTaskDelay();
-}
-
void MessageLoop::DeleteSoonInternal(const tracked_objects::Location& from_here,
void(*deleter)(const void*),
const void* object) {
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index 2d67fe5..f2f89d0 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -475,7 +475,6 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
bool DoWork() override;
bool DoDelayedWork(TimeTicks* next_delayed_work_time) override;
bool DoIdleWork() override;
- TimeTicks GetNewlyAddedTaskDelay() override;
const Type type_;
diff --git a/base/message_loop/message_pump.h b/base/message_loop/message_pump.h
index 77a49ce..a2edb45 100644
--- a/base/message_loop/message_pump.h
+++ b/base/message_loop/message_pump.h
@@ -42,9 +42,6 @@ class BASE_EXPORT MessagePump : public NonThreadSafe {
// Returns true to indicate that idle work was done. Returning false means
// the pump will now wait.
virtual bool DoIdleWork() = 0;
-
- // Returns the delay for the newly added task.
- virtual TimeTicks GetNewlyAddedTaskDelay() = 0;
};
MessagePump();
diff --git a/base/message_loop/message_pump_win.cc b/base/message_loop/message_pump_win.cc
index 53f79cd..cdbf0c2 100644
--- a/base/message_loop/message_pump_win.cc
+++ b/base/message_loop/message_pump_win.cc
@@ -12,7 +12,6 @@
#include "base/process/memory.h"
#include "base/profiler/scoped_tracker.h"
#include "base/strings/stringprintf.h"
-#include "base/threading/thread.h"
#include "base/trace_event/trace_event.h"
#include "base/win/wrapped_window_proc.h"
@@ -35,10 +34,6 @@ 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 default delay for the waitable timer used to wake up the UI worker
-// thread.
-static const int64 kDefaultUIWorkerThreadWakeupTimerMs = 3;
-
//-----------------------------------------------------------------------------
// MessagePumpWin public:
@@ -95,38 +90,35 @@ int MessagePumpWin::GetCurrentDelay() const {
MessagePumpForUI::MessagePumpForUI()
: atom_(0) {
InitMessageWnd();
-
- ui_worker_thread_timer_.Set(::CreateWaitableTimer(NULL, FALSE, NULL));
- ui_worker_thread_.reset(new base::Thread("UI Pump Worker thread"));
- ui_worker_thread_->Start();
- ui_worker_thread_->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&MessagePumpForUI::DoWorkerThreadRunLoop,
- base::Unretained(this)));
}
MessagePumpForUI::~MessagePumpForUI() {
DestroyWindow(message_hwnd_);
UnregisterClass(MAKEINTATOM(atom_),
GetModuleFromAddress(&WndProcThunk));
-
- ::QueueUserAPC(
- reinterpret_cast<PAPCFUNC>(&MessagePumpForUI::ShutdownWorkerThread),
- ui_worker_thread_->thread_handle().platform_handle(), NULL);
- ui_worker_thread_->Stop();
}
void MessagePumpForUI::ScheduleWork() {
- // If we have a regular posted task at the head of queue then we need to
- // process it quickly.
- if (state_ && state_->delegate->GetNewlyAddedTaskDelay().is_null()) {
- // Make sure the MessagePump does some work for us.
- PostWorkMessage();
- return;
- }
- // Set a one shot timer to fire after 3 milliseconds. The actual resolution
- // of the timer is dependent on timeBeginPeriod being called.
- SetWakeupTimer(kDefaultUIWorkerThreadWakeupTimerMs);
+ if (InterlockedExchange(&have_work_, 1))
+ return; // Someone else continued the pumping.
+
+ // Make sure the MessagePump does some work for us.
+ BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork,
+ reinterpret_cast<WPARAM>(this), 0);
+ if (ret)
+ return; // There was room in the Window Message queue.
+
+ // We have failed to insert a have-work message, so there is a chance that we
+ // will starve tasks/timers while sitting in a nested message loop. Nested
+ // loops only look at Windows Message queues, and don't look at *our* task
+ // queues, etc., so we might not get a time slice in such. :-(
+ // We could abort here, but the fear is that this failure mode is plausibly
+ // 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.
+ UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR,
+ MESSAGE_LOOP_PROBLEM_MAX);
}
void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
@@ -417,65 +409,45 @@ bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) {
}
bool MessagePumpForUI::ProcessPumpReplacementMessage() {
- // Since we discarded a kMsgHaveWork message, we must update the flag.
- InterlockedExchange(&have_work_, 0);
- return true;
-}
-
-void MessagePumpForUI::DoWorkerThreadRunLoop() {
- DCHECK(ui_worker_thread_timer_.Get());
- while (TRUE) {
- DWORD ret = WaitForSingleObjectEx(
- ui_worker_thread_timer_.Get(), INFINITE, TRUE);
- // The only APC this thread could receive is the Shutdown APC.
- if (ret == WAIT_IO_COMPLETION)
- return;
+ // When we encounter a kMsgHaveWork message, this method is called to peek
+ // and process a replacement message, such as a WM_PAINT or WM_TIMER. The
+ // goal is to make the kMsgHaveWork as non-intrusive as possible, even though
+ // a continuous stream of such messages are posted. This method carefully
+ // peeks a message while there is no chance for a kMsgHaveWork to be pending,
+ // then resets the have_work_ flag (allowing a replacement kMsgHaveWork to
+ // possibly be posted), and finally dispatches that peeked replacement. Note
+ // that the re-post of kMsgHaveWork may be asynchronous to this thread!!
+
+ bool have_message = false;
+ MSG msg;
+ // We should not process all window messages if we are in the context of an
+ // OS modal loop, i.e. in the context of a windows API call like MessageBox.
+ // This is to ensure that these messages are peeked out by the OS modal loop.
+ if (MessageLoop::current()->os_modal_loop()) {
+ // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above.
+ have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) ||
+ PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE);
+ } else {
+ have_message = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE;
+ }
- // Make sure the MessagePump does some work for us.
- PostWorkMessage();
+ DCHECK(!have_message || kMsgHaveWork != msg.message ||
+ msg.hwnd != message_hwnd_);
- // Set a one shot timer to process pending delayed tasks if any in the
- // queue. The actual resolution of the timer is dependent on the
- // timeBeginPeriod API being called.
- SetWakeupTimer(kDefaultUIWorkerThreadWakeupTimerMs);
- }
-}
+ // Since we discarded a kMsgHaveWork message, we must update the flag.
+ int old_have_work = InterlockedExchange(&have_work_, 0);
+ DCHECK(old_have_work);
-// static
-void CALLBACK MessagePumpForUI::ShutdownWorkerThread(ULONG_PTR param) {
- // This function is empty because we only use the fact that an APC was posted
- // to the worker thread to shut it down.
- return;
-}
-
-void MessagePumpForUI::PostWorkMessage() {
- BOOL posted = PostMessage(message_hwnd_, kMsgHaveWork,
- reinterpret_cast<WPARAM>(this),
- 0);
- if (!posted) {
- // We have failed to insert a have-work message, so there is a chance
- // that we will starve tasks/timers while sitting in a nested message
- // loop. Nested loops only look at Windows Message queues, and don't
- // look at *our* task queues, etc., so we might not get a time slice in
- // such. :-(
- // We could abort here, but the fear is that this failure mode is
- // plausibly 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.
- UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem",
- MESSAGE_POST_ERROR,
- MESSAGE_LOOP_PROBLEM_MAX);
- }
-}
+ // We don't need a special time slice if we didn't have_message to process.
+ if (!have_message)
+ return false;
-void MessagePumpForUI::SetWakeupTimer(int64 delay_ms) {
- // Set the timer for the delay passed in. The actual resolution of the
- // timer is dependent on whether timeBeginPeriod was called.
- LARGE_INTEGER due_time = {0};
- due_time.QuadPart = -delay_ms * 10000;
- BOOL timer_set = ::SetWaitableTimer(ui_worker_thread_timer_.Get(),
- &due_time, 0, NULL, NULL, FALSE);
- CHECK(timer_set);
+ // Guarantee we'll get another time slice in the case where we go into native
+ // windows code. This ScheduleWork() may hurt performance a tiny bit when
+ // tasks appear very infrequently, but when the event queue is busy, the
+ // kMsgHaveWork events get (percentage wise) rarer and rarer.
+ ScheduleWork();
+ return ProcessMessageHelper(msg);
}
//-----------------------------------------------------------------------------
diff --git a/base/message_loop/message_pump_win.h b/base/message_loop/message_pump_win.h
index 042efdf..00a1e77 100644
--- a/base/message_loop/message_pump_win.h
+++ b/base/message_loop/message_pump_win.h
@@ -11,7 +11,6 @@
#include "base/base_export.h"
#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_pump.h"
#include "base/message_loop/message_pump_dispatcher.h"
#include "base/observer_list.h"
@@ -20,8 +19,6 @@
namespace base {
-class Thread;
-
// MessagePumpWin serves as the base for specialized versions of the MessagePump
// for Windows. It provides basic functionality like handling of observers and
// controlling the lifetime of the message pump.
@@ -138,39 +135,11 @@ class BASE_EXPORT MessagePumpForUI : public MessagePumpWin {
bool ProcessMessageHelper(const MSG& msg);
bool ProcessPumpReplacementMessage();
- // We spawn a worker thread to periodically post (3 ms) the kMsgHaveWork
- // message to the UI message pump. This is to ensure that the main thread
- // gets to process tasks and delayed tasks when there is no activity in the
- // Windows message pump or when there is a nested modal loop (sizing/moving/
- // drag drop/message boxes) etc.
- void DoWorkerThreadRunLoop();
-
- // This function is posted as part of a user mode APC to shutdown the worker
- // thread when the main message pump is shutting down.
- static void CALLBACK ShutdownWorkerThread(ULONG_PTR param);
-
- // Helper function for posting the kMsgHaveWork message to wake up the pump
- // for processing tasks.
- void PostWorkMessage();
-
- // Helper function to set the waitable timer used to wake up the UI worker
- // thread for processing delayed tasks.
- // |delay_ms| : The delay in milliseconds.
- void SetWakeupTimer(int64 delay_ms);
-
// Atom representing the registered window class.
ATOM atom_;
// A hidden message-only window.
HWND message_hwnd_;
-
- // This thread is used to periodically wake up the main thread to process
- // tasks.
- scoped_ptr<base::Thread> ui_worker_thread_;
-
- // The UI worker thread waits on this timer indefinitely. When the main
- // thread has tasks ready to be processed it sets the timer.
- base::win::ScopedHandle ui_worker_thread_timer_;
};
//-----------------------------------------------------------------------------
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
index 71e493b..c6a59fc 100644
--- a/content/gpu/gpu_main.cc
+++ b/content/gpu/gpu_main.cc
@@ -160,22 +160,9 @@ int GpuMain(const MainFunctionParams& parameters) {
bool dead_on_arrival = false;
#if defined(OS_WIN)
- base::MessageLoop::Type loop_type = base::MessageLoop::TYPE_IO;
// Use a UI message loop because ANGLE and the desktop GL platform can
// create child windows to render to.
- // TODO(ananta) : Recent changes to the UI message pump class on Windows
- // will cause delays in tasks getting processed in the GPU process which
- // will show up on the bots in webgl conformance tests, perf tests etc.
- // It will be great if we can work around the issues with desktop GL and
- // avoid creating a child window in the GPU process which requires a UI
- // message pump.
- if ((command_line.HasSwitch(switches::kUseGL) &&
- command_line.GetSwitchValueASCII(switches::kUseGL) == "desktop") ||
- (command_line.HasSwitch(switches::kUseANGLE) &&
- command_line.GetSwitchValueASCII(switches::kUseANGLE) == "gl")) {
- loop_type = base::MessageLoop::TYPE_UI;
- }
- base::MessageLoop main_message_loop(loop_type);
+ base::MessageLoop main_message_loop(base::MessageLoop::TYPE_UI);
#elif defined(OS_LINUX) && defined(USE_X11)
// We need a UI loop so that we can grab the Expose events. See GLSurfaceGLX
// and https://crbug.com/326995.