OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/message_pump_win.h" | 5 #include "base/message_pump_win.h" |
6 | 6 |
7 #include <math.h> | 7 #include <math.h> |
8 | 8 |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 #include "base/win/wrapped_window_proc.h" | 11 #include "base/win/wrapped_window_proc.h" |
12 | 12 |
| 13 namespace { |
| 14 |
| 15 enum MessageLoopProblems { |
| 16 MESSAGE_POST_ERROR, |
| 17 COMPLETION_POST_ERROR, |
| 18 SET_TIMER_ERROR, |
| 19 MESSAGE_LOOP_PROBLEM_MAX, |
| 20 }; |
| 21 |
| 22 } // namespace |
| 23 |
13 namespace base { | 24 namespace base { |
14 | 25 |
15 static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow"; | 26 static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow"; |
16 | 27 |
17 // Message sent to get an additional time slice for pumping (processing) another | 28 // Message sent to get an additional time slice for pumping (processing) another |
18 // task (a series of such messages creates a continuous task pump). | 29 // task (a series of such messages creates a continuous task pump). |
19 static const int kMsgHaveWork = WM_USER + 1; | 30 static const int kMsgHaveWork = WM_USER + 1; |
20 | 31 |
21 //----------------------------------------------------------------------------- | 32 //----------------------------------------------------------------------------- |
22 // MessagePumpWin public: | 33 // MessagePumpWin public: |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 MessagePumpForUI::~MessagePumpForUI() { | 100 MessagePumpForUI::~MessagePumpForUI() { |
90 DestroyWindow(message_hwnd_); | 101 DestroyWindow(message_hwnd_); |
91 UnregisterClass(kWndClass, GetModuleHandle(NULL)); | 102 UnregisterClass(kWndClass, GetModuleHandle(NULL)); |
92 } | 103 } |
93 | 104 |
94 void MessagePumpForUI::ScheduleWork() { | 105 void MessagePumpForUI::ScheduleWork() { |
95 if (InterlockedExchange(&have_work_, 1)) | 106 if (InterlockedExchange(&have_work_, 1)) |
96 return; // Someone else continued the pumping. | 107 return; // Someone else continued the pumping. |
97 | 108 |
98 // Make sure the MessagePump does some work for us. | 109 // Make sure the MessagePump does some work for us. |
99 PostMessage(message_hwnd_, kMsgHaveWork, reinterpret_cast<WPARAM>(this), 0); | 110 BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork, |
| 111 reinterpret_cast<WPARAM>(this), 0); |
| 112 if (ret) |
| 113 return; // There was room in the Window Message queue. |
| 114 |
| 115 // We have failed to insert a have-work message, so there is a chance that we |
| 116 // will starve tasks/timers while sitting in a nested message loop. Nested |
| 117 // loops only look at Windows Message queues, and don't look at *our* task |
| 118 // queues, etc., so we might not get a time slice in such. :-( |
| 119 // We could abort here, but the fear is that this failure mode is plausibly |
| 120 // common (queue is full, of about 2000 messages), so we'll do a near-graceful |
| 121 // recovery. Nested loops are pretty transient (we think), so this will |
| 122 // probably be recoverable. |
| 123 InterlockedExchange(&have_work_, 0); // Clarify that we didn't really insert. |
| 124 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR, |
| 125 MESSAGE_LOOP_PROBLEM_MAX); |
100 } | 126 } |
101 | 127 |
102 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { | 128 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { |
103 // | 129 // |
104 // We would *like* to provide high resolution timers. Windows timers using | 130 // We would *like* to provide high resolution timers. Windows timers using |
105 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup | 131 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup |
106 // mechanism because the application can enter modal windows loops where it | 132 // mechanism because the application can enter modal windows loops where it |
107 // is not running our MessageLoop; the only way to have our timers fire in | 133 // is not running our MessageLoop; the only way to have our timers fire in |
108 // these cases is to post messages there. | 134 // these cases is to post messages there. |
109 // | 135 // |
(...skipping 12 matching lines...) Expand all Loading... |
122 // | 148 // |
123 delayed_work_time_ = delayed_work_time; | 149 delayed_work_time_ = delayed_work_time; |
124 | 150 |
125 int delay_msec = GetCurrentDelay(); | 151 int delay_msec = GetCurrentDelay(); |
126 DCHECK_GE(delay_msec, 0); | 152 DCHECK_GE(delay_msec, 0); |
127 if (delay_msec < USER_TIMER_MINIMUM) | 153 if (delay_msec < USER_TIMER_MINIMUM) |
128 delay_msec = USER_TIMER_MINIMUM; | 154 delay_msec = USER_TIMER_MINIMUM; |
129 | 155 |
130 // Create a WM_TIMER event that will wake us up to check for any pending | 156 // Create a WM_TIMER event that will wake us up to check for any pending |
131 // timers (in case we are running within a nested, external sub-pump). | 157 // timers (in case we are running within a nested, external sub-pump). |
132 SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), delay_msec, NULL); | 158 BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), |
| 159 delay_msec, NULL); |
| 160 if (ret) |
| 161 return; |
| 162 // If we can't set timers, we are in big trouble... but cross our fingers for |
| 163 // now. |
| 164 // TODO(jar): If we don't see this error, use a CHECK() here instead. |
| 165 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR, |
| 166 MESSAGE_LOOP_PROBLEM_MAX); |
133 } | 167 } |
134 | 168 |
135 void MessagePumpForUI::PumpOutPendingPaintMessages() { | 169 void MessagePumpForUI::PumpOutPendingPaintMessages() { |
136 // If we are being called outside of the context of Run, then don't try to do | 170 // If we are being called outside of the context of Run, then don't try to do |
137 // any work. | 171 // any work. |
138 if (!state_) | 172 if (!state_) |
139 return; | 173 return; |
140 | 174 |
141 // Create a mini-message-pump to force immediate processing of only Windows | 175 // Create a mini-message-pump to force immediate processing of only Windows |
142 // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking | 176 // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
413 } | 447 } |
414 | 448 |
415 void MessagePumpForIO::ScheduleWork() { | 449 void MessagePumpForIO::ScheduleWork() { |
416 if (InterlockedExchange(&have_work_, 1)) | 450 if (InterlockedExchange(&have_work_, 1)) |
417 return; // Someone else continued the pumping. | 451 return; // Someone else continued the pumping. |
418 | 452 |
419 // Make sure the MessagePump does some work for us. | 453 // Make sure the MessagePump does some work for us. |
420 BOOL ret = PostQueuedCompletionStatus(port_, 0, | 454 BOOL ret = PostQueuedCompletionStatus(port_, 0, |
421 reinterpret_cast<ULONG_PTR>(this), | 455 reinterpret_cast<ULONG_PTR>(this), |
422 reinterpret_cast<OVERLAPPED*>(this)); | 456 reinterpret_cast<OVERLAPPED*>(this)); |
423 DCHECK(ret); | 457 if (ret) |
| 458 return; // Post worked perfectly. |
| 459 |
| 460 // See comment in MessagePumpForUI::ScheduleWork() for this error recovery. |
| 461 InterlockedExchange(&have_work_, 0); // Clarify that we didn't succeed. |
| 462 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR, |
| 463 MESSAGE_LOOP_PROBLEM_MAX); |
424 } | 464 } |
425 | 465 |
426 void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { | 466 void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { |
427 // We know that we can't be blocked right now since this method can only be | 467 // We know that we can't be blocked right now since this method can only be |
428 // called on the same thread as Run, so we only need to update our record of | 468 // called on the same thread as Run, so we only need to update our record of |
429 // how long to sleep when we do sleep. | 469 // how long to sleep when we do sleep. |
430 delayed_work_time_ = delayed_work_time; | 470 delayed_work_time_ = delayed_work_time; |
431 } | 471 } |
432 | 472 |
433 void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle, | 473 void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle, |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
574 | 614 |
575 void MessagePumpForIO::WillProcessIOEvent() { | 615 void MessagePumpForIO::WillProcessIOEvent() { |
576 FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent()); | 616 FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent()); |
577 } | 617 } |
578 | 618 |
579 void MessagePumpForIO::DidProcessIOEvent() { | 619 void MessagePumpForIO::DidProcessIOEvent() { |
580 FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent()); | 620 FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent()); |
581 } | 621 } |
582 | 622 |
583 } // namespace base | 623 } // namespace base |
OLD | NEW |