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" |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
60 s.run_depth = state_ ? state_->run_depth + 1 : 1; | 60 s.run_depth = state_ ? state_->run_depth + 1 : 1; |
61 | 61 |
62 RunState* previous_state = state_; | 62 RunState* previous_state = state_; |
63 state_ = &s; | 63 state_ = &s; |
64 | 64 |
65 DoRunLoop(); | 65 DoRunLoop(); |
66 | 66 |
67 state_ = previous_state; | 67 state_ = previous_state; |
68 } | 68 } |
69 | 69 |
70 void MessagePumpWin::Run(Delegate* delegate) { | |
71 RunWithDispatcher(delegate, NULL); | |
72 } | |
73 | |
70 void MessagePumpWin::Quit() { | 74 void MessagePumpWin::Quit() { |
71 DCHECK(state_); | 75 DCHECK(state_); |
72 state_->should_quit = true; | 76 state_->should_quit = true; |
73 } | 77 } |
74 | 78 |
75 //----------------------------------------------------------------------------- | 79 //----------------------------------------------------------------------------- |
76 // MessagePumpWin protected: | 80 // MessagePumpWin protected: |
77 | 81 |
78 int MessagePumpWin::GetCurrentDelay() const { | 82 int MessagePumpWin::GetCurrentDelay() const { |
79 if (delayed_work_time_.is_null()) | 83 if (delayed_work_time_.is_null()) |
(...skipping 16 matching lines...) Expand all Loading... | |
96 //----------------------------------------------------------------------------- | 100 //----------------------------------------------------------------------------- |
97 // MessagePumpForUI public: | 101 // MessagePumpForUI public: |
98 | 102 |
99 MessagePumpForUI::MessagePumpForUI() | 103 MessagePumpForUI::MessagePumpForUI() |
100 : atom_(0), | 104 : atom_(0), |
101 message_filter_(new MessageFilter) { | 105 message_filter_(new MessageFilter) { |
102 InitMessageWnd(); | 106 InitMessageWnd(); |
103 } | 107 } |
104 | 108 |
105 MessagePumpForUI::~MessagePumpForUI() { | 109 MessagePumpForUI::~MessagePumpForUI() { |
106 DestroyWindow(message_hwnd_); | 110 DCHECK(!atom_); |
107 UnregisterClass(MAKEINTATOM(atom_), | 111 DCHECK(!message_hwnd_); |
108 base::GetModuleFromAddress(&WndProcThunk)); | |
109 } | 112 } |
110 | 113 |
111 void MessagePumpForUI::ScheduleWork() { | 114 void MessagePumpForUI::ScheduleWork() { |
112 if (InterlockedExchange(&have_work_, 1)) | 115 if (InterlockedExchange(&have_work_, 1)) |
113 return; // Someone else continued the pumping. | 116 return; // Someone else continued the pumping. |
114 | 117 |
115 // Make sure the MessagePump does some work for us. | 118 if (!message_hwnd_lock_.Try()) |
darin (slow to review)
2013/06/18 18:28:42
Please add a comment explaining the design of this
alexeypa (please no reviews)
2013/06/18 19:44:23
Done.
| |
116 BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork, | 119 return; |
117 reinterpret_cast<WPARAM>(this), 0); | 120 |
118 if (ret) | 121 { |
119 return; // There was room in the Window Message queue. | 122 base::AutoLock lock(message_hwnd_lock_, base::AutoLock::AlreadyAcquired()); |
123 | |
124 // Do nothing if the window has been destroyed already. | |
125 if (!message_hwnd_) | |
126 return; | |
127 | |
128 // Make sure the MessagePump does some work for us. | |
129 if (PostMessage(message_hwnd_, kMsgHaveWork, | |
130 reinterpret_cast<WPARAM>(this), 0)) { | |
131 return; | |
132 } | |
133 } | |
120 | 134 |
121 // We have failed to insert a have-work message, so there is a chance that we | 135 // 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 | 136 // 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 | 137 // 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. :-( | 138 // 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 | 139 // 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 | 140 // 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 | 141 // recovery. Nested loops are pretty transient (we think), so this will |
128 // probably be recoverable. | 142 // probably be recoverable. |
129 InterlockedExchange(&have_work_, 0); // Clarify that we didn't really insert. | 143 InterlockedExchange(&have_work_, 0); // Clarify that we didn't really insert. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
165 delay_msec, NULL); | 179 delay_msec, NULL); |
166 if (ret) | 180 if (ret) |
167 return; | 181 return; |
168 // If we can't set timers, we are in big trouble... but cross our fingers for | 182 // If we can't set timers, we are in big trouble... but cross our fingers for |
169 // now. | 183 // now. |
170 // TODO(jar): If we don't see this error, use a CHECK() here instead. | 184 // TODO(jar): If we don't see this error, use a CHECK() here instead. |
171 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR, | 185 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR, |
172 MESSAGE_LOOP_PROBLEM_MAX); | 186 MESSAGE_LOOP_PROBLEM_MAX); |
173 } | 187 } |
174 | 188 |
189 void MessagePumpForUI::Stop() { | |
190 HWND message_hwnd; | |
191 { | |
192 base::AutoLock lock(message_hwnd_lock_); | |
193 | |
194 // Let ScheduleWork() know that the window has been destoyed. | |
195 message_hwnd = message_hwnd_; | |
196 message_hwnd_ = NULL; | |
197 } | |
198 | |
199 // Destoy the window and its class. The destructor checks whether | |
200 // |message_hwnd_| and |atom_| are destroyed, so the variables should be | |
201 // cleared here. | |
202 DestroyWindow(message_hwnd); | |
203 UnregisterClass(MAKEINTATOM(atom_), | |
204 base::GetModuleFromAddress(&WndProcThunk)); | |
205 atom_ = 0; | |
206 } | |
207 | |
175 void MessagePumpForUI::PumpOutPendingPaintMessages() { | 208 void MessagePumpForUI::PumpOutPendingPaintMessages() { |
176 // If we are being called outside of the context of Run, then don't try to do | 209 // If we are being called outside of the context of Run, then don't try to do |
177 // any work. | 210 // any work. |
178 if (!state_) | 211 if (!state_) |
179 return; | 212 return; |
180 | 213 |
181 // Create a mini-message-pump to force immediate processing of only Windows | 214 // 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 | 215 // 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 | 216 // to get the job done. Actual common max is 4 peeks, but we'll be a little |
184 // safe here. | 217 // safe here. |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
471 return; // Someone else continued the pumping. | 504 return; // Someone else continued the pumping. |
472 | 505 |
473 // Make sure the MessagePump does some work for us. | 506 // Make sure the MessagePump does some work for us. |
474 BOOL ret = PostQueuedCompletionStatus(port_, 0, | 507 BOOL ret = PostQueuedCompletionStatus(port_, 0, |
475 reinterpret_cast<ULONG_PTR>(this), | 508 reinterpret_cast<ULONG_PTR>(this), |
476 reinterpret_cast<OVERLAPPED*>(this)); | 509 reinterpret_cast<OVERLAPPED*>(this)); |
477 if (ret) | 510 if (ret) |
478 return; // Post worked perfectly. | 511 return; // Post worked perfectly. |
479 | 512 |
480 // See comment in MessagePumpForUI::ScheduleWork() for this error recovery. | 513 // See comment in MessagePumpForUI::ScheduleWork() for this error recovery. |
481 InterlockedExchange(&have_work_, 0); // Clarify that we didn't succeed. | 514 InterlockedExchange(&have_work_, 0); |
482 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR, | 515 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR, |
483 MESSAGE_LOOP_PROBLEM_MAX); | 516 MESSAGE_LOOP_PROBLEM_MAX); |
484 } | 517 } |
485 | 518 |
486 void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { | 519 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 | 520 // 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 | 521 // 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. | 522 // how long to sleep when we do sleep. |
490 delayed_work_time_ = delayed_work_time; | 523 delayed_work_time_ = delayed_work_time; |
491 } | 524 } |
492 | 525 |
526 void MessagePumpForIO::Stop() { | |
527 } | |
528 | |
493 void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle, | 529 void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle, |
494 IOHandler* handler) { | 530 IOHandler* handler) { |
495 ULONG_PTR key = HandlerToKey(handler, true); | 531 ULONG_PTR key = HandlerToKey(handler, true); |
496 HANDLE port = CreateIoCompletionPort(file_handle, port_, key, 1); | 532 HANDLE port = CreateIoCompletionPort(file_handle, port_, key, 1); |
497 DPCHECK(port); | 533 DPCHECK(port); |
498 } | 534 } |
499 | 535 |
500 bool MessagePumpForIO::RegisterJobObject(HANDLE job_handle, | 536 bool MessagePumpForIO::RegisterJobObject(HANDLE job_handle, |
501 IOHandler* handler) { | 537 IOHandler* handler) { |
502 // Job object notifications use the OVERLAPPED pointer to carry the message | 538 // Job object notifications use the OVERLAPPED pointer to carry the message |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
677 | 713 |
678 // static | 714 // static |
679 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( | 715 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( |
680 ULONG_PTR key, | 716 ULONG_PTR key, |
681 bool* has_valid_io_context) { | 717 bool* has_valid_io_context) { |
682 *has_valid_io_context = ((key & 1) == 0); | 718 *has_valid_io_context = ((key & 1) == 0); |
683 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); | 719 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); |
684 } | 720 } |
685 | 721 |
686 } // namespace base | 722 } // namespace base |
OLD | NEW |