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/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
11 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
12 #include "base/process_util.h" | |
13 #include "base/win/wrapped_window_proc.h" | |
14 | 12 |
15 namespace { | 13 namespace { |
16 | 14 |
17 enum MessageLoopProblems { | 15 enum MessageLoopProblems { |
18 MESSAGE_POST_ERROR, | 16 MESSAGE_POST_ERROR, |
19 COMPLETION_POST_ERROR, | 17 COMPLETION_POST_ERROR, |
20 SET_TIMER_ERROR, | 18 SET_TIMER_ERROR, |
21 MESSAGE_LOOP_PROBLEM_MAX, | 19 MESSAGE_LOOP_PROBLEM_MAX, |
22 }; | 20 }; |
23 | 21 |
24 } // namespace | 22 } // namespace |
25 | 23 |
26 namespace base { | 24 namespace base { |
27 | 25 |
28 static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow"; | |
29 | |
30 // Message sent to get an additional time slice for pumping (processing) another | 26 // Message sent to get an additional time slice for pumping (processing) another |
31 // task (a series of such messages creates a continuous task pump). | 27 // task (a series of such messages creates a continuous task pump). |
32 static const int kMsgHaveWork = WM_USER + 1; | 28 static const int kMsgHaveWork = WM_USER + 1; |
33 | 29 |
34 //----------------------------------------------------------------------------- | 30 //----------------------------------------------------------------------------- |
35 // MessagePumpWin public: | 31 // MessagePumpWin public: |
36 | 32 |
37 void MessagePumpWin::AddObserver(MessagePumpObserver* observer) { | 33 void MessagePumpWin::AddObserver(MessagePumpObserver* observer) { |
38 observers_.AddObserver(observer); | 34 observers_.AddObserver(observer); |
39 } | 35 } |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
89 if (delay < 0) | 85 if (delay < 0) |
90 delay = 0; | 86 delay = 0; |
91 | 87 |
92 return delay; | 88 return delay; |
93 } | 89 } |
94 | 90 |
95 //----------------------------------------------------------------------------- | 91 //----------------------------------------------------------------------------- |
96 // MessagePumpForUI public: | 92 // MessagePumpForUI public: |
97 | 93 |
98 MessagePumpForUI::MessagePumpForUI() | 94 MessagePumpForUI::MessagePumpForUI() |
99 : instance_(NULL), | 95 : message_filter_(new MessageFilter), |
100 message_filter_(new MessageFilter) { | 96 window_(new win::MessageWindow()) { |
101 InitMessageWnd(); | 97 CHECK(window_->Create(this)) << "Couldn't create a message-only window."; |
102 } | 98 } |
103 | 99 |
104 MessagePumpForUI::~MessagePumpForUI() { | 100 MessagePumpForUI::~MessagePumpForUI() { |
105 DestroyWindow(message_hwnd_); | |
106 UnregisterClass(kWndClass, instance_); | |
107 } | 101 } |
108 | 102 |
109 void MessagePumpForUI::ScheduleWork() { | 103 void MessagePumpForUI::ScheduleWork() { |
110 if (InterlockedExchange(&have_work_, 1)) | 104 if (InterlockedExchange(&have_work_, 1)) |
111 return; // Someone else continued the pumping. | 105 return; // Someone else continued the pumping. |
112 | 106 |
113 // Make sure the MessagePump does some work for us. | 107 // Make sure the MessagePump does some work for us. |
114 BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork, | 108 BOOL ret = PostMessage(window_->hwnd(), kMsgHaveWork, |
115 reinterpret_cast<WPARAM>(this), 0); | 109 reinterpret_cast<WPARAM>(this), 0); |
darin (slow to review)
2013/05/23 00:07:14
it looks like it is no longer necessary to stuff |
alexeypa (please no reviews)
2013/05/23 17:45:54
Done.
| |
116 if (ret) | 110 if (ret) |
117 return; // There was room in the Window Message queue. | 111 return; // There was room in the Window Message queue. |
118 | 112 |
119 // We have failed to insert a have-work message, so there is a chance that we | 113 // We have failed to insert a have-work message, so there is a chance that we |
120 // will starve tasks/timers while sitting in a nested message loop. Nested | 114 // will starve tasks/timers while sitting in a nested message loop. Nested |
121 // loops only look at Windows Message queues, and don't look at *our* task | 115 // loops only look at Windows Message queues, and don't look at *our* task |
122 // queues, etc., so we might not get a time slice in such. :-( | 116 // queues, etc., so we might not get a time slice in such. :-( |
123 // We could abort here, but the fear is that this failure mode is plausibly | 117 // We could abort here, but the fear is that this failure mode is plausibly |
124 // common (queue is full, of about 2000 messages), so we'll do a near-graceful | 118 // common (queue is full, of about 2000 messages), so we'll do a near-graceful |
125 // recovery. Nested loops are pretty transient (we think), so this will | 119 // recovery. Nested loops are pretty transient (we think), so this will |
(...skipping 26 matching lines...) Expand all Loading... | |
152 // | 146 // |
153 delayed_work_time_ = delayed_work_time; | 147 delayed_work_time_ = delayed_work_time; |
154 | 148 |
155 int delay_msec = GetCurrentDelay(); | 149 int delay_msec = GetCurrentDelay(); |
156 DCHECK_GE(delay_msec, 0); | 150 DCHECK_GE(delay_msec, 0); |
157 if (delay_msec < USER_TIMER_MINIMUM) | 151 if (delay_msec < USER_TIMER_MINIMUM) |
158 delay_msec = USER_TIMER_MINIMUM; | 152 delay_msec = USER_TIMER_MINIMUM; |
159 | 153 |
160 // Create a WM_TIMER event that will wake us up to check for any pending | 154 // Create a WM_TIMER event that will wake us up to check for any pending |
161 // timers (in case we are running within a nested, external sub-pump). | 155 // timers (in case we are running within a nested, external sub-pump). |
162 BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), | 156 BOOL ret = SetTimer(window_->hwnd(), reinterpret_cast<UINT_PTR>(this), |
darin (slow to review)
2013/05/23 00:07:14
ditto.
alexeypa (please no reviews)
2013/05/23 17:45:54
Done.
| |
163 delay_msec, NULL); | 157 delay_msec, NULL); |
164 if (ret) | 158 if (ret) |
165 return; | 159 return; |
166 // If we can't set timers, we are in big trouble... but cross our fingers for | 160 // If we can't set timers, we are in big trouble... but cross our fingers for |
167 // now. | 161 // now. |
168 // TODO(jar): If we don't see this error, use a CHECK() here instead. | 162 // TODO(jar): If we don't see this error, use a CHECK() here instead. |
169 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR, | 163 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR, |
170 MESSAGE_LOOP_PROBLEM_MAX); | 164 MESSAGE_LOOP_PROBLEM_MAX); |
171 } | 165 } |
172 | 166 |
(...skipping 17 matching lines...) Expand all Loading... | |
190 if (state_->should_quit) // Handle WM_QUIT. | 184 if (state_->should_quit) // Handle WM_QUIT. |
191 break; | 185 break; |
192 } | 186 } |
193 // Histogram what was really being used, to help to adjust kMaxPeekCount. | 187 // Histogram what was really being used, to help to adjust kMaxPeekCount. |
194 DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count); | 188 DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count); |
195 } | 189 } |
196 | 190 |
197 //----------------------------------------------------------------------------- | 191 //----------------------------------------------------------------------------- |
198 // MessagePumpForUI private: | 192 // MessagePumpForUI private: |
199 | 193 |
200 // static | 194 bool MessagePumpForUI::HandleMessage(HWND hwnd, |
201 LRESULT CALLBACK MessagePumpForUI::WndProcThunk( | 195 UINT message, |
202 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { | 196 WPARAM wparam, |
197 LPARAM lparam, | |
198 LRESULT* result) { | |
203 switch (message) { | 199 switch (message) { |
204 case kMsgHaveWork: | 200 case kMsgHaveWork: |
205 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage(); | 201 HandleWorkMessage(); |
206 break; | 202 break; |
203 | |
207 case WM_TIMER: | 204 case WM_TIMER: |
208 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage(); | 205 HandleTimerMessage(); |
209 break; | 206 break; |
210 } | 207 } |
211 return DefWindowProc(hwnd, message, wparam, lparam); | 208 |
209 // Do default processing for all messages. | |
210 return false; | |
212 } | 211 } |
213 | 212 |
214 void MessagePumpForUI::DoRunLoop() { | 213 void MessagePumpForUI::DoRunLoop() { |
215 // IF this was just a simple PeekMessage() loop (servicing all possible work | 214 // IF this was just a simple PeekMessage() loop (servicing all possible work |
216 // queues), then Windows would try to achieve the following order according | 215 // queues), then Windows would try to achieve the following order according |
217 // to MSDN documentation about PeekMessage with no filter): | 216 // to MSDN documentation about PeekMessage with no filter): |
218 // * Sent messages | 217 // * Sent messages |
219 // * Posted messages | 218 // * Posted messages |
220 // * Sent messages (again) | 219 // * Sent messages (again) |
221 // * WM_PAINT messages | 220 // * WM_PAINT messages |
(...skipping 20 matching lines...) Expand all Loading... | |
242 if (state_->should_quit) | 241 if (state_->should_quit) |
243 break; | 242 break; |
244 | 243 |
245 more_work_is_plausible |= | 244 more_work_is_plausible |= |
246 state_->delegate->DoDelayedWork(&delayed_work_time_); | 245 state_->delegate->DoDelayedWork(&delayed_work_time_); |
247 // If we did not process any delayed work, then we can assume that our | 246 // If we did not process any delayed work, then we can assume that our |
248 // existing WM_TIMER if any will fire when delayed work should run. We | 247 // existing WM_TIMER if any will fire when delayed work should run. We |
249 // don't want to disturb that timer if it is already in flight. However, | 248 // don't want to disturb that timer if it is already in flight. However, |
250 // if we did do all remaining delayed work, then lets kill the WM_TIMER. | 249 // if we did do all remaining delayed work, then lets kill the WM_TIMER. |
251 if (more_work_is_plausible && delayed_work_time_.is_null()) | 250 if (more_work_is_plausible && delayed_work_time_.is_null()) |
252 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); | 251 KillTimer(window_->hwnd(), reinterpret_cast<UINT_PTR>(this)); |
253 if (state_->should_quit) | 252 if (state_->should_quit) |
254 break; | 253 break; |
255 | 254 |
256 if (more_work_is_plausible) | 255 if (more_work_is_plausible) |
257 continue; | 256 continue; |
258 | 257 |
259 more_work_is_plausible = state_->delegate->DoIdleWork(); | 258 more_work_is_plausible = state_->delegate->DoIdleWork(); |
260 if (state_->should_quit) | 259 if (state_->should_quit) |
261 break; | 260 break; |
262 | 261 |
263 if (more_work_is_plausible) | 262 if (more_work_is_plausible) |
264 continue; | 263 continue; |
265 | 264 |
266 WaitForWork(); // Wait (sleep) until we have work to do again. | 265 WaitForWork(); // Wait (sleep) until we have work to do again. |
267 } | 266 } |
268 } | 267 } |
269 | 268 |
270 void MessagePumpForUI::InitMessageWnd() { | |
271 WNDCLASSEX wc = {0}; | |
272 wc.cbSize = sizeof(wc); | |
273 wc.lpfnWndProc = base::win::WrappedWindowProc<WndProcThunk>; | |
274 wc.hInstance = base::GetModuleFromAddress(wc.lpfnWndProc); | |
275 wc.lpszClassName = kWndClass; | |
darin (slow to review)
2013/05/22 22:53:24
wouldn't it be a simpler change to just give each
alexeypa (please no reviews)
2013/05/22 23:04:48
This is pretty much what this CL does. It is just
| |
276 instance_ = wc.hInstance; | |
277 RegisterClassEx(&wc); | |
278 | |
279 message_hwnd_ = | |
280 CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, instance_, 0); | |
281 DCHECK(message_hwnd_); | |
282 } | |
283 | |
284 void MessagePumpForUI::WaitForWork() { | 269 void MessagePumpForUI::WaitForWork() { |
285 // Wait until a message is available, up to the time needed by the timer | 270 // Wait until a message is available, up to the time needed by the timer |
286 // manager to fire the next set of timers. | 271 // manager to fire the next set of timers. |
287 int delay = GetCurrentDelay(); | 272 int delay = GetCurrentDelay(); |
288 if (delay < 0) // Negative value means no timers waiting. | 273 if (delay < 0) // Negative value means no timers waiting. |
289 delay = INFINITE; | 274 delay = INFINITE; |
290 | 275 |
291 DWORD result; | 276 DWORD result; |
292 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, | 277 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, |
293 MWMO_INPUTAVAILABLE); | 278 MWMO_INPUTAVAILABLE); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
331 // messages that may be in the Windows message queue. | 316 // messages that may be in the Windows message queue. |
332 ProcessPumpReplacementMessage(); | 317 ProcessPumpReplacementMessage(); |
333 | 318 |
334 // Now give the delegate a chance to do some work. He'll let us know if he | 319 // Now give the delegate a chance to do some work. He'll let us know if he |
335 // needs to do more work. | 320 // needs to do more work. |
336 if (state_->delegate->DoWork()) | 321 if (state_->delegate->DoWork()) |
337 ScheduleWork(); | 322 ScheduleWork(); |
338 } | 323 } |
339 | 324 |
340 void MessagePumpForUI::HandleTimerMessage() { | 325 void MessagePumpForUI::HandleTimerMessage() { |
341 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); | 326 KillTimer(window_->hwnd(), reinterpret_cast<UINT_PTR>(this)); |
342 | 327 |
343 // If we are being called outside of the context of Run, then don't do | 328 // If we are being called outside of the context of Run, then don't do |
344 // anything. This could correspond to a MessageBox call or something of | 329 // anything. This could correspond to a MessageBox call or something of |
345 // that sort. | 330 // that sort. |
346 if (!state_) | 331 if (!state_) |
347 return; | 332 return; |
348 | 333 |
349 state_->delegate->DoDelayedWork(&delayed_work_time_); | 334 state_->delegate->DoDelayedWork(&delayed_work_time_); |
350 if (!delayed_work_time_.is_null()) { | 335 if (!delayed_work_time_.is_null()) { |
351 // A bit gratuitous to set delayed_work_time_ again, but oh well. | 336 // A bit gratuitous to set delayed_work_time_ again, but oh well. |
(...skipping 23 matching lines...) Expand all Loading... | |
375 "message", msg.message); | 360 "message", msg.message); |
376 if (WM_QUIT == msg.message) { | 361 if (WM_QUIT == msg.message) { |
377 // Repost the QUIT message so that it will be retrieved by the primary | 362 // Repost the QUIT message so that it will be retrieved by the primary |
378 // GetMessage() loop. | 363 // GetMessage() loop. |
379 state_->should_quit = true; | 364 state_->should_quit = true; |
380 PostQuitMessage(static_cast<int>(msg.wParam)); | 365 PostQuitMessage(static_cast<int>(msg.wParam)); |
381 return false; | 366 return false; |
382 } | 367 } |
383 | 368 |
384 // While running our main message pump, we discard kMsgHaveWork messages. | 369 // While running our main message pump, we discard kMsgHaveWork messages. |
385 if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_) | 370 if (msg.message == kMsgHaveWork && msg.hwnd == window_->hwnd()) |
386 return ProcessPumpReplacementMessage(); | 371 return ProcessPumpReplacementMessage(); |
387 | 372 |
388 if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode)) | 373 if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode)) |
389 return true; | 374 return true; |
390 | 375 |
391 WillProcessMessage(msg); | 376 WillProcessMessage(msg); |
392 | 377 |
393 if (!message_filter_->ProcessMessage(msg)) { | 378 if (!message_filter_->ProcessMessage(msg)) { |
394 if (state_->dispatcher) { | 379 if (state_->dispatcher) { |
395 if (!state_->dispatcher->Dispatch(msg)) | 380 if (!state_->dispatcher->Dispatch(msg)) |
(...skipping 26 matching lines...) Expand all Loading... | |
422 if (MessageLoop::current()->os_modal_loop()) { | 407 if (MessageLoop::current()->os_modal_loop()) { |
423 // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above. | 408 // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above. |
424 have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) || | 409 have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) || |
425 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); | 410 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); |
426 } else { | 411 } else { |
427 have_message = !!message_filter_->DoPeekMessage(&msg, NULL, 0, 0, | 412 have_message = !!message_filter_->DoPeekMessage(&msg, NULL, 0, 0, |
428 PM_REMOVE); | 413 PM_REMOVE); |
429 } | 414 } |
430 | 415 |
431 DCHECK(!have_message || kMsgHaveWork != msg.message || | 416 DCHECK(!have_message || kMsgHaveWork != msg.message || |
432 msg.hwnd != message_hwnd_); | 417 msg.hwnd != window_->hwnd()); |
433 | 418 |
434 // Since we discarded a kMsgHaveWork message, we must update the flag. | 419 // Since we discarded a kMsgHaveWork message, we must update the flag. |
435 int old_have_work = InterlockedExchange(&have_work_, 0); | 420 int old_have_work = InterlockedExchange(&have_work_, 0); |
436 DCHECK(old_have_work); | 421 DCHECK(old_have_work); |
437 | 422 |
438 // We don't need a special time slice if we didn't have_message to process. | 423 // We don't need a special time slice if we didn't have_message to process. |
439 if (!have_message) | 424 if (!have_message) |
440 return false; | 425 return false; |
441 | 426 |
442 // Guarantee we'll get another time slice in the case where we go into native | 427 // Guarantee we'll get another time slice in the case where we go into native |
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
671 | 656 |
672 // static | 657 // static |
673 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( | 658 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( |
674 ULONG_PTR key, | 659 ULONG_PTR key, |
675 bool* has_valid_io_context) { | 660 bool* has_valid_io_context) { |
676 *has_valid_io_context = ((key & 1) == 0); | 661 *has_valid_io_context = ((key & 1) == 0); |
677 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); | 662 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); |
678 } | 663 } |
679 | 664 |
680 } // namespace base | 665 } // namespace base |
OLD | NEW |