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 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
690 | 698 |
691 // static | 699 // static |
692 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( | 700 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( |
693 ULONG_PTR key, | 701 ULONG_PTR key, |
694 bool* has_valid_io_context) { | 702 bool* has_valid_io_context) { |
695 *has_valid_io_context = ((key & 1) == 0); | 703 *has_valid_io_context = ((key & 1) == 0); |
696 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); | 704 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); |
697 } | 705 } |
698 | 706 |
699 } // namespace base | 707 } // namespace base |
OLD | NEW |