Chromium Code Reviews| 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 |