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_loop/message_pump_win.h" | 5 #include "base/message_loop/message_pump_win.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 #include <math.h> | 8 #include <math.h> |
9 | 9 |
10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 // We could abort here, but the fear is that this failure mode is plausibly | 115 // We could abort here, but the fear is that this failure mode is plausibly |
116 // common (queue is full, of about 2000 messages), so we'll do a near-graceful | 116 // common (queue is full, of about 2000 messages), so we'll do a near-graceful |
117 // recovery. Nested loops are pretty transient (we think), so this will | 117 // recovery. Nested loops are pretty transient (we think), so this will |
118 // probably be recoverable. | 118 // probably be recoverable. |
119 InterlockedExchange(&have_work_, 0); // Clarify that we didn't really insert. | 119 InterlockedExchange(&have_work_, 0); // Clarify that we didn't really insert. |
120 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR, | 120 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR, |
121 MESSAGE_LOOP_PROBLEM_MAX); | 121 MESSAGE_LOOP_PROBLEM_MAX); |
122 } | 122 } |
123 | 123 |
124 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { | 124 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { |
125 // | |
126 // We would *like* to provide high resolution timers. Windows timers using | |
127 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup | |
128 // mechanism because the application can enter modal windows loops where it | |
129 // is not running our MessageLoop; the only way to have our timers fire in | |
130 // these cases is to post messages there. | |
131 // | |
132 // To provide sub-10ms timers, we process timers directly from our run loop. | |
133 // For the common case, timers will be processed there as the run loop does | |
134 // its normal work. However, we *also* set the system timer so that WM_TIMER | |
135 // events fire. This mops up the case of timers not being able to work in | |
136 // modal message loops. It is possible for the SetTimer to pop and have no | |
137 // pending timers, because they could have already been processed by the | |
138 // run loop itself. | |
139 // | |
140 // We use a single SetTimer corresponding to the timer that will expire | |
141 // soonest. As new timers are created and destroyed, we update SetTimer. | |
142 // Getting a spurrious SetTimer event firing is benign, as we'll just be | |
143 // processing an empty timer queue. | |
144 // | |
145 delayed_work_time_ = delayed_work_time; | 125 delayed_work_time_ = delayed_work_time; |
146 | 126 RescheduleTimer(); |
147 int delay_msec = GetCurrentDelay(); | |
148 DCHECK_GE(delay_msec, 0); | |
149 if (delay_msec < USER_TIMER_MINIMUM) | |
150 delay_msec = USER_TIMER_MINIMUM; | |
151 | |
152 // Create a WM_TIMER event that will wake us up to check for any pending | |
153 // timers (in case we are running within a nested, external sub-pump). | |
154 BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), | |
155 delay_msec, NULL); | |
156 if (ret) | |
157 return; | |
158 // If we can't set timers, we are in big trouble... but cross our fingers for | |
159 // now. | |
160 // TODO(jar): If we don't see this error, use a CHECK() here instead. | |
161 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR, | |
162 MESSAGE_LOOP_PROBLEM_MAX); | |
163 } | 127 } |
164 | 128 |
165 //----------------------------------------------------------------------------- | 129 //----------------------------------------------------------------------------- |
166 // MessagePumpForUI private: | 130 // MessagePumpForUI private: |
167 | 131 |
168 // static | 132 // static |
169 LRESULT CALLBACK MessagePumpForUI::WndProcThunk( | 133 LRESULT CALLBACK MessagePumpForUI::WndProcThunk( |
170 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { | 134 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { |
171 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. | 135 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. |
172 tracked_objects::ScopedTracker tracking_profile1( | 136 tracked_objects::ScopedTracker tracking_profile1( |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
311 | 275 |
312 // Let whatever would have run had we not been putting messages in the queue | 276 // Let whatever would have run had we not been putting messages in the queue |
313 // run now. This is an attempt to make our dummy message not starve other | 277 // run now. This is an attempt to make our dummy message not starve other |
314 // messages that may be in the Windows message queue. | 278 // messages that may be in the Windows message queue. |
315 ProcessPumpReplacementMessage(); | 279 ProcessPumpReplacementMessage(); |
316 | 280 |
317 // Now give the delegate a chance to do some work. He'll let us know if he | 281 // Now give the delegate a chance to do some work. He'll let us know if he |
318 // needs to do more work. | 282 // needs to do more work. |
319 if (state_->delegate->DoWork()) | 283 if (state_->delegate->DoWork()) |
320 ScheduleWork(); | 284 ScheduleWork(); |
| 285 state_->delegate->DoDelayedWork(&delayed_work_time_); |
| 286 RescheduleTimer(); |
321 } | 287 } |
322 | 288 |
323 void MessagePumpForUI::HandleTimerMessage() { | 289 void MessagePumpForUI::HandleTimerMessage() { |
324 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); | 290 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); |
325 | 291 |
326 // If we are being called outside of the context of Run, then don't do | 292 // If we are being called outside of the context of Run, then don't do |
327 // anything. This could correspond to a MessageBox call or something of | 293 // anything. This could correspond to a MessageBox call or something of |
328 // that sort. | 294 // that sort. |
329 if (!state_) | 295 if (!state_) |
330 return; | 296 return; |
331 | 297 |
332 state_->delegate->DoDelayedWork(&delayed_work_time_); | 298 state_->delegate->DoDelayedWork(&delayed_work_time_); |
333 if (!delayed_work_time_.is_null()) { | 299 RescheduleTimer(); |
334 // A bit gratuitous to set delayed_work_time_ again, but oh well. | 300 } |
335 ScheduleDelayedWork(delayed_work_time_); | 301 |
| 302 void MessagePumpForUI::RescheduleTimer() { |
| 303 if (delayed_work_time_.is_null()) |
| 304 return; |
| 305 // |
| 306 // We would *like* to provide high resolution timers. Windows timers using |
| 307 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup |
| 308 // mechanism because the application can enter modal windows loops where it |
| 309 // is not running our MessageLoop; the only way to have our timers fire in |
| 310 // these cases is to post messages there. |
| 311 // |
| 312 // To provide sub-10ms timers, we process timers directly from our run loop. |
| 313 // For the common case, timers will be processed there as the run loop does |
| 314 // its normal work. However, we *also* set the system timer so that WM_TIMER |
| 315 // events fire. This mops up the case of timers not being able to work in |
| 316 // modal message loops. It is possible for the SetTimer to pop and have no |
| 317 // pending timers, because they could have already been processed by the |
| 318 // run loop itself. |
| 319 // |
| 320 // We use a single SetTimer corresponding to the timer that will expire |
| 321 // soonest. As new timers are created and destroyed, we update SetTimer. |
| 322 // Getting a spurrious SetTimer event firing is benign, as we'll just be |
| 323 // processing an empty timer queue. |
| 324 // |
| 325 int delay_msec = GetCurrentDelay(); |
| 326 DCHECK_GE(delay_msec, 0); |
| 327 if (delay_msec == 0) { |
| 328 ScheduleWork(); |
| 329 } else { |
| 330 if (delay_msec < USER_TIMER_MINIMUM) |
| 331 delay_msec = USER_TIMER_MINIMUM; |
| 332 |
| 333 // Create a WM_TIMER event that will wake us up to check for any pending |
| 334 // timers (in case we are running within a nested, external sub-pump). |
| 335 BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), |
| 336 delay_msec, NULL); |
| 337 if (ret) |
| 338 return; |
| 339 // If we can't set timers, we are in big trouble... but cross our fingers |
| 340 // for now. |
| 341 // TODO(jar): If we don't see this error, use a CHECK() here instead. |
| 342 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR, |
| 343 MESSAGE_LOOP_PROBLEM_MAX); |
336 } | 344 } |
337 } | 345 } |
338 | 346 |
339 bool MessagePumpForUI::ProcessNextWindowsMessage() { | 347 bool MessagePumpForUI::ProcessNextWindowsMessage() { |
340 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. | 348 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. |
341 tracked_objects::ScopedTracker tracking_profile1( | 349 tracked_objects::ScopedTracker tracking_profile1( |
342 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 350 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
343 "440919 MessagePumpForUI::ProcessNextWindowsMessage1")); | 351 "440919 MessagePumpForUI::ProcessNextWindowsMessage1")); |
344 | 352 |
345 // If there are sent messages in the queue then PeekMessage internally | 353 // If there are sent messages in the queue then PeekMessage internally |
(...skipping 11 matching lines...) Expand all Loading... |
357 "440919 MessagePumpForUI::ProcessNextWindowsMessage2")); | 365 "440919 MessagePumpForUI::ProcessNextWindowsMessage2")); |
358 | 366 |
359 MSG msg; | 367 MSG msg; |
360 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE) | 368 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE) |
361 return ProcessMessageHelper(msg); | 369 return ProcessMessageHelper(msg); |
362 | 370 |
363 return sent_messages_in_queue; | 371 return sent_messages_in_queue; |
364 } | 372 } |
365 | 373 |
366 bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) { | 374 bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) { |
367 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. | |
368 tracked_objects::ScopedTracker tracking_profile1( | |
369 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
370 "440919 MessagePumpForUI::ProcessMessageHelper1")); | |
371 | |
372 TRACE_EVENT1("base", "MessagePumpForUI::ProcessMessageHelper", | 375 TRACE_EVENT1("base", "MessagePumpForUI::ProcessMessageHelper", |
373 "message", msg.message); | 376 "message", msg.message); |
374 if (WM_QUIT == msg.message) { | 377 if (WM_QUIT == msg.message) { |
375 // Repost the QUIT message so that it will be retrieved by the primary | 378 // Repost the QUIT message so that it will be retrieved by the primary |
376 // GetMessage() loop. | 379 // GetMessage() loop. |
377 state_->should_quit = true; | 380 state_->should_quit = true; |
378 PostQuitMessage(static_cast<int>(msg.wParam)); | 381 PostQuitMessage(static_cast<int>(msg.wParam)); |
379 return false; | 382 return false; |
380 } | 383 } |
381 | 384 |
382 // While running our main message pump, we discard kMsgHaveWork messages. | 385 // While running our main message pump, we discard kMsgHaveWork messages. |
383 if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_) | 386 if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_) |
384 return ProcessPumpReplacementMessage(); | 387 return ProcessPumpReplacementMessage(); |
385 | 388 |
386 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. | |
387 tracked_objects::ScopedTracker tracking_profile2( | |
388 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
389 "440919 MessagePumpForUI::ProcessMessageHelper2")); | |
390 | |
391 if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode)) | 389 if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode)) |
392 return true; | 390 return true; |
393 | 391 |
394 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. | |
395 tracked_objects::ScopedTracker tracking_profile3( | |
396 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
397 "440919 MessagePumpForUI::ProcessMessageHelper3")); | |
398 | |
399 uint32_t action = MessagePumpDispatcher::POST_DISPATCH_PERFORM_DEFAULT; | 392 uint32_t action = MessagePumpDispatcher::POST_DISPATCH_PERFORM_DEFAULT; |
400 if (state_->dispatcher) { | 393 if (state_->dispatcher) { |
401 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. | 394 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. |
402 tracked_objects::ScopedTracker tracking_profile4( | 395 tracked_objects::ScopedTracker tracking_profile4( |
403 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 396 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
404 "440919 MessagePumpForUI::ProcessMessageHelper4")); | 397 "440919 MessagePumpForUI::ProcessMessageHelper4")); |
405 | 398 |
406 action = state_->dispatcher->Dispatch(msg); | 399 action = state_->dispatcher->Dispatch(msg); |
407 } | 400 } |
408 if (action & MessagePumpDispatcher::POST_DISPATCH_QUIT_LOOP) | 401 if (action & MessagePumpDispatcher::POST_DISPATCH_QUIT_LOOP) |
409 state_->should_quit = true; | 402 state_->should_quit = true; |
410 if (action & MessagePumpDispatcher::POST_DISPATCH_PERFORM_DEFAULT) { | 403 if (action & MessagePumpDispatcher::POST_DISPATCH_PERFORM_DEFAULT) { |
411 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. | |
412 tracked_objects::ScopedTracker tracking_profile5( | |
413 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
414 "440919 MessagePumpForUI::ProcessMessageHelper5")); | |
415 | |
416 TranslateMessage(&msg); | 404 TranslateMessage(&msg); |
417 | |
418 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. | |
419 tracked_objects::ScopedTracker tracking_profile6( | |
420 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
421 "440919 MessagePumpForUI::ProcessMessageHelper6")); | |
422 | |
423 DispatchMessage(&msg); | 405 DispatchMessage(&msg); |
424 } | 406 } |
425 | 407 |
426 return true; | 408 return true; |
427 } | 409 } |
428 | 410 |
429 bool MessagePumpForUI::ProcessPumpReplacementMessage() { | 411 bool MessagePumpForUI::ProcessPumpReplacementMessage() { |
430 // When we encounter a kMsgHaveWork message, this method is called to peek | 412 // When we encounter a kMsgHaveWork message, this method is called to peek |
431 // and process a replacement message, such as a WM_PAINT or WM_TIMER. The | 413 // and process a replacement message, such as a WM_PAINT or WM_TIMER. The |
432 // goal is to make the kMsgHaveWork as non-intrusive as possible, even though | 414 // goal is to make the kMsgHaveWork as non-intrusive as possible, even though |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
690 | 672 |
691 // static | 673 // static |
692 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( | 674 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( |
693 ULONG_PTR key, | 675 ULONG_PTR key, |
694 bool* has_valid_io_context) { | 676 bool* has_valid_io_context) { |
695 *has_valid_io_context = ((key & 1) == 0); | 677 *has_valid_io_context = ((key & 1) == 0); |
696 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); | 678 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); |
697 } | 679 } |
698 | 680 |
699 } // namespace base | 681 } // namespace base |
OLD | NEW |