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; | |
|
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 |