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