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" | 12 #include "base/process_util.h" |
13 #include "base/stringprintf.h" | 13 #include "base/stringprintf.h" |
14 #include "base/win/wrapped_window_proc.h" | 14 #include "base/win/wrapped_window_proc.h" |
15 | 15 |
16 namespace { | 16 namespace { |
17 | 17 |
18 enum MessageLoopProblems { | 18 enum MessageLoopProblems { |
19 MESSAGE_POST_ERROR, | 19 MESSAGE_POST_ERROR, |
20 COMPLETION_POST_ERROR, | 20 COMPLETION_POST_ERROR, |
21 SET_TIMER_ERROR, | 21 SET_TIMER_ERROR, |
22 MESSAGE_LOOP_PROBLEM_MAX, | 22 MESSAGE_LOOP_PROBLEM_MAX, |
23 }; | 23 }; |
24 | 24 |
25 // Possible states of the message pump: | |
26 // - kPumpIdle: the thread is sleeping, waiting for work to be posted. | |
27 // - kPumpHaveWork: a window message or completion packet has been posted. | |
28 // - kPumpDisabled: the pump is disabled, no more work can be posted. | |
29 static const LONG kPumpIdle = 0; | |
rvargas (doing something else)
2013/06/12 00:22:22
nit: don't need static
alexeypa (please no reviews)
2013/06/12 18:05:22
Done.
| |
30 static const LONG kPumpHaveWork = 1; | |
31 static const LONG kPumpDisabled = 2; | |
32 | |
33 // Used to wake up the message loop thread in the case if it is waiting for | |
rvargas (doing something else)
2013/06/12 00:22:22
nit: remove "in the case"
alexeypa (please no reviews)
2013/06/12 18:05:22
Done.
| |
34 // another thread to exit MessagePumpForUI::ScheduleWork(). | |
35 VOID CALLBACK DummyApc(ULONG_PTR) {} | |
36 | |
25 } // namespace | 37 } // namespace |
26 | 38 |
27 namespace base { | 39 namespace base { |
28 | 40 |
29 static const wchar_t kWndClassFormat[] = L"Chrome_MessagePumpWindow_%p"; | 41 static const wchar_t kWndClassFormat[] = L"Chrome_MessagePumpWindow_%p"; |
30 | 42 |
31 // Message sent to get an additional time slice for pumping (processing) another | 43 // Message sent to get an additional time slice for pumping (processing) another |
32 // task (a series of such messages creates a continuous task pump). | 44 // task (a series of such messages creates a continuous task pump). |
33 static const int kMsgHaveWork = WM_USER + 1; | 45 static const int kMsgHaveWork = WM_USER + 1; |
34 | 46 |
35 //----------------------------------------------------------------------------- | 47 //----------------------------------------------------------------------------- |
36 // MessagePumpWin public: | 48 // MessagePumpWin public: |
37 | 49 |
50 MessagePumpWin::MessagePumpWin() : pump_state_(kPumpIdle), state_(NULL) {} | |
51 | |
38 void MessagePumpWin::AddObserver(MessagePumpObserver* observer) { | 52 void MessagePumpWin::AddObserver(MessagePumpObserver* observer) { |
39 observers_.AddObserver(observer); | 53 observers_.AddObserver(observer); |
40 } | 54 } |
41 | 55 |
42 void MessagePumpWin::RemoveObserver(MessagePumpObserver* observer) { | 56 void MessagePumpWin::RemoveObserver(MessagePumpObserver* observer) { |
43 observers_.RemoveObserver(observer); | 57 observers_.RemoveObserver(observer); |
44 } | 58 } |
45 | 59 |
46 void MessagePumpWin::WillProcessMessage(const MSG& msg) { | 60 void MessagePumpWin::WillProcessMessage(const MSG& msg) { |
47 FOR_EACH_OBSERVER(MessagePumpObserver, observers_, WillProcessEvent(msg)); | 61 FOR_EACH_OBSERVER(MessagePumpObserver, observers_, WillProcessEvent(msg)); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
92 | 106 |
93 return delay; | 107 return delay; |
94 } | 108 } |
95 | 109 |
96 //----------------------------------------------------------------------------- | 110 //----------------------------------------------------------------------------- |
97 // MessagePumpForUI public: | 111 // MessagePumpForUI public: |
98 | 112 |
99 MessagePumpForUI::MessagePumpForUI() | 113 MessagePumpForUI::MessagePumpForUI() |
100 : atom_(0), | 114 : atom_(0), |
101 message_filter_(new MessageFilter) { | 115 message_filter_(new MessageFilter) { |
116 CHECK(DuplicateHandle(GetCurrentProcess(), | |
117 GetCurrentThread(), | |
118 GetCurrentProcess(), | |
119 thread_.Receive(), | |
120 THREAD_SET_CONTEXT, | |
121 FALSE, // no not inherit this handle | |
rvargas (doing something else)
2013/06/12 00:22:22
fix comment
alexeypa (please no reviews)
2013/06/12 18:05:22
Done.
| |
122 0)); | |
102 InitMessageWnd(); | 123 InitMessageWnd(); |
103 } | 124 } |
104 | 125 |
105 MessagePumpForUI::~MessagePumpForUI() { | 126 MessagePumpForUI::~MessagePumpForUI() { |
106 DestroyWindow(message_hwnd_); | 127 DCHECK(!atom_); |
107 UnregisterClass(MAKEINTATOM(atom_), | 128 DCHECK(!message_hwnd_); |
108 base::GetModuleFromAddress(&WndProcThunk)); | |
109 } | 129 } |
110 | 130 |
111 void MessagePumpForUI::ScheduleWork() { | 131 void MessagePumpForUI::ScheduleWork() { |
112 if (InterlockedExchange(&have_work_, 1)) | 132 if (InterlockedCompareExchange(&pump_state_, kPumpHaveWork, |
113 return; // Someone else continued the pumping. | 133 kPumpIdle) != kPumpIdle) { |
134 // Either someone else continued the pumping or the pump is disabled. | |
135 return; | |
136 } | |
114 | 137 |
115 // Make sure the MessagePump does some work for us. | 138 // Make sure the MessagePump does some work for us. |
116 BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork, | 139 if (PostMessage(message_hwnd_, kMsgHaveWork, reinterpret_cast<WPARAM>(this), |
117 reinterpret_cast<WPARAM>(this), 0); | 140 0)) { |
118 if (ret) | 141 return; |
119 return; // There was room in the Window Message queue. | 142 } |
120 | 143 |
121 // We have failed to insert a have-work message, so there is a chance that we | 144 // We have failed to insert a have-work message, so there is a chance that we |
122 // will starve tasks/timers while sitting in a nested message loop. Nested | 145 // will starve tasks/timers while sitting in a nested message loop. Nested |
123 // loops only look at Windows Message queues, and don't look at *our* task | 146 // loops only look at Windows Message queues, and don't look at *our* task |
124 // queues, etc., so we might not get a time slice in such. :-( | 147 // queues, etc., so we might not get a time slice in such. :-( |
125 // We could abort here, but the fear is that this failure mode is plausibly | 148 // We could abort here, but the fear is that this failure mode is plausibly |
126 // common (queue is full, of about 2000 messages), so we'll do a near-graceful | 149 // common (queue is full, of about 2000 messages), so we'll do a near-graceful |
127 // recovery. Nested loops are pretty transient (we think), so this will | 150 // recovery. Nested loops are pretty transient (we think), so this will |
128 // probably be recoverable. | 151 // probably be recoverable. |
129 InterlockedExchange(&have_work_, 0); // Clarify that we didn't really insert. | |
130 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR, | 152 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR, |
131 MESSAGE_LOOP_PROBLEM_MAX); | 153 MESSAGE_LOOP_PROBLEM_MAX); |
154 | |
155 | |
156 | |
157 // Clarify that we didn't really insert. | |
158 InterlockedExchange(&pump_state_, kPumpIdle); | |
159 | |
160 // Try to wake up the message loop thread by posting an APC. This might not | |
161 // work while a nested loop still running (see the comment above) but this | |
162 // will unblock WillDestroyCurrentMessageLoop() if it is waiting for | |
163 // ScheduleWork() to complete. | |
164 // | |
165 // According to the UMA metrics posting an I/O completion packet has very low | |
166 // error rate. Queuing an APC hits roughly the same path in the kernel so | |
167 // the error rate should be low as well. Given that we do it only when | |
168 // PostMessage() fails it should be safe to CHECK() here. | |
169 CHECK(QueueUserAPC(&DummyApc, thread_, 0)); | |
132 } | 170 } |
133 | 171 |
134 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { | 172 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { |
135 // | 173 // |
136 // We would *like* to provide high resolution timers. Windows timers using | 174 // We would *like* to provide high resolution timers. Windows timers using |
137 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup | 175 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup |
138 // mechanism because the application can enter modal windows loops where it | 176 // mechanism because the application can enter modal windows loops where it |
139 // is not running our MessageLoop; the only way to have our timers fire in | 177 // is not running our MessageLoop; the only way to have our timers fire in |
140 // these cases is to post messages there. | 178 // these cases is to post messages there. |
141 // | 179 // |
(...skipping 23 matching lines...) Expand all Loading... | |
165 delay_msec, NULL); | 203 delay_msec, NULL); |
166 if (ret) | 204 if (ret) |
167 return; | 205 return; |
168 // If we can't set timers, we are in big trouble... but cross our fingers for | 206 // If we can't set timers, we are in big trouble... but cross our fingers for |
169 // now. | 207 // now. |
170 // TODO(jar): If we don't see this error, use a CHECK() here instead. | 208 // TODO(jar): If we don't see this error, use a CHECK() here instead. |
171 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR, | 209 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR, |
172 MESSAGE_LOOP_PROBLEM_MAX); | 210 MESSAGE_LOOP_PROBLEM_MAX); |
173 } | 211 } |
174 | 212 |
213 void MessagePumpForUI::WillDestroyCurrentMessageLoop() { | |
214 // Disable the message pump. If |pump_state_ == kPumpHaveWork| then | |
215 // ScheduleWork() might be still running on a different thread. Wait until | |
216 // |kMsgHaveWork| is received or |pump_state_| is reset back to |kPumpIdle|. | |
217 while (InterlockedCompareExchange(&pump_state_, kPumpDisabled, | |
218 kPumpIdle) == kPumpHaveWork) { | |
219 MSG msg; | |
220 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { | |
221 if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_) { | |
222 // Now that we received |kMsgHaveWork| the pump can be safely disabled. | |
223 InterlockedExchange(&pump_state_, kPumpDisabled); | |
224 break; | |
225 } | |
226 } | |
227 | |
228 // Wait until |kMsgHaveWork| is posted or an APC is received. | |
229 WaitForWork(); | |
230 } | |
231 | |
232 // At this point the pump is disabled and other threads exited ScheduleWork(). | |
233 DestroyWindow(message_hwnd_); | |
234 UnregisterClass(MAKEINTATOM(atom_), | |
235 base::GetModuleFromAddress(&WndProcThunk)); | |
236 | |
237 // Let the destructor know that the resources have been freed. | |
238 message_hwnd_ = NULL; | |
239 atom_ = 0; | |
240 } | |
241 | |
175 void MessagePumpForUI::PumpOutPendingPaintMessages() { | 242 void MessagePumpForUI::PumpOutPendingPaintMessages() { |
176 // If we are being called outside of the context of Run, then don't try to do | 243 // If we are being called outside of the context of Run, then don't try to do |
177 // any work. | 244 // any work. |
178 if (!state_) | 245 if (!state_) |
179 return; | 246 return; |
180 | 247 |
181 // Create a mini-message-pump to force immediate processing of only Windows | 248 // Create a mini-message-pump to force immediate processing of only Windows |
182 // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking | 249 // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking |
183 // to get the job done. Actual common max is 4 peeks, but we'll be a little | 250 // to get the job done. Actual common max is 4 peeks, but we'll be a little |
184 // safe here. | 251 // safe here. |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
290 | 357 |
291 void MessagePumpForUI::WaitForWork() { | 358 void MessagePumpForUI::WaitForWork() { |
292 // Wait until a message is available, up to the time needed by the timer | 359 // Wait until a message is available, up to the time needed by the timer |
293 // manager to fire the next set of timers. | 360 // manager to fire the next set of timers. |
294 int delay = GetCurrentDelay(); | 361 int delay = GetCurrentDelay(); |
295 if (delay < 0) // Negative value means no timers waiting. | 362 if (delay < 0) // Negative value means no timers waiting. |
296 delay = INFINITE; | 363 delay = INFINITE; |
297 | 364 |
298 DWORD result; | 365 DWORD result; |
299 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, | 366 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, |
300 MWMO_INPUTAVAILABLE); | 367 MWMO_ALERTABLE | MWMO_INPUTAVAILABLE); |
301 | 368 |
302 if (WAIT_OBJECT_0 == result) { | 369 if (WAIT_OBJECT_0 == result) { |
303 // A WM_* message is available. | 370 // A WM_* message is available. |
304 // If a parent child relationship exists between windows across threads | 371 // If a parent child relationship exists between windows across threads |
305 // then their thread inputs are implicitly attached. | 372 // then their thread inputs are implicitly attached. |
306 // This causes the MsgWaitForMultipleObjectsEx API to return indicating | 373 // This causes the MsgWaitForMultipleObjectsEx API to return indicating |
307 // that messages are ready for processing (Specifically, mouse messages | 374 // that messages are ready for processing (Specifically, mouse messages |
308 // intended for the child window may appear if the child window has | 375 // intended for the child window may appear if the child window has |
309 // capture). | 376 // capture). |
310 // The subsequent PeekMessages call may fail to return any messages thus | 377 // The subsequent PeekMessages call may fail to return any messages thus |
311 // causing us to enter a tight loop at times. | 378 // causing us to enter a tight loop at times. |
312 // The WaitMessage call below is a workaround to give the child window | 379 // The WaitMessage call below is a workaround to give the child window |
313 // some time to process its input messages. | 380 // some time to process its input messages. |
314 MSG msg = {0}; | 381 MSG msg = {0}; |
315 DWORD queue_status = GetQueueStatus(QS_MOUSE); | 382 DWORD queue_status = GetQueueStatus(QS_MOUSE); |
316 if (HIWORD(queue_status) & QS_MOUSE && | 383 if (HIWORD(queue_status) & QS_MOUSE && |
317 !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) { | 384 !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) { |
318 WaitMessage(); | 385 WaitMessage(); |
319 } | 386 } |
320 return; | 387 return; |
388 } else if (WAIT_IO_COMPLETION == result) { | |
389 // The wait was ended by one or more APCs. It could be cause | |
390 // MessagePumpUI::ScheduleWork() is trying to wake up the message loop | |
391 // thread. | |
392 return; | |
321 } | 393 } |
322 | 394 |
323 DCHECK_NE(WAIT_FAILED, result) << GetLastError(); | 395 DCHECK_NE(WAIT_FAILED, result) << GetLastError(); |
324 } | 396 } |
325 | 397 |
326 void MessagePumpForUI::HandleWorkMessage() { | 398 void MessagePumpForUI::HandleWorkMessage() { |
327 // If we are being called outside of the context of Run, then don't try to do | 399 // If we are being called outside of the context of Run, then don't try to do |
328 // any work. This could correspond to a MessageBox call or something of that | 400 // any work. This could correspond to a MessageBox call or something of that |
329 // sort. | 401 // sort. |
330 if (!state_) { | 402 if (!state_) { |
331 // Since we handled a kMsgHaveWork message, we must still update this flag. | 403 // Since we handled a kMsgHaveWork message, we must still update this flag. |
332 InterlockedExchange(&have_work_, 0); | 404 InterlockedExchange(&pump_state_, kPumpIdle); |
333 return; | 405 return; |
334 } | 406 } |
335 | 407 |
336 // Let whatever would have run had we not been putting messages in the queue | 408 // Let whatever would have run had we not been putting messages in the queue |
337 // run now. This is an attempt to make our dummy message not starve other | 409 // run now. This is an attempt to make our dummy message not starve other |
338 // messages that may be in the Windows message queue. | 410 // messages that may be in the Windows message queue. |
339 ProcessPumpReplacementMessage(); | 411 ProcessPumpReplacementMessage(); |
340 | 412 |
341 // Now give the delegate a chance to do some work. He'll let us know if he | 413 // Now give the delegate a chance to do some work. He'll let us know if he |
342 // needs to do more work. | 414 // needs to do more work. |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
410 DidProcessMessage(msg); | 482 DidProcessMessage(msg); |
411 return true; | 483 return true; |
412 } | 484 } |
413 | 485 |
414 bool MessagePumpForUI::ProcessPumpReplacementMessage() { | 486 bool MessagePumpForUI::ProcessPumpReplacementMessage() { |
415 // When we encounter a kMsgHaveWork message, this method is called to peek | 487 // When we encounter a kMsgHaveWork message, this method is called to peek |
416 // and process a replacement message, such as a WM_PAINT or WM_TIMER. The | 488 // and process a replacement message, such as a WM_PAINT or WM_TIMER. The |
417 // goal is to make the kMsgHaveWork as non-intrusive as possible, even though | 489 // goal is to make the kMsgHaveWork as non-intrusive as possible, even though |
418 // a continuous stream of such messages are posted. This method carefully | 490 // a continuous stream of such messages are posted. This method carefully |
419 // peeks a message while there is no chance for a kMsgHaveWork to be pending, | 491 // peeks a message while there is no chance for a kMsgHaveWork to be pending, |
420 // then resets the have_work_ flag (allowing a replacement kMsgHaveWork to | 492 // then resets the pump_state_ flag (allowing a replacement kMsgHaveWork to |
rvargas (doing something else)
2013/06/12 00:22:22
nit: not a flag to be reset anymore.
alexeypa (please no reviews)
2013/06/12 18:05:22
Done.
| |
421 // possibly be posted), and finally dispatches that peeked replacement. Note | 493 // possibly be posted), and finally dispatches that peeked replacement. Note |
422 // that the re-post of kMsgHaveWork may be asynchronous to this thread!! | 494 // that the re-post of kMsgHaveWork may be asynchronous to this thread!! |
423 | 495 |
424 bool have_message = false; | 496 bool have_message = false; |
425 MSG msg; | 497 MSG msg; |
426 // We should not process all window messages if we are in the context of an | 498 // We should not process all window messages if we are in the context of an |
427 // OS modal loop, i.e. in the context of a windows API call like MessageBox. | 499 // OS modal loop, i.e. in the context of a windows API call like MessageBox. |
428 // This is to ensure that these messages are peeked out by the OS modal loop. | 500 // This is to ensure that these messages are peeked out by the OS modal loop. |
429 if (MessageLoop::current()->os_modal_loop()) { | 501 if (MessageLoop::current()->os_modal_loop()) { |
430 // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above. | 502 // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above. |
431 have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) || | 503 have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) || |
432 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); | 504 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); |
433 } else { | 505 } else { |
434 have_message = !!message_filter_->DoPeekMessage(&msg, NULL, 0, 0, | 506 have_message = !!message_filter_->DoPeekMessage(&msg, NULL, 0, 0, |
435 PM_REMOVE); | 507 PM_REMOVE); |
436 } | 508 } |
437 | 509 |
438 DCHECK(!have_message || kMsgHaveWork != msg.message || | 510 DCHECK(!have_message || kMsgHaveWork != msg.message || |
439 msg.hwnd != message_hwnd_); | 511 msg.hwnd != message_hwnd_); |
440 | 512 |
441 // Since we discarded a kMsgHaveWork message, we must update the flag. | 513 // Since we discarded a kMsgHaveWork message, we must update the flag. |
442 int old_have_work = InterlockedExchange(&have_work_, 0); | 514 int old_have_work = InterlockedExchange(&pump_state_, kPumpIdle); |
443 DCHECK(old_have_work); | 515 DCHECK(old_have_work); |
444 | 516 |
445 // We don't need a special time slice if we didn't have_message to process. | 517 // We don't need a special time slice if we didn't have_message to process. |
446 if (!have_message) | 518 if (!have_message) |
447 return false; | 519 return false; |
448 | 520 |
449 // Guarantee we'll get another time slice in the case where we go into native | 521 // Guarantee we'll get another time slice in the case where we go into native |
450 // windows code. This ScheduleWork() may hurt performance a tiny bit when | 522 // windows code. This ScheduleWork() may hurt performance a tiny bit when |
451 // tasks appear very infrequently, but when the event queue is busy, the | 523 // tasks appear very infrequently, but when the event queue is busy, the |
452 // kMsgHaveWork events get (percentage wise) rarer and rarer. | 524 // kMsgHaveWork events get (percentage wise) rarer and rarer. |
453 ScheduleWork(); | 525 ScheduleWork(); |
454 return ProcessMessageHelper(msg); | 526 return ProcessMessageHelper(msg); |
455 } | 527 } |
456 | 528 |
457 void MessagePumpForUI::SetMessageFilter( | 529 void MessagePumpForUI::SetMessageFilter( |
458 scoped_ptr<MessageFilter> message_filter) { | 530 scoped_ptr<MessageFilter> message_filter) { |
459 message_filter_ = message_filter.Pass(); | 531 message_filter_ = message_filter.Pass(); |
460 } | 532 } |
461 | 533 |
462 //----------------------------------------------------------------------------- | 534 //----------------------------------------------------------------------------- |
463 // MessagePumpForIO public: | 535 // MessagePumpForIO public: |
464 | 536 |
465 MessagePumpForIO::MessagePumpForIO() { | 537 MessagePumpForIO::MessagePumpForIO() { |
466 port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1)); | 538 port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1)); |
467 DCHECK(port_.IsValid()); | 539 DCHECK(port_.IsValid()); |
468 } | 540 } |
469 | 541 |
470 void MessagePumpForIO::ScheduleWork() { | 542 void MessagePumpForIO::ScheduleWork() { |
471 if (InterlockedExchange(&have_work_, 1)) | 543 if (InterlockedExchange(&pump_state_, kPumpHaveWork)) |
472 return; // Someone else continued the pumping. | 544 return; // Someone else continued the pumping. |
473 | 545 |
474 // Make sure the MessagePump does some work for us. | 546 // Make sure the MessagePump does some work for us. |
475 BOOL ret = PostQueuedCompletionStatus(port_, 0, | 547 BOOL ret = PostQueuedCompletionStatus(port_, 0, |
476 reinterpret_cast<ULONG_PTR>(this), | 548 reinterpret_cast<ULONG_PTR>(this), |
477 reinterpret_cast<OVERLAPPED*>(this)); | 549 reinterpret_cast<OVERLAPPED*>(this)); |
478 if (ret) | 550 if (ret) |
479 return; // Post worked perfectly. | 551 return; // Post worked perfectly. |
480 | 552 |
481 // See comment in MessagePumpForUI::ScheduleWork() for this error recovery. | 553 // See comment in MessagePumpForUI::ScheduleWork() for this error recovery. |
482 InterlockedExchange(&have_work_, 0); // Clarify that we didn't succeed. | 554 InterlockedExchange(&pump_state_, kPumpIdle); |
483 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR, | 555 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR, |
484 MESSAGE_LOOP_PROBLEM_MAX); | 556 MESSAGE_LOOP_PROBLEM_MAX); |
485 } | 557 } |
486 | 558 |
487 void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { | 559 void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { |
488 // We know that we can't be blocked right now since this method can only be | 560 // We know that we can't be blocked right now since this method can only be |
489 // called on the same thread as Run, so we only need to update our record of | 561 // called on the same thread as Run, so we only need to update our record of |
490 // how long to sleep when we do sleep. | 562 // how long to sleep when we do sleep. |
491 delayed_work_time_ = delayed_work_time; | 563 delayed_work_time_ = delayed_work_time; |
492 } | 564 } |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
617 item->handler = KeyToHandler(key, &item->has_valid_io_context); | 689 item->handler = KeyToHandler(key, &item->has_valid_io_context); |
618 item->context = reinterpret_cast<IOContext*>(overlapped); | 690 item->context = reinterpret_cast<IOContext*>(overlapped); |
619 return true; | 691 return true; |
620 } | 692 } |
621 | 693 |
622 bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) { | 694 bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) { |
623 if (this == reinterpret_cast<MessagePumpForIO*>(item.context) && | 695 if (this == reinterpret_cast<MessagePumpForIO*>(item.context) && |
624 this == reinterpret_cast<MessagePumpForIO*>(item.handler)) { | 696 this == reinterpret_cast<MessagePumpForIO*>(item.handler)) { |
625 // This is our internal completion. | 697 // This is our internal completion. |
626 DCHECK(!item.bytes_transfered); | 698 DCHECK(!item.bytes_transfered); |
627 InterlockedExchange(&have_work_, 0); | 699 InterlockedExchange(&pump_state_, kPumpIdle); |
628 return true; | 700 return true; |
629 } | 701 } |
630 return false; | 702 return false; |
631 } | 703 } |
632 | 704 |
633 // Returns a completion item that was previously received. | 705 // Returns a completion item that was previously received. |
634 bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) { | 706 bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) { |
635 DCHECK(!completed_io_.empty()); | 707 DCHECK(!completed_io_.empty()); |
636 for (std::list<IOItem>::iterator it = completed_io_.begin(); | 708 for (std::list<IOItem>::iterator it = completed_io_.begin(); |
637 it != completed_io_.end(); ++it) { | 709 it != completed_io_.end(); ++it) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
678 | 750 |
679 // static | 751 // static |
680 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( | 752 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( |
681 ULONG_PTR key, | 753 ULONG_PTR key, |
682 bool* has_valid_io_context) { | 754 bool* has_valid_io_context) { |
683 *has_valid_io_context = ((key & 1) == 0); | 755 *has_valid_io_context = ((key & 1) == 0); |
684 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); | 756 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); |
685 } | 757 } |
686 | 758 |
687 } // namespace base | 759 } // namespace base |
OLD | NEW |