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 <math.h> | 7 #include <math.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <limits> | 10 #include <limits> |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
73 // Range check the |timeout| while converting to an integer. If the |timeout| | 73 // Range check the |timeout| while converting to an integer. If the |timeout| |
74 // is negative, then we need to run delayed work soon. If the |timeout| is | 74 // is negative, then we need to run delayed work soon. If the |timeout| is |
75 // "overflowingly" large, that means a delayed task was posted with a | 75 // "overflowingly" large, that means a delayed task was posted with a |
76 // super-long delay. | 76 // super-long delay. |
77 return timeout < 0 ? 0 : | 77 return timeout < 0 ? 0 : |
78 (timeout > std::numeric_limits<int>::max() ? | 78 (timeout > std::numeric_limits<int>::max() ? |
79 std::numeric_limits<int>::max() : static_cast<int>(timeout)); | 79 std::numeric_limits<int>::max() : static_cast<int>(timeout)); |
80 } | 80 } |
81 | 81 |
82 //----------------------------------------------------------------------------- | 82 //----------------------------------------------------------------------------- |
83 // MessagePumpForUI public: | 83 // MessagePumpForUIBase public: |
84 | 84 |
85 MessagePumpForUI::MessagePumpForUI() | 85 MessagePumpForUIBase::MessagePumpForUIBase() |
86 : atom_(0) { | 86 : atom_(0) { |
87 InitMessageWnd(); | 87 InitMessageWnd(); |
jbauman
2016/03/18 01:00:50
We could essentially get rid of MessagePumpForUIBa
stanisc
2016/03/18 18:16:46
Thanks for the feedback! I've tried a separate cla
| |
88 } | 88 } |
89 | 89 |
90 MessagePumpForUI::~MessagePumpForUI() { | 90 MessagePumpForUIBase::~MessagePumpForUIBase() { |
91 DestroyWindow(message_hwnd_); | 91 DestroyWindow(message_hwnd_); |
92 UnregisterClass(MAKEINTATOM(atom_), | 92 UnregisterClass(MAKEINTATOM(atom_), |
93 GetModuleFromAddress(&WndProcThunk)); | 93 GetModuleFromAddress(&WndProcThunk)); |
94 } | 94 } |
95 | 95 |
96 void MessagePumpForUI::ScheduleWork() { | 96 void MessagePumpForUIBase::ScheduleWork() { |
97 if (InterlockedExchange(&have_work_, 1)) | 97 if (READY != InterlockedExchange(&work_state_, HAVE_WORK)) |
98 return; // Someone else continued the pumping. | 98 return; // Someone else continued the pumping. |
99 | 99 |
100 // Make sure the MessagePump does some work for us. | 100 // Make sure the MessagePump does some work for us. |
101 BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork, | 101 BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork, |
102 reinterpret_cast<WPARAM>(this), 0); | 102 reinterpret_cast<WPARAM>(this), 0); |
103 if (ret) | 103 if (ret) |
104 return; // There was room in the Window Message queue. | 104 return; // There was room in the Window Message queue. |
105 | 105 |
106 // We have failed to insert a have-work message, so there is a chance that we | 106 // We have failed to insert a have-work message, so there is a chance that we |
107 // will starve tasks/timers while sitting in a nested message loop. Nested | 107 // will starve tasks/timers while sitting in a nested message loop. Nested |
108 // loops only look at Windows Message queues, and don't look at *our* task | 108 // loops only look at Windows Message queues, and don't look at *our* task |
109 // queues, etc., so we might not get a time slice in such. :-( | 109 // queues, etc., so we might not get a time slice in such. :-( |
110 // We could abort here, but the fear is that this failure mode is plausibly | 110 // We could abort here, but the fear is that this failure mode is plausibly |
111 // common (queue is full, of about 2000 messages), so we'll do a near-graceful | 111 // common (queue is full, of about 2000 messages), so we'll do a near-graceful |
112 // recovery. Nested loops are pretty transient (we think), so this will | 112 // recovery. Nested loops are pretty transient (we think), so this will |
113 // probably be recoverable. | 113 // probably be recoverable. |
114 InterlockedExchange(&have_work_, 0); // Clarify that we didn't really insert. | 114 |
115 // Clarify that we didn't really insert. | |
116 InterlockedExchange(&work_state_, READY); | |
115 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR, | 117 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR, |
116 MESSAGE_LOOP_PROBLEM_MAX); | 118 MESSAGE_LOOP_PROBLEM_MAX); |
117 } | 119 } |
118 | 120 |
119 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { | 121 //----------------------------------------------------------------------------- |
120 delayed_work_time_ = delayed_work_time; | 122 // MessagePumpForUIBase protected: |
121 RescheduleTimer(); | 123 |
124 void MessagePumpForUIBase::SetTimer(int delay_msec) { | |
125 // We would *like* to provide high resolution timers. Windows timers using | |
126 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup | |
127 // mechanism because the application can enter modal windows loops where it | |
128 // is not running our MessageLoop; the only way to have our timers fire in | |
129 // these cases is to post messages there. | |
130 // | |
131 // To provide sub-10ms timers, we process timers directly from our run loop. | |
132 // For the common case, timers will be processed there as the run loop does | |
133 // its normal work. However, we *also* set the system timer so that WM_TIMER | |
134 // events fire. This mops up the case of timers not being able to work in | |
135 // modal message loops. It is possible for the SetTimer to pop and have no | |
136 // pending timers, because they could have already been processed by the | |
137 // run loop itself. | |
138 // | |
139 // We use a single SetTimer corresponding to the timer that will expire | |
140 // soonest. As new timers are created and destroyed, we update SetTimer. | |
141 // Getting a spurious SetTimer event firing is benign, as we'll just be | |
142 // processing an empty timer queue. | |
143 if (delay_msec < USER_TIMER_MINIMUM) | |
144 delay_msec = USER_TIMER_MINIMUM; | |
145 | |
146 // Create a WM_TIMER event that will wake us up to check for any pending | |
147 // timers (in case we are running within a nested, external sub-pump). | |
148 BOOL ret = ::SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), | |
149 delay_msec, NULL); | |
150 if (ret) | |
151 return; | |
152 // If we can't set timers, we are in big trouble... but cross our fingers | |
153 // for now. | |
154 // TODO(jar): If we don't see this error, use a CHECK() here instead. | |
155 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR, | |
156 MESSAGE_LOOP_PROBLEM_MAX); | |
157 } | |
158 | |
159 void MessagePumpForUIBase::KillTimer() { | |
160 ::KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); | |
161 } | |
162 | |
163 bool MessagePumpForUIBase::IsWorkMessage(const MSG& msg) const { | |
164 return msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_; | |
165 } | |
166 | |
167 //----------------------------------------------------------------------------- | |
168 // MessagePumpForUIBase private: | |
169 | |
170 // static | |
171 LRESULT CALLBACK MessagePumpForUIBase::WndProcThunk( | |
172 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { | |
173 switch (message) { | |
174 case kMsgHaveWork: | |
175 reinterpret_cast<MessagePumpForUIBase*>(wparam)->HandleWorkMessage(); | |
176 break; | |
177 case WM_TIMER: | |
178 reinterpret_cast<MessagePumpForUIBase*>(wparam)->HandleTimerMessage(); | |
179 break; | |
180 } | |
181 return DefWindowProc(hwnd, message, wparam, lparam); | |
182 } | |
183 | |
184 void MessagePumpForUIBase::InitMessageWnd() { | |
185 // Generate a unique window class name. | |
186 string16 class_name = StringPrintf(kWndClassFormat, this); | |
187 | |
188 HINSTANCE instance = GetModuleFromAddress(&WndProcThunk); | |
189 WNDCLASSEX wc = {0}; | |
190 wc.cbSize = sizeof(wc); | |
191 wc.lpfnWndProc = base::win::WrappedWindowProc<WndProcThunk>; | |
192 wc.hInstance = instance; | |
193 wc.lpszClassName = class_name.c_str(); | |
194 atom_ = RegisterClassEx(&wc); | |
195 DCHECK(atom_); | |
196 | |
197 message_hwnd_ = CreateWindow(MAKEINTATOM(atom_), 0, 0, 0, 0, 0, 0, | |
198 HWND_MESSAGE, 0, instance, 0); | |
199 DCHECK(message_hwnd_); | |
200 } | |
201 | |
202 //----------------------------------------------------------------------------- | |
203 // MessagePumpForUI public: | |
204 | |
205 MessagePumpForUI::MessagePumpForUI() { | |
206 } | |
207 | |
208 MessagePumpForUI::~MessagePumpForUI() { | |
122 } | 209 } |
123 | 210 |
124 //----------------------------------------------------------------------------- | 211 //----------------------------------------------------------------------------- |
125 // MessagePumpForUI private: | 212 // MessagePumpForUI private: |
126 | 213 |
127 // static | 214 void MessagePumpForUI::ScheduleDelayedWork( |
128 LRESULT CALLBACK MessagePumpForUI::WndProcThunk( | 215 const TimeTicks& delayed_work_time) { |
129 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { | 216 delayed_work_time_ = delayed_work_time; |
130 switch (message) { | 217 RescheduleTimer(); |
131 case kMsgHaveWork: | |
132 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage(); | |
133 break; | |
134 case WM_TIMER: | |
135 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage(); | |
136 break; | |
137 } | |
138 return DefWindowProc(hwnd, message, wparam, lparam); | |
139 } | 218 } |
140 | 219 |
141 void MessagePumpForUI::DoRunLoop() { | 220 void MessagePumpForUI::DoRunLoop() { |
142 // IF this was just a simple PeekMessage() loop (servicing all possible work | 221 // IF this was just a simple PeekMessage() loop (servicing all possible work |
143 // queues), then Windows would try to achieve the following order according | 222 // queues), then Windows would try to achieve the following order according |
144 // to MSDN documentation about PeekMessage with no filter): | 223 // to MSDN documentation about PeekMessage with no filter): |
145 // * Sent messages | 224 // * Sent messages |
146 // * Posted messages | 225 // * Posted messages |
147 // * Sent messages (again) | 226 // * Sent messages (again) |
148 // * WM_PAINT messages | 227 // * WM_PAINT messages |
(...skipping 20 matching lines...) Expand all Loading... | |
169 if (state_->should_quit) | 248 if (state_->should_quit) |
170 break; | 249 break; |
171 | 250 |
172 more_work_is_plausible |= | 251 more_work_is_plausible |= |
173 state_->delegate->DoDelayedWork(&delayed_work_time_); | 252 state_->delegate->DoDelayedWork(&delayed_work_time_); |
174 // If we did not process any delayed work, then we can assume that our | 253 // If we did not process any delayed work, then we can assume that our |
175 // existing WM_TIMER if any will fire when delayed work should run. We | 254 // existing WM_TIMER if any will fire when delayed work should run. We |
176 // don't want to disturb that timer if it is already in flight. However, | 255 // don't want to disturb that timer if it is already in flight. However, |
177 // if we did do all remaining delayed work, then lets kill the WM_TIMER. | 256 // if we did do all remaining delayed work, then lets kill the WM_TIMER. |
178 if (more_work_is_plausible && delayed_work_time_.is_null()) | 257 if (more_work_is_plausible && delayed_work_time_.is_null()) |
179 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); | 258 KillTimer(); |
180 if (state_->should_quit) | 259 if (state_->should_quit) |
181 break; | 260 break; |
182 | 261 |
183 if (more_work_is_plausible) | 262 if (more_work_is_plausible) |
184 continue; | 263 continue; |
185 | 264 |
186 more_work_is_plausible = state_->delegate->DoIdleWork(); | 265 more_work_is_plausible = state_->delegate->DoIdleWork(); |
187 if (state_->should_quit) | 266 if (state_->should_quit) |
188 break; | 267 break; |
189 | 268 |
190 if (more_work_is_plausible) | 269 if (more_work_is_plausible) |
191 continue; | 270 continue; |
192 | 271 |
193 WaitForWork(); // Wait (sleep) until we have work to do again. | 272 WaitForWork(); // Wait (sleep) until we have work to do again. |
194 } | 273 } |
195 } | 274 } |
196 | 275 |
197 void MessagePumpForUI::InitMessageWnd() { | |
198 // Generate a unique window class name. | |
199 string16 class_name = StringPrintf(kWndClassFormat, this); | |
200 | |
201 HINSTANCE instance = GetModuleFromAddress(&WndProcThunk); | |
202 WNDCLASSEX wc = {0}; | |
203 wc.cbSize = sizeof(wc); | |
204 wc.lpfnWndProc = base::win::WrappedWindowProc<WndProcThunk>; | |
205 wc.hInstance = instance; | |
206 wc.lpszClassName = class_name.c_str(); | |
207 atom_ = RegisterClassEx(&wc); | |
208 DCHECK(atom_); | |
209 | |
210 message_hwnd_ = CreateWindow(MAKEINTATOM(atom_), 0, 0, 0, 0, 0, 0, | |
211 HWND_MESSAGE, 0, instance, 0); | |
212 DCHECK(message_hwnd_); | |
213 } | |
214 | |
215 void MessagePumpForUI::WaitForWork() { | 276 void MessagePumpForUI::WaitForWork() { |
216 // Wait until a message is available, up to the time needed by the timer | 277 // Wait until a message is available, up to the time needed by the timer |
217 // manager to fire the next set of timers. | 278 // manager to fire the next set of timers. |
218 int delay = GetCurrentDelay(); | 279 int delay = GetCurrentDelay(); |
219 if (delay < 0) // Negative value means no timers waiting. | 280 if (delay < 0) // Negative value means no timers waiting. |
220 delay = INFINITE; | 281 delay = INFINITE; |
221 | 282 |
222 DWORD result; | 283 DWORD result; |
223 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, | 284 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, |
224 MWMO_INPUTAVAILABLE); | 285 MWMO_INPUTAVAILABLE); |
(...skipping 21 matching lines...) Expand all Loading... | |
246 | 307 |
247 DCHECK_NE(WAIT_FAILED, result) << GetLastError(); | 308 DCHECK_NE(WAIT_FAILED, result) << GetLastError(); |
248 } | 309 } |
249 | 310 |
250 void MessagePumpForUI::HandleWorkMessage() { | 311 void MessagePumpForUI::HandleWorkMessage() { |
251 // If we are being called outside of the context of Run, then don't try to do | 312 // If we are being called outside of the context of Run, then don't try to do |
252 // any work. This could correspond to a MessageBox call or something of that | 313 // any work. This could correspond to a MessageBox call or something of that |
253 // sort. | 314 // sort. |
254 if (!state_) { | 315 if (!state_) { |
255 // Since we handled a kMsgHaveWork message, we must still update this flag. | 316 // Since we handled a kMsgHaveWork message, we must still update this flag. |
256 InterlockedExchange(&have_work_, 0); | 317 InterlockedExchange(&work_state_, READY); |
257 return; | 318 return; |
258 } | 319 } |
259 | 320 |
260 // Let whatever would have run had we not been putting messages in the queue | 321 // Let whatever would have run had we not been putting messages in the queue |
261 // run now. This is an attempt to make our dummy message not starve other | 322 // run now. This is an attempt to make our dummy message not starve other |
262 // messages that may be in the Windows message queue. | 323 // messages that may be in the Windows message queue. |
263 ProcessPumpReplacementMessage(); | 324 ProcessPumpReplacementMessage(); |
264 | 325 |
265 // Now give the delegate a chance to do some work. He'll let us know if he | 326 // Now give the delegate a chance to do some work. He'll let us know if he |
266 // needs to do more work. | 327 // needs to do more work. |
267 if (state_->delegate->DoWork()) | 328 if (state_->delegate->DoWork()) |
268 ScheduleWork(); | 329 ScheduleWork(); |
269 state_->delegate->DoDelayedWork(&delayed_work_time_); | 330 state_->delegate->DoDelayedWork(&delayed_work_time_); |
270 RescheduleTimer(); | 331 RescheduleTimer(); |
271 } | 332 } |
272 | 333 |
273 void MessagePumpForUI::HandleTimerMessage() { | 334 void MessagePumpForUI::HandleTimerMessage() { |
274 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); | 335 KillTimer(); |
275 | 336 |
276 // If we are being called outside of the context of Run, then don't do | 337 // If we are being called outside of the context of Run, then don't do |
277 // anything. This could correspond to a MessageBox call or something of | 338 // anything. This could correspond to a MessageBox call or something of |
278 // that sort. | 339 // that sort. |
279 if (!state_) | 340 if (!state_) |
280 return; | 341 return; |
281 | 342 |
282 state_->delegate->DoDelayedWork(&delayed_work_time_); | 343 state_->delegate->DoDelayedWork(&delayed_work_time_); |
283 RescheduleTimer(); | 344 RescheduleTimer(); |
284 } | 345 } |
285 | 346 |
286 void MessagePumpForUI::RescheduleTimer() { | 347 void MessagePumpForUI::RescheduleTimer() { |
287 if (delayed_work_time_.is_null()) | 348 if (delayed_work_time_.is_null()) |
288 return; | 349 return; |
289 // | 350 |
290 // We would *like* to provide high resolution timers. Windows timers using | |
291 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup | |
292 // mechanism because the application can enter modal windows loops where it | |
293 // is not running our MessageLoop; the only way to have our timers fire in | |
294 // these cases is to post messages there. | |
295 // | |
296 // To provide sub-10ms timers, we process timers directly from our run loop. | |
297 // For the common case, timers will be processed there as the run loop does | |
298 // its normal work. However, we *also* set the system timer so that WM_TIMER | |
299 // events fire. This mops up the case of timers not being able to work in | |
300 // modal message loops. It is possible for the SetTimer to pop and have no | |
301 // pending timers, because they could have already been processed by the | |
302 // run loop itself. | |
303 // | |
304 // We use a single SetTimer corresponding to the timer that will expire | |
305 // soonest. As new timers are created and destroyed, we update SetTimer. | |
306 // Getting a spurious SetTimer event firing is benign, as we'll just be | |
307 // processing an empty timer queue. | |
308 // | |
309 int delay_msec = GetCurrentDelay(); | 351 int delay_msec = GetCurrentDelay(); |
310 DCHECK_GE(delay_msec, 0); | 352 DCHECK_GE(delay_msec, 0); |
311 if (delay_msec == 0) { | 353 if (delay_msec == 0) { |
312 ScheduleWork(); | 354 ScheduleWork(); |
313 } else { | 355 } else { |
314 if (delay_msec < USER_TIMER_MINIMUM) | 356 SetTimer(delay_msec); |
315 delay_msec = USER_TIMER_MINIMUM; | |
316 | |
317 // Create a WM_TIMER event that will wake us up to check for any pending | |
318 // timers (in case we are running within a nested, external sub-pump). | |
319 BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), | |
320 delay_msec, NULL); | |
321 if (ret) | |
322 return; | |
323 // If we can't set timers, we are in big trouble... but cross our fingers | |
324 // for now. | |
325 // TODO(jar): If we don't see this error, use a CHECK() here instead. | |
326 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR, | |
327 MESSAGE_LOOP_PROBLEM_MAX); | |
328 } | 357 } |
329 } | 358 } |
330 | 359 |
331 bool MessagePumpForUI::ProcessNextWindowsMessage() { | 360 bool MessagePumpForUI::ProcessNextWindowsMessage() { |
332 // If there are sent messages in the queue then PeekMessage internally | 361 // If there are sent messages in the queue then PeekMessage internally |
333 // dispatches the message and returns false. We return true in this | 362 // dispatches the message and returns false. We return true in this |
334 // case to ensure that the message loop peeks again instead of calling | 363 // case to ensure that the message loop peeks again instead of calling |
335 // MsgWaitForMultipleObjectsEx again. | 364 // MsgWaitForMultipleObjectsEx again. |
336 bool sent_messages_in_queue = false; | 365 bool sent_messages_in_queue = false; |
337 DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE); | 366 DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE); |
338 if (HIWORD(queue_status) & QS_SENDMESSAGE) | 367 if (HIWORD(queue_status) & QS_SENDMESSAGE) |
339 sent_messages_in_queue = true; | 368 sent_messages_in_queue = true; |
340 | 369 |
341 MSG msg; | 370 MSG msg; |
342 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE) | 371 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE) |
343 return ProcessMessageHelper(msg); | 372 return ProcessMessageHelper(msg); |
344 | 373 |
345 return sent_messages_in_queue; | 374 return sent_messages_in_queue; |
346 } | 375 } |
347 | 376 |
348 bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) { | 377 bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) { |
349 TRACE_EVENT1("base", "MessagePumpForUI::ProcessMessageHelper", | 378 TRACE_EVENT1("base", "MessagePumpForUIBase::ProcessMessageHelper", |
350 "message", msg.message); | 379 "message", msg.message); |
351 if (WM_QUIT == msg.message) { | 380 if (WM_QUIT == msg.message) { |
352 // Repost the QUIT message so that it will be retrieved by the primary | 381 // Repost the QUIT message so that it will be retrieved by the primary |
353 // GetMessage() loop. | 382 // GetMessage() loop. |
354 state_->should_quit = true; | 383 state_->should_quit = true; |
355 PostQuitMessage(static_cast<int>(msg.wParam)); | 384 PostQuitMessage(static_cast<int>(msg.wParam)); |
356 return false; | 385 return false; |
357 } | 386 } |
358 | 387 |
359 // While running our main message pump, we discard kMsgHaveWork messages. | 388 // While running our main message pump, we discard kMsgHaveWork messages. |
360 if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_) | 389 if (IsWorkMessage(msg)) |
361 return ProcessPumpReplacementMessage(); | 390 return ProcessPumpReplacementMessage(); |
362 | 391 |
363 if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode)) | 392 if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode)) |
364 return true; | 393 return true; |
365 | 394 |
366 TranslateMessage(&msg); | 395 TranslateMessage(&msg); |
367 DispatchMessage(&msg); | 396 DispatchMessage(&msg); |
368 | 397 |
369 return true; | 398 return true; |
370 } | 399 } |
(...skipping 14 matching lines...) Expand all Loading... | |
385 // OS modal loop, i.e. in the context of a windows API call like MessageBox. | 414 // OS modal loop, i.e. in the context of a windows API call like MessageBox. |
386 // This is to ensure that these messages are peeked out by the OS modal loop. | 415 // This is to ensure that these messages are peeked out by the OS modal loop. |
387 if (MessageLoop::current()->os_modal_loop()) { | 416 if (MessageLoop::current()->os_modal_loop()) { |
388 // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above. | 417 // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above. |
389 have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) || | 418 have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) || |
390 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); | 419 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); |
391 } else { | 420 } else { |
392 have_message = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE; | 421 have_message = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE; |
393 } | 422 } |
394 | 423 |
395 DCHECK(!have_message || kMsgHaveWork != msg.message || | 424 DCHECK(!have_message || !IsWorkMessage(msg)); |
396 msg.hwnd != message_hwnd_); | |
397 | 425 |
398 // Since we discarded a kMsgHaveWork message, we must update the flag. | 426 // Since we discarded a kMsgHaveWork message, we must update the flag. |
399 int old_have_work = InterlockedExchange(&have_work_, 0); | 427 int old_work_state_ = InterlockedExchange(&work_state_, READY); |
400 DCHECK(old_have_work); | 428 DCHECK_EQ(HAVE_WORK, old_work_state_); |
401 | 429 |
402 // We don't need a special time slice if we didn't have_message to process. | 430 // We don't need a special time slice if we didn't have_message to process. |
403 if (!have_message) | 431 if (!have_message) |
404 return false; | 432 return false; |
405 | 433 |
406 // Guarantee we'll get another time slice in the case where we go into native | 434 // Guarantee we'll get another time slice in the case where we go into native |
407 // windows code. This ScheduleWork() may hurt performance a tiny bit when | 435 // windows code. This ScheduleWork() may hurt performance a tiny bit when |
408 // tasks appear very infrequently, but when the event queue is busy, the | 436 // tasks appear very infrequently, but when the event queue is busy, the |
409 // kMsgHaveWork events get (percentage wise) rarer and rarer. | 437 // kMsgHaveWork events get (percentage wise) rarer and rarer. |
410 ScheduleWork(); | 438 ScheduleWork(); |
411 return ProcessMessageHelper(msg); | 439 return ProcessMessageHelper(msg); |
412 } | 440 } |
413 | 441 |
414 //----------------------------------------------------------------------------- | 442 //----------------------------------------------------------------------------- |
443 // MessagePumpForGpu public: | |
444 | |
445 MessagePumpForGpu::MessagePumpForGpu() { | |
446 } | |
447 | |
448 MessagePumpForGpu::~MessagePumpForGpu() { | |
449 } | |
450 | |
451 //----------------------------------------------------------------------------- | |
452 // MessagePumpForGpu private: | |
453 | |
454 void MessagePumpForGpu::ScheduleDelayedWork( | |
455 const TimeTicks& delayed_work_time) { | |
456 // We know that we can't be blocked right now since this method can only be | |
457 // called on the same thread as Run, so we only need to update our record of | |
458 // how long to sleep when we do sleep. | |
459 delayed_work_time_ = delayed_work_time; | |
460 } | |
461 | |
462 void MessagePumpForGpu::DoRunLoop() { | |
463 while (!state_->should_quit) { | |
464 // Indicate that the loop is handling the work. | |
465 // If there is a race condition between switching to WORKING state here and | |
466 // the producer thread setting the HAVE_WORK state after exiting the wait, | |
467 // the event might remain in the signalled state. That might be less than | |
468 // optimal but wouldn't result in failing to handle the work. | |
469 InterlockedExchange(&work_state_, WORKING); | |
470 | |
471 bool more_work_is_plausible = state_->delegate->DoWork(); | |
472 if (state_->should_quit) | |
473 break; | |
474 | |
475 more_work_is_plausible |= | |
476 state_->delegate->DoDelayedWork(&delayed_work_time_); | |
477 if (state_->should_quit) | |
478 break; | |
479 | |
480 if (more_work_is_plausible) | |
481 continue; | |
482 | |
483 more_work_is_plausible = state_->delegate->DoIdleWork(); | |
484 if (state_->should_quit) | |
485 break; | |
486 | |
487 if (more_work_is_plausible) | |
488 continue; | |
489 | |
490 // Switch that working state to READY to indicate that the loop is | |
491 // waiting for accepting new work if it is still in WORKING state and hasn't | |
492 // been signalled. Otherwise if it is in HAVE_WORK state skip the wait | |
493 // and proceed to handing the work. | |
494 if (HAVE_WORK == InterlockedCompareExchange(&work_state_, READY, WORKING)) | |
495 continue; // Skip wait, more work was requested. | |
496 | |
497 WaitForWork(); // Wait (sleep) until we have work to do again. | |
498 } | |
499 } | |
500 | |
501 void MessagePumpForGpu::WaitForWork() { | |
502 // Wait until a message is available, up to the time needed by the timer | |
503 // manager to fire the next set of timers. | |
504 int delay; | |
505 | |
506 // The while loop handles the situation where on Windows 7 and later versions | |
507 // MsgWaitForMultipleObjectsEx might time out slightly earlier (less than one | |
508 // ms) than the specified |delay|. In that situation it is more optimal to | |
509 // just wait again rather than waste a DoRunLoop cycle. | |
510 while((delay = GetCurrentDelay()) != 0) { | |
511 if (delay < 0) // Negative value means no timers waiting. | |
512 delay = INFINITE; | |
513 | |
514 DWORD result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, | |
515 MWMO_INPUTAVAILABLE); | |
516 if (WAIT_OBJECT_0 == result) { | |
517 // A WM_* message is available. | |
518 ProcessWindowsMessages(); | |
519 return; | |
520 } | |
521 | |
522 DCHECK_NE(WAIT_FAILED, result) << GetLastError(); | |
523 } | |
524 } | |
525 | |
526 void MessagePumpForGpu::ProcessWindowsMessages() { | |
527 MSG msg; | |
528 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE) { | |
529 if (WM_QUIT == msg.message) { | |
530 // Repost the QUIT message so that it will be retrieved by the primary | |
531 // GetMessage() loop. | |
532 state_->should_quit = true; | |
533 PostQuitMessage(static_cast<int>(msg.wParam)); | |
534 return; | |
535 } | |
536 | |
537 if (!IsWorkMessage(msg)) { | |
538 TranslateMessage(&msg); | |
539 DispatchMessage(&msg); | |
540 } | |
541 } | |
542 } | |
543 | |
544 void MessagePumpForGpu::HandleWorkMessage() { | |
545 NOTREACHED(); | |
546 } | |
547 | |
548 void MessagePumpForGpu::HandleTimerMessage() { | |
549 NOTREACHED(); | |
550 } | |
551 | |
552 void MessagePumpForGpu::InitFactory() { | |
553 MessageLoop::InitMessagePumpForUIFactory( | |
554 &MessagePumpForGpu::CreateMessagePumpForGpu); | |
555 } | |
556 | |
557 scoped_ptr<MessagePump> MessagePumpForGpu::CreateMessagePumpForGpu() { | |
558 return scoped_ptr<MessagePump>(new MessagePumpForGpu); | |
559 } | |
560 | |
561 //----------------------------------------------------------------------------- | |
415 // MessagePumpForIO public: | 562 // MessagePumpForIO public: |
416 | 563 |
417 MessagePumpForIO::MessagePumpForIO() { | 564 MessagePumpForIO::MessagePumpForIO() { |
418 port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1)); | 565 port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1)); |
419 DCHECK(port_.IsValid()); | 566 DCHECK(port_.IsValid()); |
420 } | 567 } |
421 | 568 |
422 MessagePumpForIO::~MessagePumpForIO() { | 569 MessagePumpForIO::~MessagePumpForIO() { |
423 } | 570 } |
424 | 571 |
425 void MessagePumpForIO::ScheduleWork() { | 572 void MessagePumpForIO::ScheduleWork() { |
426 if (InterlockedExchange(&have_work_, 1)) | 573 if (READY != InterlockedExchange(&work_state_, HAVE_WORK)) |
427 return; // Someone else continued the pumping. | 574 return; // Someone else continued the pumping. |
428 | 575 |
429 // Make sure the MessagePump does some work for us. | 576 // Make sure the MessagePump does some work for us. |
430 BOOL ret = PostQueuedCompletionStatus(port_.Get(), 0, | 577 BOOL ret = PostQueuedCompletionStatus(port_.Get(), 0, |
431 reinterpret_cast<ULONG_PTR>(this), | 578 reinterpret_cast<ULONG_PTR>(this), |
432 reinterpret_cast<OVERLAPPED*>(this)); | 579 reinterpret_cast<OVERLAPPED*>(this)); |
433 if (ret) | 580 if (ret) |
434 return; // Post worked perfectly. | 581 return; // Post worked perfectly. |
435 | 582 |
436 // See comment in MessagePumpForUI::ScheduleWork() for this error recovery. | 583 // See comment in MessagePumpForUI::ScheduleWork() for this error recovery. |
437 InterlockedExchange(&have_work_, 0); // Clarify that we didn't succeed. | 584 InterlockedExchange(&work_state_, READY); // Clarify that we didn't succeed. |
438 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR, | 585 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR, |
439 MESSAGE_LOOP_PROBLEM_MAX); | 586 MESSAGE_LOOP_PROBLEM_MAX); |
440 } | 587 } |
441 | 588 |
442 void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { | 589 void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { |
443 // We know that we can't be blocked right now since this method can only be | 590 // We know that we can't be blocked right now since this method can only be |
444 // called on the same thread as Run, so we only need to update our record of | 591 // called on the same thread as Run, so we only need to update our record of |
445 // how long to sleep when we do sleep. | 592 // how long to sleep when we do sleep. |
446 delayed_work_time_ = delayed_work_time; | 593 delayed_work_time_ = delayed_work_time; |
447 } | 594 } |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
572 item->handler = KeyToHandler(key, &item->has_valid_io_context); | 719 item->handler = KeyToHandler(key, &item->has_valid_io_context); |
573 item->context = reinterpret_cast<IOContext*>(overlapped); | 720 item->context = reinterpret_cast<IOContext*>(overlapped); |
574 return true; | 721 return true; |
575 } | 722 } |
576 | 723 |
577 bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) { | 724 bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) { |
578 if (reinterpret_cast<void*>(this) == reinterpret_cast<void*>(item.context) && | 725 if (reinterpret_cast<void*>(this) == reinterpret_cast<void*>(item.context) && |
579 reinterpret_cast<void*>(this) == reinterpret_cast<void*>(item.handler)) { | 726 reinterpret_cast<void*>(this) == reinterpret_cast<void*>(item.handler)) { |
580 // This is our internal completion. | 727 // This is our internal completion. |
581 DCHECK(!item.bytes_transfered); | 728 DCHECK(!item.bytes_transfered); |
582 InterlockedExchange(&have_work_, 0); | 729 InterlockedExchange(&work_state_, READY); |
583 return true; | 730 return true; |
584 } | 731 } |
585 return false; | 732 return false; |
586 } | 733 } |
587 | 734 |
588 // Returns a completion item that was previously received. | 735 // Returns a completion item that was previously received. |
589 bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) { | 736 bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) { |
590 DCHECK(!completed_io_.empty()); | 737 DCHECK(!completed_io_.empty()); |
591 for (std::list<IOItem>::iterator it = completed_io_.begin(); | 738 for (std::list<IOItem>::iterator it = completed_io_.begin(); |
592 it != completed_io_.end(); ++it) { | 739 it != completed_io_.end(); ++it) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
633 | 780 |
634 // static | 781 // static |
635 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( | 782 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( |
636 ULONG_PTR key, | 783 ULONG_PTR key, |
637 bool* has_valid_io_context) { | 784 bool* has_valid_io_context) { |
638 *has_valid_io_context = ((key & 1) == 0); | 785 *has_valid_io_context = ((key & 1) == 0); |
639 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); | 786 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); |
640 } | 787 } |
641 | 788 |
642 } // namespace base | 789 } // namespace base |
OLD | NEW |