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; | |
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 | |
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 | |
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, | |
rvargas (doing something else)
2013/06/12 00:22:23
To be honest I prefer the version with a lock here
alexeypa (please no reviews)
2013/06/12 18:05:22
Well, Darin's reaction was exactly the opposite. H
rvargas (doing something else)
2013/06/12 18:24:24
Yes, I read all the comments on the original CL be
alexeypa (please no reviews)
2013/06/12 18:57:25
OK, fair enough. I resurrected the version with th
| |
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 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
289 | 356 |
290 void MessagePumpForUI::WaitForWork() { | 357 void MessagePumpForUI::WaitForWork() { |
291 // Wait until a message is available, up to the time needed by the timer | 358 // Wait until a message is available, up to the time needed by the timer |
292 // manager to fire the next set of timers. | 359 // manager to fire the next set of timers. |
293 int delay = GetCurrentDelay(); | 360 int delay = GetCurrentDelay(); |
294 if (delay < 0) // Negative value means no timers waiting. | 361 if (delay < 0) // Negative value means no timers waiting. |
295 delay = INFINITE; | 362 delay = INFINITE; |
296 | 363 |
297 DWORD result; | 364 DWORD result; |
298 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, | 365 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, |
299 MWMO_INPUTAVAILABLE); | 366 MWMO_ALERTABLE | MWMO_INPUTAVAILABLE); |
300 | 367 |
301 if (WAIT_OBJECT_0 == result) { | 368 if (WAIT_OBJECT_0 == result) { |
302 // A WM_* message is available. | 369 // A WM_* message is available. |
303 // If a parent child relationship exists between windows across threads | 370 // If a parent child relationship exists between windows across threads |
304 // then their thread inputs are implicitly attached. | 371 // then their thread inputs are implicitly attached. |
305 // This causes the MsgWaitForMultipleObjectsEx API to return indicating | 372 // This causes the MsgWaitForMultipleObjectsEx API to return indicating |
306 // that messages are ready for processing (Specifically, mouse messages | 373 // that messages are ready for processing (Specifically, mouse messages |
307 // intended for the child window may appear if the child window has | 374 // intended for the child window may appear if the child window has |
308 // capture). | 375 // capture). |
309 // The subsequent PeekMessages call may fail to return any messages thus | 376 // The subsequent PeekMessages call may fail to return any messages thus |
310 // causing us to enter a tight loop at times. | 377 // causing us to enter a tight loop at times. |
311 // The WaitMessage call below is a workaround to give the child window | 378 // The WaitMessage call below is a workaround to give the child window |
312 // some time to process its input messages. | 379 // some time to process its input messages. |
313 MSG msg = {0}; | 380 MSG msg = {0}; |
314 DWORD queue_status = GetQueueStatus(QS_MOUSE); | 381 DWORD queue_status = GetQueueStatus(QS_MOUSE); |
315 if (HIWORD(queue_status) & QS_MOUSE && | 382 if (HIWORD(queue_status) & QS_MOUSE && |
316 !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) { | 383 !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) { |
317 WaitMessage(); | 384 WaitMessage(); |
318 } | 385 } |
319 return; | 386 return; |
387 } else if (WAIT_IO_COMPLETION == result) { | |
388 // The wait was ended by one or more APCs. It could be cause | |
389 // MessagePumpUI::ScheduleWork() is trying to wake up the message loop | |
390 // thread. | |
391 return; | |
320 } | 392 } |
321 | 393 |
322 DCHECK_NE(WAIT_FAILED, result) << GetLastError(); | 394 DCHECK_NE(WAIT_FAILED, result) << GetLastError(); |
323 } | 395 } |
324 | 396 |
325 void MessagePumpForUI::HandleWorkMessage() { | 397 void MessagePumpForUI::HandleWorkMessage() { |
326 // If we are being called outside of the context of Run, then don't try to do | 398 // If we are being called outside of the context of Run, then don't try to do |
327 // any work. This could correspond to a MessageBox call or something of that | 399 // any work. This could correspond to a MessageBox call or something of that |
328 // sort. | 400 // sort. |
329 if (!state_) { | 401 if (!state_) { |
330 // Since we handled a kMsgHaveWork message, we must still update this flag. | 402 // Since we handled a kMsgHaveWork message, we must still update this flag. |
331 InterlockedExchange(&have_work_, 0); | 403 InterlockedExchange(&pump_state_, kPumpIdle); |
332 return; | 404 return; |
333 } | 405 } |
334 | 406 |
335 // Let whatever would have run had we not been putting messages in the queue | 407 // Let whatever would have run had we not been putting messages in the queue |
336 // run now. This is an attempt to make our dummy message not starve other | 408 // run now. This is an attempt to make our dummy message not starve other |
337 // messages that may be in the Windows message queue. | 409 // messages that may be in the Windows message queue. |
338 ProcessPumpReplacementMessage(); | 410 ProcessPumpReplacementMessage(); |
339 | 411 |
340 // Now give the delegate a chance to do some work. He'll let us know if he | 412 // Now give the delegate a chance to do some work. He'll let us know if he |
341 // needs to do more work. | 413 // needs to do more work. |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
409 DidProcessMessage(msg); | 481 DidProcessMessage(msg); |
410 return true; | 482 return true; |
411 } | 483 } |
412 | 484 |
413 bool MessagePumpForUI::ProcessPumpReplacementMessage() { | 485 bool MessagePumpForUI::ProcessPumpReplacementMessage() { |
414 // When we encounter a kMsgHaveWork message, this method is called to peek | 486 // When we encounter a kMsgHaveWork message, this method is called to peek |
415 // and process a replacement message, such as a WM_PAINT or WM_TIMER. The | 487 // and process a replacement message, such as a WM_PAINT or WM_TIMER. The |
416 // goal is to make the kMsgHaveWork as non-intrusive as possible, even though | 488 // goal is to make the kMsgHaveWork as non-intrusive as possible, even though |
417 // a continuous stream of such messages are posted. This method carefully | 489 // a continuous stream of such messages are posted. This method carefully |
418 // peeks a message while there is no chance for a kMsgHaveWork to be pending, | 490 // peeks a message while there is no chance for a kMsgHaveWork to be pending, |
419 // then resets the have_work_ flag (allowing a replacement kMsgHaveWork to | 491 // then resets the pump_state_ flag (allowing a replacement kMsgHaveWork to |
420 // possibly be posted), and finally dispatches that peeked replacement. Note | 492 // possibly be posted), and finally dispatches that peeked replacement. Note |
421 // that the re-post of kMsgHaveWork may be asynchronous to this thread!! | 493 // that the re-post of kMsgHaveWork may be asynchronous to this thread!! |
422 | 494 |
423 bool have_message = false; | 495 bool have_message = false; |
424 MSG msg; | 496 MSG msg; |
425 // We should not process all window messages if we are in the context of an | 497 // We should not process all window messages if we are in the context of an |
426 // OS modal loop, i.e. in the context of a windows API call like MessageBox. | 498 // OS modal loop, i.e. in the context of a windows API call like MessageBox. |
427 // This is to ensure that these messages are peeked out by the OS modal loop. | 499 // This is to ensure that these messages are peeked out by the OS modal loop. |
428 if (MessageLoop::current()->os_modal_loop()) { | 500 if (MessageLoop::current()->os_modal_loop()) { |
429 // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above. | 501 // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above. |
430 have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) || | 502 have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) || |
431 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); | 503 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); |
432 } else { | 504 } else { |
433 have_message = !!message_filter_->DoPeekMessage(&msg, NULL, 0, 0, | 505 have_message = !!message_filter_->DoPeekMessage(&msg, NULL, 0, 0, |
434 PM_REMOVE); | 506 PM_REMOVE); |
435 } | 507 } |
436 | 508 |
437 DCHECK(!have_message || kMsgHaveWork != msg.message || | 509 DCHECK(!have_message || kMsgHaveWork != msg.message || |
438 msg.hwnd != message_hwnd_); | 510 msg.hwnd != message_hwnd_); |
439 | 511 |
440 // Since we discarded a kMsgHaveWork message, we must update the flag. | 512 // Since we discarded a kMsgHaveWork message, we must update the flag. |
441 int old_have_work = InterlockedExchange(&have_work_, 0); | 513 int old_have_work = InterlockedExchange(&pump_state_, kPumpIdle); |
442 DCHECK(old_have_work); | 514 DCHECK(old_have_work); |
443 | 515 |
444 // We don't need a special time slice if we didn't have_message to process. | 516 // We don't need a special time slice if we didn't have_message to process. |
445 if (!have_message) | 517 if (!have_message) |
446 return false; | 518 return false; |
447 | 519 |
448 // Guarantee we'll get another time slice in the case where we go into native | 520 // Guarantee we'll get another time slice in the case where we go into native |
449 // windows code. This ScheduleWork() may hurt performance a tiny bit when | 521 // windows code. This ScheduleWork() may hurt performance a tiny bit when |
450 // tasks appear very infrequently, but when the event queue is busy, the | 522 // tasks appear very infrequently, but when the event queue is busy, the |
451 // kMsgHaveWork events get (percentage wise) rarer and rarer. | 523 // kMsgHaveWork events get (percentage wise) rarer and rarer. |
452 ScheduleWork(); | 524 ScheduleWork(); |
453 return ProcessMessageHelper(msg); | 525 return ProcessMessageHelper(msg); |
454 } | 526 } |
455 | 527 |
456 void MessagePumpForUI::SetMessageFilter( | 528 void MessagePumpForUI::SetMessageFilter( |
457 scoped_ptr<MessageFilter> message_filter) { | 529 scoped_ptr<MessageFilter> message_filter) { |
458 message_filter_ = message_filter.Pass(); | 530 message_filter_ = message_filter.Pass(); |
459 } | 531 } |
460 | 532 |
461 //----------------------------------------------------------------------------- | 533 //----------------------------------------------------------------------------- |
462 // MessagePumpForIO public: | 534 // MessagePumpForIO public: |
463 | 535 |
464 MessagePumpForIO::MessagePumpForIO() { | 536 MessagePumpForIO::MessagePumpForIO() { |
465 port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1)); | 537 port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1)); |
466 DCHECK(port_.IsValid()); | 538 DCHECK(port_.IsValid()); |
467 } | 539 } |
468 | 540 |
469 void MessagePumpForIO::ScheduleWork() { | 541 void MessagePumpForIO::ScheduleWork() { |
470 if (InterlockedExchange(&have_work_, 1)) | 542 if (InterlockedExchange(&pump_state_, kPumpHaveWork)) |
471 return; // Someone else continued the pumping. | 543 return; // Someone else continued the pumping. |
472 | 544 |
473 // Make sure the MessagePump does some work for us. | 545 // Make sure the MessagePump does some work for us. |
474 BOOL ret = PostQueuedCompletionStatus(port_, 0, | 546 BOOL ret = PostQueuedCompletionStatus(port_, 0, |
475 reinterpret_cast<ULONG_PTR>(this), | 547 reinterpret_cast<ULONG_PTR>(this), |
476 reinterpret_cast<OVERLAPPED*>(this)); | 548 reinterpret_cast<OVERLAPPED*>(this)); |
477 if (ret) | 549 if (ret) |
478 return; // Post worked perfectly. | 550 return; // Post worked perfectly. |
479 | 551 |
480 // See comment in MessagePumpForUI::ScheduleWork() for this error recovery. | 552 // See comment in MessagePumpForUI::ScheduleWork() for this error recovery. |
481 InterlockedExchange(&have_work_, 0); // Clarify that we didn't succeed. | 553 InterlockedExchange(&pump_state_, kPumpIdle); |
482 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR, | 554 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR, |
483 MESSAGE_LOOP_PROBLEM_MAX); | 555 MESSAGE_LOOP_PROBLEM_MAX); |
484 } | 556 } |
485 | 557 |
486 void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { | 558 void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { |
487 // We know that we can't be blocked right now since this method can only be | 559 // We know that we can't be blocked right now since this method can only be |
488 // called on the same thread as Run, so we only need to update our record of | 560 // called on the same thread as Run, so we only need to update our record of |
489 // how long to sleep when we do sleep. | 561 // how long to sleep when we do sleep. |
490 delayed_work_time_ = delayed_work_time; | 562 delayed_work_time_ = delayed_work_time; |
491 } | 563 } |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
616 item->handler = KeyToHandler(key, &item->has_valid_io_context); | 688 item->handler = KeyToHandler(key, &item->has_valid_io_context); |
617 item->context = reinterpret_cast<IOContext*>(overlapped); | 689 item->context = reinterpret_cast<IOContext*>(overlapped); |
618 return true; | 690 return true; |
619 } | 691 } |
620 | 692 |
621 bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) { | 693 bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) { |
622 if (this == reinterpret_cast<MessagePumpForIO*>(item.context) && | 694 if (this == reinterpret_cast<MessagePumpForIO*>(item.context) && |
623 this == reinterpret_cast<MessagePumpForIO*>(item.handler)) { | 695 this == reinterpret_cast<MessagePumpForIO*>(item.handler)) { |
624 // This is our internal completion. | 696 // This is our internal completion. |
625 DCHECK(!item.bytes_transfered); | 697 DCHECK(!item.bytes_transfered); |
626 InterlockedExchange(&have_work_, 0); | 698 InterlockedExchange(&pump_state_, kPumpIdle); |
627 return true; | 699 return true; |
628 } | 700 } |
629 return false; | 701 return false; |
630 } | 702 } |
631 | 703 |
632 // Returns a completion item that was previously received. | 704 // Returns a completion item that was previously received. |
633 bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) { | 705 bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) { |
634 DCHECK(!completed_io_.empty()); | 706 DCHECK(!completed_io_.empty()); |
635 for (std::list<IOItem>::iterator it = completed_io_.begin(); | 707 for (std::list<IOItem>::iterator it = completed_io_.begin(); |
636 it != completed_io_.end(); ++it) { | 708 it != completed_io_.end(); ++it) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
677 | 749 |
678 // static | 750 // static |
679 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( | 751 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( |
680 ULONG_PTR key, | 752 ULONG_PTR key, |
681 bool* has_valid_io_context) { | 753 bool* has_valid_io_context) { |
682 *has_valid_io_context = ((key & 1) == 0); | 754 *has_valid_io_context = ((key & 1) == 0); |
683 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); | 755 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); |
684 } | 756 } |
685 | 757 |
686 } // namespace base | 758 } // namespace base |
OLD | NEW |