| 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 |