OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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/histogram.h" | 9 #include "base/histogram.h" |
10 #include "base/win_util.h" | 10 #include "base/win_util.h" |
11 | 11 |
12 using base::Time; | 12 using base::Time; |
13 | 13 |
14 namespace { | |
15 | |
16 class HandlerData : public base::MessagePumpForIO::Watcher { | |
17 public: | |
18 typedef base::MessagePumpForIO::IOHandler IOHandler; | |
19 HandlerData(OVERLAPPED* context, IOHandler* handler) | |
20 : context_(context), handler_(handler) {} | |
21 ~HandlerData() {} | |
22 | |
23 virtual void OnObjectSignaled(HANDLE object); | |
24 | |
25 private: | |
26 OVERLAPPED* context_; | |
27 IOHandler* handler_; | |
28 | |
29 DISALLOW_COPY_AND_ASSIGN(HandlerData); | |
30 }; | |
31 | |
32 void HandlerData::OnObjectSignaled(HANDLE object) { | |
33 DCHECK(object == context_->hEvent); | |
34 DWORD transfered; | |
35 DWORD error = ERROR_SUCCESS; | |
36 BOOL ret = GetOverlappedResult(NULL, context_, &transfered, FALSE); | |
37 if (!ret) { | |
38 error = GetLastError(); | |
39 DCHECK(ERROR_HANDLE_EOF == error || ERROR_BROKEN_PIPE == error); | |
40 transfered = 0; | |
41 } | |
42 | |
43 ResetEvent(context_->hEvent); | |
44 handler_->OnIOCompleted(context_, transfered, error); | |
45 } | |
46 | |
47 } // namespace | |
48 | |
49 namespace base { | 14 namespace base { |
50 | 15 |
51 static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow"; | 16 static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow"; |
52 | 17 |
53 // Message sent to get an additional time slice for pumping (processing) another | 18 // Message sent to get an additional time slice for pumping (processing) another |
54 // task (a series of such messages creates a continuous task pump). | 19 // task (a series of such messages creates a continuous task pump). |
55 static const int kMsgHaveWork = WM_USER + 1; | 20 static const int kMsgHaveWork = WM_USER + 1; |
56 | 21 |
57 #ifndef NDEBUG | |
58 // Force exercise of polling model. | |
59 static const int kMaxWaitObjects = 8; | |
60 #else | |
61 static const int kMaxWaitObjects = MAXIMUM_WAIT_OBJECTS; | |
62 #endif | |
63 | |
64 //----------------------------------------------------------------------------- | 22 //----------------------------------------------------------------------------- |
65 // MessagePumpWin public: | 23 // MessagePumpWin public: |
66 | 24 |
67 MessagePumpWin::MessagePumpWin() : have_work_(0), state_(NULL) { | |
68 InitMessageWnd(); | |
69 } | |
70 | |
71 MessagePumpWin::~MessagePumpWin() { | |
72 DestroyWindow(message_hwnd_); | |
73 } | |
74 | |
75 void MessagePumpWin::AddObserver(Observer* observer) { | 25 void MessagePumpWin::AddObserver(Observer* observer) { |
76 observers_.AddObserver(observer); | 26 observers_.AddObserver(observer); |
77 } | 27 } |
78 | 28 |
79 void MessagePumpWin::RemoveObserver(Observer* observer) { | 29 void MessagePumpWin::RemoveObserver(Observer* observer) { |
80 observers_.RemoveObserver(observer); | 30 observers_.RemoveObserver(observer); |
81 } | 31 } |
82 | 32 |
83 void MessagePumpWin::WillProcessMessage(const MSG& msg) { | 33 void MessagePumpWin::WillProcessMessage(const MSG& msg) { |
84 FOR_EACH_OBSERVER(Observer, observers_, WillProcessMessage(msg)); | 34 FOR_EACH_OBSERVER(Observer, observers_, WillProcessMessage(msg)); |
85 } | 35 } |
86 | 36 |
87 void MessagePumpWin::DidProcessMessage(const MSG& msg) { | 37 void MessagePumpWin::DidProcessMessage(const MSG& msg) { |
88 FOR_EACH_OBSERVER(Observer, observers_, DidProcessMessage(msg)); | 38 FOR_EACH_OBSERVER(Observer, observers_, DidProcessMessage(msg)); |
89 } | 39 } |
90 | 40 |
91 void MessagePumpWin::PumpOutPendingPaintMessages() { | |
92 // If we are being called outside of the context of Run, then don't try to do | |
93 // any work. | |
94 if (!state_) | |
95 return; | |
96 | |
97 // Create a mini-message-pump to force immediate processing of only Windows | |
98 // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking | |
99 // to get the job done. Actual common max is 4 peeks, but we'll be a little | |
100 // safe here. | |
101 const int kMaxPeekCount = 20; | |
102 bool win2k = win_util::GetWinVersion() <= win_util::WINVERSION_2000; | |
103 int peek_count; | |
104 for (peek_count = 0; peek_count < kMaxPeekCount; ++peek_count) { | |
105 MSG msg; | |
106 if (win2k) { | |
107 if (!PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE)) | |
108 break; | |
109 } else { | |
110 if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_PAINT)) | |
111 break; | |
112 } | |
113 ProcessMessageHelper(msg); | |
114 if (state_->should_quit) // Handle WM_QUIT. | |
115 break; | |
116 } | |
117 // Histogram what was really being used, to help to adjust kMaxPeekCount. | |
118 DHISTOGRAM_COUNTS(L"Loop.PumpOutPendingPaintMessages Peeks", peek_count); | |
119 } | |
120 | |
121 void MessagePumpWin::RunWithDispatcher( | 41 void MessagePumpWin::RunWithDispatcher( |
122 Delegate* delegate, Dispatcher* dispatcher) { | 42 Delegate* delegate, Dispatcher* dispatcher) { |
123 RunState s; | 43 RunState s; |
124 s.delegate = delegate; | 44 s.delegate = delegate; |
125 s.dispatcher = dispatcher; | 45 s.dispatcher = dispatcher; |
126 s.should_quit = false; | 46 s.should_quit = false; |
127 s.run_depth = state_ ? state_->run_depth + 1 : 1; | 47 s.run_depth = state_ ? state_->run_depth + 1 : 1; |
128 | 48 |
129 RunState* previous_state = state_; | 49 RunState* previous_state = state_; |
130 state_ = &s; | 50 state_ = &s; |
131 | 51 |
132 DoRunLoop(); | 52 DoRunLoop(); |
133 | 53 |
134 state_ = previous_state; | 54 state_ = previous_state; |
135 } | 55 } |
136 | 56 |
137 void MessagePumpWin::Quit() { | 57 void MessagePumpWin::Quit() { |
138 DCHECK(state_); | 58 DCHECK(state_); |
139 state_->should_quit = true; | 59 state_->should_quit = true; |
140 } | 60 } |
141 | 61 |
142 void MessagePumpWin::ScheduleWork() { | 62 //----------------------------------------------------------------------------- |
| 63 // MessagePumpWin protected: |
| 64 |
| 65 int MessagePumpWin::GetCurrentDelay() const { |
| 66 if (delayed_work_time_.is_null()) |
| 67 return -1; |
| 68 |
| 69 // Be careful here. TimeDelta has a precision of microseconds, but we want a |
| 70 // value in milliseconds. If there are 5.5ms left, should the delay be 5 or |
| 71 // 6? It should be 6 to avoid executing delayed work too early. |
| 72 double timeout = ceil((delayed_work_time_ - Time::Now()).InMillisecondsF()); |
| 73 |
| 74 // If this value is negative, then we need to run delayed work soon. |
| 75 int delay = static_cast<int>(timeout); |
| 76 if (delay < 0) |
| 77 delay = 0; |
| 78 |
| 79 return delay; |
| 80 } |
| 81 |
| 82 //----------------------------------------------------------------------------- |
| 83 // MessagePumpForUI public: |
| 84 |
| 85 MessagePumpForUI::MessagePumpForUI() { |
| 86 InitMessageWnd(); |
| 87 } |
| 88 |
| 89 MessagePumpForUI::~MessagePumpForUI() { |
| 90 DestroyWindow(message_hwnd_); |
| 91 } |
| 92 |
| 93 void MessagePumpForUI::ScheduleWork() { |
143 if (InterlockedExchange(&have_work_, 1)) | 94 if (InterlockedExchange(&have_work_, 1)) |
144 return; // Someone else continued the pumping. | 95 return; // Someone else continued the pumping. |
145 | 96 |
146 // Make sure the MessagePump does some work for us. | 97 // Make sure the MessagePump does some work for us. |
147 PostMessage(message_hwnd_, kMsgHaveWork, reinterpret_cast<WPARAM>(this), 0); | 98 PostMessage(message_hwnd_, kMsgHaveWork, reinterpret_cast<WPARAM>(this), 0); |
148 } | 99 } |
149 | 100 |
150 void MessagePumpWin::ScheduleDelayedWork(const Time& delayed_work_time) { | 101 void MessagePumpForUI::ScheduleDelayedWork(const Time& delayed_work_time) { |
151 // | 102 // |
152 // We would *like* to provide high resolution timers. Windows timers using | 103 // We would *like* to provide high resolution timers. Windows timers using |
153 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup | 104 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup |
154 // mechanism because the application can enter modal windows loops where it | 105 // mechanism because the application can enter modal windows loops where it |
155 // is not running our MessageLoop; the only way to have our timers fire in | 106 // is not running our MessageLoop; the only way to have our timers fire in |
156 // these cases is to post messages there. | 107 // these cases is to post messages there. |
157 // | 108 // |
158 // To provide sub-10ms timers, we process timers directly from our run loop. | 109 // To provide sub-10ms timers, we process timers directly from our run loop. |
159 // For the common case, timers will be processed there as the run loop does | 110 // For the common case, timers will be processed there as the run loop does |
160 // its normal work. However, we *also* set the system timer so that WM_TIMER | 111 // its normal work. However, we *also* set the system timer so that WM_TIMER |
(...skipping 12 matching lines...) Expand all Loading... |
173 int delay_msec = GetCurrentDelay(); | 124 int delay_msec = GetCurrentDelay(); |
174 DCHECK(delay_msec >= 0); | 125 DCHECK(delay_msec >= 0); |
175 if (delay_msec < USER_TIMER_MINIMUM) | 126 if (delay_msec < USER_TIMER_MINIMUM) |
176 delay_msec = USER_TIMER_MINIMUM; | 127 delay_msec = USER_TIMER_MINIMUM; |
177 | 128 |
178 // Create a WM_TIMER event that will wake us up to check for any pending | 129 // Create a WM_TIMER event that will wake us up to check for any pending |
179 // timers (in case we are running within a nested, external sub-pump). | 130 // timers (in case we are running within a nested, external sub-pump). |
180 SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), delay_msec, NULL); | 131 SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), delay_msec, NULL); |
181 } | 132 } |
182 | 133 |
| 134 void MessagePumpForUI::PumpOutPendingPaintMessages() { |
| 135 // If we are being called outside of the context of Run, then don't try to do |
| 136 // any work. |
| 137 if (!state_) |
| 138 return; |
| 139 |
| 140 // Create a mini-message-pump to force immediate processing of only Windows |
| 141 // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking |
| 142 // to get the job done. Actual common max is 4 peeks, but we'll be a little |
| 143 // safe here. |
| 144 const int kMaxPeekCount = 20; |
| 145 bool win2k = win_util::GetWinVersion() <= win_util::WINVERSION_2000; |
| 146 int peek_count; |
| 147 for (peek_count = 0; peek_count < kMaxPeekCount; ++peek_count) { |
| 148 MSG msg; |
| 149 if (win2k) { |
| 150 if (!PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE)) |
| 151 break; |
| 152 } else { |
| 153 if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_PAINT)) |
| 154 break; |
| 155 } |
| 156 ProcessMessageHelper(msg); |
| 157 if (state_->should_quit) // Handle WM_QUIT. |
| 158 break; |
| 159 } |
| 160 // Histogram what was really being used, to help to adjust kMaxPeekCount. |
| 161 DHISTOGRAM_COUNTS(L"Loop.PumpOutPendingPaintMessages Peeks", peek_count); |
| 162 } |
| 163 |
183 //----------------------------------------------------------------------------- | 164 //----------------------------------------------------------------------------- |
184 // MessagePumpWin protected: | 165 // MessagePumpForUI private: |
185 | 166 |
186 // static | 167 // static |
187 LRESULT CALLBACK MessagePumpWin::WndProcThunk( | 168 LRESULT CALLBACK MessagePumpForUI::WndProcThunk( |
188 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { | 169 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { |
189 switch (message) { | 170 switch (message) { |
190 case kMsgHaveWork: | 171 case kMsgHaveWork: |
191 reinterpret_cast<MessagePumpWin*>(wparam)->HandleWorkMessage(); | 172 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage(); |
192 break; | 173 break; |
193 case WM_TIMER: | 174 case WM_TIMER: |
194 reinterpret_cast<MessagePumpWin*>(wparam)->HandleTimerMessage(); | 175 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage(); |
195 break; | 176 break; |
196 } | 177 } |
197 return DefWindowProc(hwnd, message, wparam, lparam); | 178 return DefWindowProc(hwnd, message, wparam, lparam); |
198 } | 179 } |
199 | 180 |
200 void MessagePumpWin::InitMessageWnd() { | 181 void MessagePumpForUI::DoRunLoop() { |
| 182 // IF this was just a simple PeekMessage() loop (servicing all possible work |
| 183 // queues), then Windows would try to achieve the following order according |
| 184 // to MSDN documentation about PeekMessage with no filter): |
| 185 // * Sent messages |
| 186 // * Posted messages |
| 187 // * Sent messages (again) |
| 188 // * WM_PAINT messages |
| 189 // * WM_TIMER messages |
| 190 // |
| 191 // Summary: none of the above classes is starved, and sent messages has twice |
| 192 // the chance of being processed (i.e., reduced service time). |
| 193 |
| 194 for (;;) { |
| 195 // If we do any work, we may create more messages etc., and more work may |
| 196 // possibly be waiting in another task group. When we (for example) |
| 197 // ProcessNextWindowsMessage(), there is a good chance there are still more |
| 198 // messages waiting. On the other hand, when any of these methods return |
| 199 // having done no work, then it is pretty unlikely that calling them again |
| 200 // quickly will find any work to do. Finally, if they all say they had no |
| 201 // work, then it is a good time to consider sleeping (waiting) for more |
| 202 // work. |
| 203 |
| 204 bool more_work_is_plausible = ProcessNextWindowsMessage(); |
| 205 if (state_->should_quit) |
| 206 break; |
| 207 |
| 208 more_work_is_plausible |= state_->delegate->DoWork(); |
| 209 if (state_->should_quit) |
| 210 break; |
| 211 |
| 212 more_work_is_plausible |= |
| 213 state_->delegate->DoDelayedWork(&delayed_work_time_); |
| 214 // If we did not process any delayed work, then we can assume that our |
| 215 // existing WM_TIMER if any will fire when delayed work should run. We |
| 216 // don't want to disturb that timer if it is already in flight. However, |
| 217 // if we did do all remaining delayed work, then lets kill the WM_TIMER. |
| 218 if (more_work_is_plausible && delayed_work_time_.is_null()) |
| 219 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); |
| 220 if (state_->should_quit) |
| 221 break; |
| 222 |
| 223 if (more_work_is_plausible) |
| 224 continue; |
| 225 |
| 226 more_work_is_plausible = state_->delegate->DoIdleWork(); |
| 227 if (state_->should_quit) |
| 228 break; |
| 229 |
| 230 if (more_work_is_plausible) |
| 231 continue; |
| 232 |
| 233 WaitForWork(); // Wait (sleep) until we have work to do again. |
| 234 } |
| 235 } |
| 236 |
| 237 void MessagePumpForUI::InitMessageWnd() { |
201 HINSTANCE hinst = GetModuleHandle(NULL); | 238 HINSTANCE hinst = GetModuleHandle(NULL); |
202 | 239 |
203 WNDCLASSEX wc = {0}; | 240 WNDCLASSEX wc = {0}; |
204 wc.cbSize = sizeof(wc); | 241 wc.cbSize = sizeof(wc); |
205 wc.lpfnWndProc = WndProcThunk; | 242 wc.lpfnWndProc = WndProcThunk; |
206 wc.hInstance = hinst; | 243 wc.hInstance = hinst; |
207 wc.lpszClassName = kWndClass; | 244 wc.lpszClassName = kWndClass; |
208 RegisterClassEx(&wc); | 245 RegisterClassEx(&wc); |
209 | 246 |
210 message_hwnd_ = | 247 message_hwnd_ = |
211 CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, 0); | 248 CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, 0); |
212 DCHECK(message_hwnd_); | 249 DCHECK(message_hwnd_); |
213 } | 250 } |
214 | 251 |
215 void MessagePumpWin::HandleWorkMessage() { | 252 void MessagePumpForUI::WaitForWork() { |
| 253 // Wait until a message is available, up to the time needed by the timer |
| 254 // manager to fire the next set of timers. |
| 255 int delay = GetCurrentDelay(); |
| 256 if (delay < 0) // Negative value means no timers waiting. |
| 257 delay = INFINITE; |
| 258 |
| 259 DWORD result; |
| 260 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, |
| 261 MWMO_INPUTAVAILABLE); |
| 262 |
| 263 if (WAIT_OBJECT_0 == result) { |
| 264 // A WM_* message is available. |
| 265 // If a parent child relationship exists between windows across threads |
| 266 // then their thread inputs are implicitly attached. |
| 267 // This causes the MsgWaitForMultipleObjectsEx API to return indicating |
| 268 // that messages are ready for processing (specifically mouse messages |
| 269 // intended for the child window. Occurs if the child window has capture) |
| 270 // The subsequent PeekMessages call fails to return any messages thus |
| 271 // causing us to enter a tight loop at times. |
| 272 // The WaitMessage call below is a workaround to give the child window |
| 273 // sometime to process its input messages. |
| 274 MSG msg = {0}; |
| 275 DWORD queue_status = GetQueueStatus(QS_MOUSE); |
| 276 if (HIWORD(queue_status) & QS_MOUSE && |
| 277 !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) { |
| 278 WaitMessage(); |
| 279 } |
| 280 return; |
| 281 } |
| 282 |
| 283 DCHECK_NE(WAIT_FAILED, result) << GetLastError(); |
| 284 } |
| 285 |
| 286 void MessagePumpForUI::HandleWorkMessage() { |
216 // If we are being called outside of the context of Run, then don't try to do | 287 // If we are being called outside of the context of Run, then don't try to do |
217 // any work. This could correspond to a MessageBox call or something of that | 288 // any work. This could correspond to a MessageBox call or something of that |
218 // sort. | 289 // sort. |
219 if (!state_) { | 290 if (!state_) { |
220 // Since we handled a kMsgHaveWork message, we must still update this flag. | 291 // Since we handled a kMsgHaveWork message, we must still update this flag. |
221 InterlockedExchange(&have_work_, 0); | 292 InterlockedExchange(&have_work_, 0); |
222 return; | 293 return; |
223 } | 294 } |
224 | 295 |
225 // Let whatever would have run had we not been putting messages in the queue | 296 // Let whatever would have run had we not been putting messages in the queue |
226 // run now. This is an attempt to make our dummy message not starve other | 297 // run now. This is an attempt to make our dummy message not starve other |
227 // messages that may be in the Windows message queue. | 298 // messages that may be in the Windows message queue. |
228 ProcessPumpReplacementMessage(); | 299 ProcessPumpReplacementMessage(); |
229 | 300 |
230 // Now give the delegate a chance to do some work. He'll let us know if he | 301 // Now give the delegate a chance to do some work. He'll let us know if he |
231 // needs to do more work. | 302 // needs to do more work. |
232 if (state_->delegate->DoWork()) | 303 if (state_->delegate->DoWork()) |
233 ScheduleWork(); | 304 ScheduleWork(); |
234 } | 305 } |
235 | 306 |
236 void MessagePumpWin::HandleTimerMessage() { | 307 void MessagePumpForUI::HandleTimerMessage() { |
237 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); | 308 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); |
238 | 309 |
239 // If we are being called outside of the context of Run, then don't do | 310 // If we are being called outside of the context of Run, then don't do |
240 // anything. This could correspond to a MessageBox call or something of | 311 // anything. This could correspond to a MessageBox call or something of |
241 // that sort. | 312 // that sort. |
242 if (!state_) | 313 if (!state_) |
243 return; | 314 return; |
244 | 315 |
245 state_->delegate->DoDelayedWork(&delayed_work_time_); | 316 state_->delegate->DoDelayedWork(&delayed_work_time_); |
246 if (!delayed_work_time_.is_null()) { | 317 if (!delayed_work_time_.is_null()) { |
247 // A bit gratuitous to set delayed_work_time_ again, but oh well. | 318 // A bit gratuitous to set delayed_work_time_ again, but oh well. |
248 ScheduleDelayedWork(delayed_work_time_); | 319 ScheduleDelayedWork(delayed_work_time_); |
249 } | 320 } |
250 } | 321 } |
251 | 322 |
252 bool MessagePumpWin::ProcessNextWindowsMessage() { | 323 bool MessagePumpForUI::ProcessNextWindowsMessage() { |
253 // If there are sent messages in the queue then PeekMessage internally | 324 // If there are sent messages in the queue then PeekMessage internally |
254 // dispatches the message and returns false. We return true in this | 325 // dispatches the message and returns false. We return true in this |
255 // case to ensure that the message loop peeks again instead of calling | 326 // case to ensure that the message loop peeks again instead of calling |
256 // MsgWaitForMultipleObjectsEx again. | 327 // MsgWaitForMultipleObjectsEx again. |
257 bool sent_messages_in_queue = false; | 328 bool sent_messages_in_queue = false; |
258 DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE); | 329 DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE); |
259 if (HIWORD(queue_status) & QS_SENDMESSAGE) | 330 if (HIWORD(queue_status) & QS_SENDMESSAGE) |
260 sent_messages_in_queue = true; | 331 sent_messages_in_queue = true; |
261 | 332 |
262 MSG msg; | 333 MSG msg; |
263 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) | 334 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) |
264 return ProcessMessageHelper(msg); | 335 return ProcessMessageHelper(msg); |
265 | 336 |
266 return sent_messages_in_queue; | 337 return sent_messages_in_queue; |
267 } | 338 } |
268 | 339 |
269 bool MessagePumpWin::ProcessMessageHelper(const MSG& msg) { | 340 bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) { |
270 if (WM_QUIT == msg.message) { | 341 if (WM_QUIT == msg.message) { |
271 // Repost the QUIT message so that it will be retrieved by the primary | 342 // Repost the QUIT message so that it will be retrieved by the primary |
272 // GetMessage() loop. | 343 // GetMessage() loop. |
273 state_->should_quit = true; | 344 state_->should_quit = true; |
274 PostQuitMessage(static_cast<int>(msg.wParam)); | 345 PostQuitMessage(static_cast<int>(msg.wParam)); |
275 return false; | 346 return false; |
276 } | 347 } |
277 | 348 |
278 // While running our main message pump, we discard kMsgHaveWork messages. | 349 // While running our main message pump, we discard kMsgHaveWork messages. |
279 if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_) | 350 if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_) |
280 return ProcessPumpReplacementMessage(); | 351 return ProcessPumpReplacementMessage(); |
281 | 352 |
282 WillProcessMessage(msg); | 353 WillProcessMessage(msg); |
283 | 354 |
284 if (state_->dispatcher) { | 355 if (state_->dispatcher) { |
285 if (!state_->dispatcher->Dispatch(msg)) | 356 if (!state_->dispatcher->Dispatch(msg)) |
286 state_->should_quit = true; | 357 state_->should_quit = true; |
287 } else { | 358 } else { |
288 TranslateMessage(&msg); | 359 TranslateMessage(&msg); |
289 DispatchMessage(&msg); | 360 DispatchMessage(&msg); |
290 } | 361 } |
291 | 362 |
292 DidProcessMessage(msg); | 363 DidProcessMessage(msg); |
293 return true; | 364 return true; |
294 } | 365 } |
295 | 366 |
296 bool MessagePumpWin::ProcessPumpReplacementMessage() { | 367 bool MessagePumpForUI::ProcessPumpReplacementMessage() { |
297 // When we encounter a kMsgHaveWork message, this method is called to peek | 368 // When we encounter a kMsgHaveWork message, this method is called to peek |
298 // and process a replacement message, such as a WM_PAINT or WM_TIMER. The | 369 // and process a replacement message, such as a WM_PAINT or WM_TIMER. The |
299 // goal is to make the kMsgHaveWork as non-intrusive as possible, even though | 370 // goal is to make the kMsgHaveWork as non-intrusive as possible, even though |
300 // a continuous stream of such messages are posted. This method carefully | 371 // a continuous stream of such messages are posted. This method carefully |
301 // peeks a message while there is no chance for a kMsgHaveWork to be pending, | 372 // peeks a message while there is no chance for a kMsgHaveWork to be pending, |
302 // then resets the have_work_ flag (allowing a replacement kMsgHaveWork to | 373 // then resets the have_work_ flag (allowing a replacement kMsgHaveWork to |
303 // possibly be posted), and finally dispatches that peeked replacement. Note | 374 // possibly be posted), and finally dispatches that peeked replacement. Note |
304 // that the re-post of kMsgHaveWork may be asynchronous to this thread!! | 375 // that the re-post of kMsgHaveWork may be asynchronous to this thread!! |
305 | 376 |
306 MSG msg; | 377 MSG msg; |
307 bool have_message = (0 != PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)); | 378 bool have_message = (0 != PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)); |
308 DCHECK(!have_message || kMsgHaveWork != msg.message || | 379 DCHECK(!have_message || kMsgHaveWork != msg.message || |
309 msg.hwnd != message_hwnd_); | 380 msg.hwnd != message_hwnd_); |
310 | 381 |
311 // Since we discarded a kMsgHaveWork message, we must update the flag. | 382 // Since we discarded a kMsgHaveWork message, we must update the flag. |
312 InterlockedExchange(&have_work_, 0); | 383 InterlockedExchange(&have_work_, 0); |
313 | 384 |
314 // TODO(darin,jar): There is risk of being lost in a sub-pump within the call | 385 // TODO(darin,jar): There is risk of being lost in a sub-pump within the call |
315 // to ProcessMessageHelper, which could result in no longer getting a | 386 // to ProcessMessageHelper, which could result in no longer getting a |
316 // kMsgHaveWork message until the next out-of-band call to ScheduleWork. | 387 // kMsgHaveWork message until the next out-of-band call to ScheduleWork. |
317 | 388 |
318 return have_message && ProcessMessageHelper(msg); | 389 return have_message && ProcessMessageHelper(msg); |
319 } | 390 } |
320 | 391 |
321 int MessagePumpWin::GetCurrentDelay() const { | |
322 if (delayed_work_time_.is_null()) | |
323 return -1; | |
324 | |
325 // Be careful here. TimeDelta has a precision of microseconds, but we want a | |
326 // value in milliseconds. If there are 5.5ms left, should the delay be 5 or | |
327 // 6? It should be 6 to avoid executing delayed work too early. | |
328 double timeout = ceil((delayed_work_time_ - Time::Now()).InMillisecondsF()); | |
329 | |
330 // If this value is negative, then we need to run delayed work soon. | |
331 int delay = static_cast<int>(timeout); | |
332 if (delay < 0) | |
333 delay = 0; | |
334 | |
335 return delay; | |
336 } | |
337 | |
338 //----------------------------------------------------------------------------- | |
339 // MessagePumpForUI private: | |
340 | |
341 void MessagePumpForUI::DoRunLoop() { | |
342 // IF this was just a simple PeekMessage() loop (servicing all possible work | |
343 // queues), then Windows would try to achieve the following order according | |
344 // to MSDN documentation about PeekMessage with no filter): | |
345 // * Sent messages | |
346 // * Posted messages | |
347 // * Sent messages (again) | |
348 // * WM_PAINT messages | |
349 // * WM_TIMER messages | |
350 // | |
351 // Summary: none of the above classes is starved, and sent messages has twice | |
352 // the chance of being processed (i.e., reduced service time). | |
353 | |
354 for (;;) { | |
355 // If we do any work, we may create more messages etc., and more work may | |
356 // possibly be waiting in another task group. When we (for example) | |
357 // ProcessNextWindowsMessage(), there is a good chance there are still more | |
358 // messages waiting. On the other hand, when any of these methods return | |
359 // having done no work, then it is pretty unlikely that calling them again | |
360 // quickly will find any work to do. Finally, if they all say they had no | |
361 // work, then it is a good time to consider sleeping (waiting) for more | |
362 // work. | |
363 | |
364 bool more_work_is_plausible = ProcessNextWindowsMessage(); | |
365 if (state_->should_quit) | |
366 break; | |
367 | |
368 more_work_is_plausible |= state_->delegate->DoWork(); | |
369 if (state_->should_quit) | |
370 break; | |
371 | |
372 more_work_is_plausible |= | |
373 state_->delegate->DoDelayedWork(&delayed_work_time_); | |
374 // If we did not process any delayed work, then we can assume that our | |
375 // existing WM_TIMER if any will fire when delayed work should run. We | |
376 // don't want to disturb that timer if it is already in flight. However, | |
377 // if we did do all remaining delayed work, then lets kill the WM_TIMER. | |
378 if (more_work_is_plausible && delayed_work_time_.is_null()) | |
379 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); | |
380 if (state_->should_quit) | |
381 break; | |
382 | |
383 if (more_work_is_plausible) | |
384 continue; | |
385 | |
386 more_work_is_plausible = state_->delegate->DoIdleWork(); | |
387 if (state_->should_quit) | |
388 break; | |
389 | |
390 if (more_work_is_plausible) | |
391 continue; | |
392 | |
393 WaitForWork(); // Wait (sleep) until we have work to do again. | |
394 } | |
395 } | |
396 | |
397 void MessagePumpForUI::WaitForWork() { | |
398 // Wait until a message is available, up to the time needed by the timer | |
399 // manager to fire the next set of timers. | |
400 int delay = GetCurrentDelay(); | |
401 if (delay < 0) // Negative value means no timers waiting. | |
402 delay = INFINITE; | |
403 | |
404 DWORD result; | |
405 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, | |
406 MWMO_INPUTAVAILABLE); | |
407 | |
408 if (WAIT_OBJECT_0 == result) { | |
409 // A WM_* message is available. | |
410 // If a parent child relationship exists between windows across threads | |
411 // then their thread inputs are implicitly attached. | |
412 // This causes the MsgWaitForMultipleObjectsEx API to return indicating | |
413 // that messages are ready for processing (specifically mouse messages | |
414 // intended for the child window. Occurs if the child window has capture) | |
415 // The subsequent PeekMessages call fails to return any messages thus | |
416 // causing us to enter a tight loop at times. | |
417 // The WaitMessage call below is a workaround to give the child window | |
418 // sometime to process its input messages. | |
419 MSG msg = {0}; | |
420 DWORD queue_status = GetQueueStatus(QS_MOUSE); | |
421 if (HIWORD(queue_status) & QS_MOUSE && | |
422 !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) { | |
423 WaitMessage(); | |
424 } | |
425 return; | |
426 } | |
427 | |
428 DCHECK_NE(WAIT_FAILED, result) << GetLastError(); | |
429 } | |
430 | |
431 //----------------------------------------------------------------------------- | 392 //----------------------------------------------------------------------------- |
432 // MessagePumpForIO public: | 393 // MessagePumpForIO public: |
433 | 394 |
434 void MessagePumpForIO::WatchObject(HANDLE object, Watcher* watcher) { | 395 MessagePumpForIO::MessagePumpForIO() { |
435 DCHECK(object); | 396 port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1)); |
436 DCHECK_NE(object, INVALID_HANDLE_VALUE); | 397 DCHECK(port_.IsValid()); |
| 398 } |
437 | 399 |
438 std::vector<HANDLE>::iterator it = | 400 void MessagePumpForIO::ScheduleWork() { |
439 find(objects_.begin(), objects_.end(), object); | 401 if (InterlockedExchange(&have_work_, 1)) |
440 if (watcher) { | 402 return; // Someone else continued the pumping. |
441 if (it == objects_.end()) { | 403 |
442 static size_t warning_multiple = 1; | 404 // Make sure the MessagePump does some work for us. |
443 if (objects_.size() >= warning_multiple * MAXIMUM_WAIT_OBJECTS / 2) { | 405 BOOL ret = PostQueuedCompletionStatus(port_, 0, |
444 LOG(INFO) << "More than " << warning_multiple * MAXIMUM_WAIT_OBJECTS / 2 | 406 reinterpret_cast<ULONG_PTR>(this), |
445 << " objects being watched"; | 407 reinterpret_cast<OVERLAPPED*>(this)); |
446 // This DCHECK() is an artificial limitation, meant to warn us if we | 408 DCHECK(ret); |
447 // start creating too many objects. It can safely be raised to a higher | 409 } |
448 // level, and the program is designed to handle much larger values. | 410 |
449 // Before raising this limit, make sure that there is a very good reason | 411 void MessagePumpForIO::ScheduleDelayedWork(const Time& delayed_work_time) { |
450 // (in your debug testing) to be watching this many objects. | 412 // We know that we can't be blocked right now since this method can only be |
451 DCHECK(2 <= warning_multiple); | 413 // called on the same thread as Run, so we only need to update our record of |
452 ++warning_multiple; | 414 // how long to sleep when we do sleep. |
453 } | 415 delayed_work_time_ = delayed_work_time; |
454 objects_.push_back(object); | |
455 watchers_.push_back(watcher); | |
456 } else { | |
457 watchers_[it - objects_.begin()] = watcher; | |
458 } | |
459 } else if (it != objects_.end()) { | |
460 std::vector<HANDLE>::difference_type index = it - objects_.begin(); | |
461 objects_.erase(it); | |
462 watchers_.erase(watchers_.begin() + index); | |
463 } | |
464 } | 416 } |
465 | 417 |
466 void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle, | 418 void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle, |
467 IOHandler* handler) { | 419 IOHandler* handler) { |
468 #if 0 | |
469 // TODO(rvargas): This is just to give an idea of what this code will look | |
470 // like when we actually move to completion ports. Of course, we cannot | |
471 // do this without calling GetQueuedCompletionStatus(). | |
472 ULONG_PTR key = reinterpret_cast<ULONG_PTR>(handler); | 420 ULONG_PTR key = reinterpret_cast<ULONG_PTR>(handler); |
473 HANDLE port = CreateIoCompletionPort(file_handle, port_, key, 1); | 421 HANDLE port = CreateIoCompletionPort(file_handle, port_, key, 1); |
474 if (!port_.IsValid()) | 422 DCHECK(port == port_.Get()); |
475 port_.Set(port); | |
476 #endif | |
477 } | |
478 | |
479 void MessagePumpForIO::RegisterIOContext(OVERLAPPED* context, | |
480 IOHandler* handler) { | |
481 DCHECK(context->hEvent); | |
482 if (handler) { | |
483 HandlerData* watcher = new HandlerData(context, handler); | |
484 WatchObject(context->hEvent, watcher); | |
485 } else { | |
486 std::vector<HANDLE>::iterator it = | |
487 find(objects_.begin(), objects_.end(), context->hEvent); | |
488 | |
489 if (it == objects_.end()) { | |
490 NOTREACHED(); | |
491 return; | |
492 } | |
493 | |
494 std::vector<HANDLE>::difference_type index = it - objects_.begin(); | |
495 objects_.erase(it); | |
496 delete watchers_[index]; | |
497 watchers_.erase(watchers_.begin() + index); | |
498 } | |
499 } | 423 } |
500 | 424 |
501 //----------------------------------------------------------------------------- | 425 //----------------------------------------------------------------------------- |
502 // MessagePumpForIO private: | 426 // MessagePumpForIO private: |
503 | 427 |
504 void MessagePumpForIO::DoRunLoop() { | 428 void MessagePumpForIO::DoRunLoop() { |
505 // IF this was just a simple PeekMessage() loop (servicing all possible work | |
506 // queues), then Windows would try to achieve the following order according | |
507 // to MSDN documentation about PeekMessage with no filter): | |
508 // * Sent messages | |
509 // * Posted messages | |
510 // * Sent messages (again) | |
511 // * WM_PAINT messages | |
512 // * WM_TIMER messages | |
513 // | |
514 // Summary: none of the above classes is starved, and sent messages has twice | |
515 // the chance of being processed (i.e., reduced service time). | |
516 | |
517 for (;;) { | 429 for (;;) { |
518 // If we do any work, we may create more messages etc., and more work may | 430 // If we do any work, we may create more messages etc., and more work may |
519 // possibly be waiting in another task group. When we (for example) | 431 // possibly be waiting in another task group. When we (for example) |
520 // ProcessNextWindowsMessage(), there is a good chance there are still more | 432 // WaitForIOCompletion(), there is a good chance there are still more |
521 // messages waiting (same thing for ProcessNextObject(), which responds to | 433 // messages waiting. On the other hand, when any of these methods return |
522 // only one signaled object; etc.). On the other hand, when any of these | 434 // having done no work, then it is pretty unlikely that calling them |
523 // methods return having done no work, then it is pretty unlikely that | 435 // again quickly will find any work to do. Finally, if they all say they |
524 // calling them again quickly will find any work to do. Finally, if they | 436 // had no work, then it is a good time to consider sleeping (waiting) for |
525 // all say they had no work, then it is a good time to consider sleeping | 437 // more work. |
526 // (waiting) for more work. | |
527 | 438 |
528 bool more_work_is_plausible = ProcessNextWindowsMessage(); | 439 bool more_work_is_plausible = state_->delegate->DoWork(); |
529 if (state_->should_quit) | 440 if (state_->should_quit) |
530 break; | 441 break; |
531 | 442 |
532 more_work_is_plausible |= state_->delegate->DoWork(); | 443 more_work_is_plausible |= WaitForIOCompletion(0, NULL); |
533 if (state_->should_quit) | |
534 break; | |
535 | |
536 more_work_is_plausible |= ProcessNextObject(); | |
537 if (state_->should_quit) | 444 if (state_->should_quit) |
538 break; | 445 break; |
539 | 446 |
540 more_work_is_plausible |= | 447 more_work_is_plausible |= |
541 state_->delegate->DoDelayedWork(&delayed_work_time_); | 448 state_->delegate->DoDelayedWork(&delayed_work_time_); |
542 // If we did not process any delayed work, then we can assume that our | |
543 // existing WM_TIMER if any will fire when delayed work should run. We | |
544 // don't want to disturb that timer if it is already in flight. However, | |
545 // if we did do all remaining delayed work, then lets kill the WM_TIMER. | |
546 if (more_work_is_plausible && delayed_work_time_.is_null()) | |
547 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); | |
548 if (state_->should_quit) | 449 if (state_->should_quit) |
549 break; | 450 break; |
550 | 451 |
551 if (more_work_is_plausible) | 452 if (more_work_is_plausible) |
552 continue; | 453 continue; |
553 | 454 |
554 more_work_is_plausible = state_->delegate->DoIdleWork(); | 455 more_work_is_plausible = state_->delegate->DoIdleWork(); |
555 if (state_->should_quit) | 456 if (state_->should_quit) |
556 break; | 457 break; |
557 | 458 |
558 if (more_work_is_plausible) | 459 if (more_work_is_plausible) |
559 continue; | 460 continue; |
560 | 461 |
561 // We service APCs in WaitForWork, without returning. | |
562 WaitForWork(); // Wait (sleep) until we have work to do again. | 462 WaitForWork(); // Wait (sleep) until we have work to do again. |
563 } | 463 } |
564 } | 464 } |
565 | 465 |
566 // If we handle more than the OS limit on the number of objects that can be | 466 // Wait until IO completes, up to the time needed by the timer manager to fire |
567 // waited for, we'll need to poll (sequencing through subsets of the objects | 467 // the next set of timers. |
568 // that can be passed in a single OS wait call). The following is the polling | 468 void MessagePumpForIO::WaitForWork() { |
569 // interval used in that (unusual) case. (I don't have a lot of justifcation | 469 // We do not support nested IO message loops. This is to avoid messy |
570 // for the specific value, but it needed to be short enough that it would not | 470 // recursion problems. |
571 // add a lot of latency, and long enough that we wouldn't thrash the CPU for no | 471 DCHECK(state_->run_depth == 1) << "Cannot nest an IO message loop!"; |
572 // reason... especially considering the silly user probably has a million tabs | |
573 // open, etc.) | |
574 static const int kMultipleWaitPollingInterval = 20; | |
575 | 472 |
576 void MessagePumpForIO::WaitForWork() { | 473 int timeout = GetCurrentDelay(); |
577 // Wait until either an object is signaled or a message is available. Handle | 474 if (timeout < 0) // Negative value means no timers waiting. |
578 // (without returning) any APCs (only the IO thread currently has APCs.) | 475 timeout = INFINITE; |
579 | 476 |
580 // We do not support nested message loops when we have watched objects. This | 477 WaitForIOCompletion(timeout, NULL); |
581 // is to avoid messy recursion problems. | |
582 DCHECK(objects_.empty() || state_->run_depth == 1) << | |
583 "Cannot nest a message loop when there are watched objects!"; | |
584 | |
585 int wait_flags = MWMO_ALERTABLE | MWMO_INPUTAVAILABLE; | |
586 | |
587 bool use_polling = false; // Poll if too many objects for one OS Wait call. | |
588 for (;;) { | |
589 // Do initialization here, in case APC modifies object list. | |
590 size_t total_objs = objects_.size(); | |
591 | |
592 int delay; | |
593 size_t polling_index = 0; // The first unprocessed object index. | |
594 do { | |
595 size_t objs_len = | |
596 (polling_index < total_objs) ? total_objs - polling_index : 0; | |
597 if (objs_len >= MAXIMUM_WAIT_OBJECTS) { | |
598 objs_len = MAXIMUM_WAIT_OBJECTS - 1; | |
599 use_polling = true; | |
600 } | |
601 HANDLE* objs = objs_len ? polling_index + &objects_.front() : NULL; | |
602 | |
603 // Only wait up to the time needed by the timer manager to fire the next | |
604 // set of timers. | |
605 delay = GetCurrentDelay(); | |
606 if (use_polling && delay > kMultipleWaitPollingInterval) | |
607 delay = kMultipleWaitPollingInterval; | |
608 if (delay < 0) // Negative value means no timers waiting. | |
609 delay = INFINITE; | |
610 | |
611 DWORD result; | |
612 result = MsgWaitForMultipleObjectsEx(static_cast<DWORD>(objs_len), objs, | |
613 delay, QS_ALLINPUT, wait_flags); | |
614 | |
615 if (WAIT_IO_COMPLETION == result) { | |
616 // We'll loop here when we service an APC. At it currently stands, | |
617 // *ONLY* the IO thread uses *any* APCs, so this should have no impact | |
618 // on the UI thread. | |
619 break; // Break to outer loop, and waitforwork() again. | |
620 } | |
621 | |
622 // Use unsigned type to simplify range detection; | |
623 size_t signaled_index = result - WAIT_OBJECT_0; | |
624 if (signaled_index < objs_len) { | |
625 SignalWatcher(polling_index + signaled_index); | |
626 return; // We serviced a signaled object. | |
627 } | |
628 | |
629 if (objs_len == signaled_index) | |
630 return; // A WM_* message is available. | |
631 | |
632 DCHECK_NE(WAIT_FAILED, result) << GetLastError(); | |
633 | |
634 DCHECK(!objs || result == WAIT_TIMEOUT); | |
635 if (!use_polling) | |
636 return; | |
637 polling_index += objs_len; | |
638 } while (polling_index < total_objs); | |
639 // For compatibility, we didn't return sooner. This made us do *some* wait | |
640 // call(s) before returning. This will probably change in next rev. | |
641 if (!delay || !GetCurrentDelay()) | |
642 return; // No work done, but timer is ready to fire. | |
643 } | |
644 } | 478 } |
645 | 479 |
646 bool MessagePumpForIO::ProcessNextObject() { | 480 bool MessagePumpForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) { |
647 size_t total_objs = objects_.size(); | 481 IOItem item; |
648 if (!total_objs) { | 482 if (completed_io_.empty() || !MatchCompletedIOItem(filter, &item)) { |
649 return false; | 483 // We have to ask the system for another IO completion. |
| 484 if (!GetIOItem(timeout, &item)) |
| 485 return false; |
| 486 |
| 487 if (ProcessInternalIOItem(item)) |
| 488 return true; |
650 } | 489 } |
651 | 490 |
652 size_t polling_index = 0; // The first unprocessed object index. | 491 if (item.context->handler) { |
653 do { | 492 if (filter && item.handler != filter) { |
654 DCHECK(polling_index < total_objs); | 493 // Save this item for later |
655 size_t objs_len = total_objs - polling_index; | 494 completed_io_.push_back(item); |
656 if (objs_len >= kMaxWaitObjects) | 495 } else { |
657 objs_len = kMaxWaitObjects - 1; | 496 DCHECK(item.context->handler == item.handler); |
658 HANDLE* objs = polling_index + &objects_.front(); | 497 item.handler->OnIOCompleted(item.context, item.bytes_transfered, |
659 | 498 item.error); |
660 // Identify 1 pending object, or allow an IO APC to be completed. | |
661 DWORD result = WaitForMultipleObjectsEx(static_cast<DWORD>(objs_len), objs, | |
662 FALSE, // 1 signal is sufficient. | |
663 0, // Wait 0ms. | |
664 false); // Not alertable (no APC). | |
665 | |
666 // Use unsigned type to simplify range detection; | |
667 size_t signaled_index = result - WAIT_OBJECT_0; | |
668 if (signaled_index < objs_len) { | |
669 SignalWatcher(polling_index + signaled_index); | |
670 return true; // We serviced a signaled object. | |
671 } | 499 } |
672 | 500 } else { |
673 // If an handle is invalid, it will be WAIT_FAILED. | 501 // The handler must be gone by now, just cleanup the mess. |
674 DCHECK_EQ(WAIT_TIMEOUT, result) << GetLastError(); | 502 delete item.context; |
675 polling_index += objs_len; | 503 } |
676 } while (polling_index < total_objs); | |
677 return false; // We serviced nothing. | |
678 } | |
679 | |
680 bool MessagePumpForIO::SignalWatcher(size_t object_index) { | |
681 // Signal the watcher corresponding to the given index. | |
682 | |
683 DCHECK(objects_.size() > object_index); | |
684 | |
685 // On reception of OnObjectSignaled() to a Watcher object, it may call | |
686 // WatchObject(). watchers_ and objects_ will be modified. This is expected, | |
687 // so don't be afraid if, while tracing a OnObjectSignaled() function, the | |
688 // corresponding watchers_[result] is non-existant. | |
689 watchers_[object_index]->OnObjectSignaled(objects_[object_index]); | |
690 | |
691 // Signaled objects tend to be removed from the watch list, and then added | |
692 // back (appended). As a result, they move to the end of the objects_ array, | |
693 // and this should make their service "fair" (no HANDLEs should be starved). | |
694 | |
695 return true; | 504 return true; |
696 } | 505 } |
697 | 506 |
| 507 // Asks the OS for another IO completion result. |
| 508 bool MessagePumpForIO::GetIOItem(DWORD timeout, IOItem* item) { |
| 509 memset(item, 0, sizeof(*item)); |
| 510 ULONG_PTR key = NULL; |
| 511 OVERLAPPED* overlapped = NULL; |
| 512 if (!GetQueuedCompletionStatus(port_.Get(), &item->bytes_transfered, &key, |
| 513 &overlapped, timeout)) { |
| 514 if (!overlapped) |
| 515 return false; // Nothing in the queue. |
| 516 item->error = GetLastError(); |
| 517 item->bytes_transfered = 0; |
| 518 } |
| 519 |
| 520 item->handler = reinterpret_cast<IOHandler*>(key); |
| 521 item->context = reinterpret_cast<IOContext*>(overlapped); |
| 522 return true; |
| 523 } |
| 524 |
| 525 bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) { |
| 526 if (this == reinterpret_cast<MessagePumpForIO*>(item.context) && |
| 527 this == reinterpret_cast<MessagePumpForIO*>(item.handler)) { |
| 528 // This is our internal completion. |
| 529 DCHECK(!item.bytes_transfered); |
| 530 InterlockedExchange(&have_work_, 0); |
| 531 return true; |
| 532 } |
| 533 return false; |
| 534 } |
| 535 |
| 536 // Returns a completion item that was previously received. |
| 537 bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) { |
| 538 DCHECK(!completed_io_.empty()); |
| 539 for (std::list<IOItem>::iterator it = completed_io_.begin(); |
| 540 it != completed_io_.end(); ++it) { |
| 541 if (!filter || it->handler == filter) { |
| 542 *item = *it; |
| 543 completed_io_.erase(it); |
| 544 return true; |
| 545 } |
| 546 } |
| 547 return false; |
| 548 } |
| 549 |
698 } // namespace base | 550 } // namespace base |
OLD | NEW |