|
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
|
2 // Use of this source code is governed by a BSD-style license that can be |
|
3 // found in the LICENSE file. |
|
4 |
|
5 #include "base/message_pump_win.h" |
|
6 |
|
7 #include <math.h> |
|
8 |
|
9 #include "base/message_loop.h" |
|
10 #include "base/histogram.h" |
|
11 #include "base/win_util.h" |
|
12 |
|
13 using base::Time; |
|
14 |
|
15 namespace base { |
|
16 |
|
17 static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow"; |
|
18 |
|
19 // Message sent to get an additional time slice for pumping (processing) another |
|
20 // task (a series of such messages creates a continuous task pump). |
|
21 static const int kMsgHaveWork = WM_USER + 1; |
|
22 |
|
23 //----------------------------------------------------------------------------- |
|
24 // MessagePumpWin public: |
|
25 |
|
26 void MessagePumpWin::AddObserver(Observer* observer) { |
|
27 observers_.AddObserver(observer); |
|
28 } |
|
29 |
|
30 void MessagePumpWin::RemoveObserver(Observer* observer) { |
|
31 observers_.RemoveObserver(observer); |
|
32 } |
|
33 |
|
34 void MessagePumpWin::WillProcessMessage(const MSG& msg) { |
|
35 FOR_EACH_OBSERVER(Observer, observers_, WillProcessMessage(msg)); |
|
36 } |
|
37 |
|
38 void MessagePumpWin::DidProcessMessage(const MSG& msg) { |
|
39 FOR_EACH_OBSERVER(Observer, observers_, DidProcessMessage(msg)); |
|
40 } |
|
41 |
|
42 void MessagePumpWin::RunWithDispatcher( |
|
43 Delegate* delegate, Dispatcher* dispatcher) { |
|
44 RunState s; |
|
45 s.delegate = delegate; |
|
46 s.dispatcher = dispatcher; |
|
47 s.should_quit = false; |
|
48 s.run_depth = state_ ? state_->run_depth + 1 : 1; |
|
49 |
|
50 RunState* previous_state = state_; |
|
51 state_ = &s; |
|
52 |
|
53 DoRunLoop(); |
|
54 |
|
55 state_ = previous_state; |
|
56 } |
|
57 |
|
58 void MessagePumpWin::Quit() { |
|
59 DCHECK(state_); |
|
60 state_->should_quit = true; |
|
61 } |
|
62 |
|
63 //----------------------------------------------------------------------------- |
|
64 // MessagePumpWin protected: |
|
65 |
|
66 int MessagePumpWin::GetCurrentDelay() const { |
|
67 if (delayed_work_time_.is_null()) |
|
68 return -1; |
|
69 |
|
70 // Be careful here. TimeDelta has a precision of microseconds, but we want a |
|
71 // value in milliseconds. If there are 5.5ms left, should the delay be 5 or |
|
72 // 6? It should be 6 to avoid executing delayed work too early. |
|
73 double timeout = |
|
74 ceil((delayed_work_time_ - TimeTicks::Now()).InMillisecondsF()); |
|
75 |
|
76 // If this value is negative, then we need to run delayed work soon. |
|
77 int delay = static_cast<int>(timeout); |
|
78 if (delay < 0) |
|
79 delay = 0; |
|
80 |
|
81 return delay; |
|
82 } |
|
83 |
|
84 //----------------------------------------------------------------------------- |
|
85 // MessagePumpForUI public: |
|
86 |
|
87 MessagePumpForUI::MessagePumpForUI() { |
|
88 InitMessageWnd(); |
|
89 } |
|
90 |
|
91 MessagePumpForUI::~MessagePumpForUI() { |
|
92 DestroyWindow(message_hwnd_); |
|
93 UnregisterClass(kWndClass, GetModuleHandle(NULL)); |
|
94 } |
|
95 |
|
96 void MessagePumpForUI::ScheduleWork() { |
|
97 if (InterlockedExchange(&have_work_, 1)) |
|
98 return; // Someone else continued the pumping. |
|
99 |
|
100 // Make sure the MessagePump does some work for us. |
|
101 PostMessage(message_hwnd_, kMsgHaveWork, reinterpret_cast<WPARAM>(this), 0); |
|
102 |
|
103 // In order to wake up any cross-process COM calls which may currently be |
|
104 // pending on the main thread, we also have to post a UI message. |
|
105 PostMessage(message_hwnd_, WM_NULL, 0, 0); |
|
106 } |
|
107 |
|
108 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { |
|
109 // |
|
110 // We would *like* to provide high resolution timers. Windows timers using |
|
111 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup |
|
112 // mechanism because the application can enter modal windows loops where it |
|
113 // is not running our MessageLoop; the only way to have our timers fire in |
|
114 // these cases is to post messages there. |
|
115 // |
|
116 // To provide sub-10ms timers, we process timers directly from our run loop. |
|
117 // For the common case, timers will be processed there as the run loop does |
|
118 // its normal work. However, we *also* set the system timer so that WM_TIMER |
|
119 // events fire. This mops up the case of timers not being able to work in |
|
120 // modal message loops. It is possible for the SetTimer to pop and have no |
|
121 // pending timers, because they could have already been processed by the |
|
122 // run loop itself. |
|
123 // |
|
124 // We use a single SetTimer corresponding to the timer that will expire |
|
125 // soonest. As new timers are created and destroyed, we update SetTimer. |
|
126 // Getting a spurrious SetTimer event firing is benign, as we'll just be |
|
127 // processing an empty timer queue. |
|
128 // |
|
129 delayed_work_time_ = delayed_work_time; |
|
130 |
|
131 int delay_msec = GetCurrentDelay(); |
|
132 DCHECK(delay_msec >= 0); |
|
133 if (delay_msec < USER_TIMER_MINIMUM) |
|
134 delay_msec = USER_TIMER_MINIMUM; |
|
135 |
|
136 // Create a WM_TIMER event that will wake us up to check for any pending |
|
137 // timers (in case we are running within a nested, external sub-pump). |
|
138 SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), delay_msec, NULL); |
|
139 } |
|
140 |
|
141 void MessagePumpForUI::PumpOutPendingPaintMessages() { |
|
142 // If we are being called outside of the context of Run, then don't try to do |
|
143 // any work. |
|
144 if (!state_) |
|
145 return; |
|
146 |
|
147 // Create a mini-message-pump to force immediate processing of only Windows |
|
148 // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking |
|
149 // to get the job done. Actual common max is 4 peeks, but we'll be a little |
|
150 // safe here. |
|
151 const int kMaxPeekCount = 20; |
|
152 bool win2k = win_util::GetWinVersion() <= win_util::WINVERSION_2000; |
|
153 int peek_count; |
|
154 for (peek_count = 0; peek_count < kMaxPeekCount; ++peek_count) { |
|
155 MSG msg; |
|
156 if (win2k) { |
|
157 if (!PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE)) |
|
158 break; |
|
159 } else { |
|
160 if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_PAINT)) |
|
161 break; |
|
162 } |
|
163 ProcessMessageHelper(msg); |
|
164 if (state_->should_quit) // Handle WM_QUIT. |
|
165 break; |
|
166 } |
|
167 // Histogram what was really being used, to help to adjust kMaxPeekCount. |
|
168 DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count); |
|
169 } |
|
170 |
|
171 //----------------------------------------------------------------------------- |
|
172 // MessagePumpForUI private: |
|
173 |
|
174 // static |
|
175 LRESULT CALLBACK MessagePumpForUI::WndProcThunk( |
|
176 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { |
|
177 switch (message) { |
|
178 case kMsgHaveWork: |
|
179 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage(); |
|
180 break; |
|
181 case WM_TIMER: |
|
182 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage(); |
|
183 break; |
|
184 } |
|
185 return DefWindowProc(hwnd, message, wparam, lparam); |
|
186 } |
|
187 |
|
188 void MessagePumpForUI::DoRunLoop() { |
|
189 // IF this was just a simple PeekMessage() loop (servicing all possible work |
|
190 // queues), then Windows would try to achieve the following order according |
|
191 // to MSDN documentation about PeekMessage with no filter): |
|
192 // * Sent messages |
|
193 // * Posted messages |
|
194 // * Sent messages (again) |
|
195 // * WM_PAINT messages |
|
196 // * WM_TIMER messages |
|
197 // |
|
198 // Summary: none of the above classes is starved, and sent messages has twice |
|
199 // the chance of being processed (i.e., reduced service time). |
|
200 |
|
201 for (;;) { |
|
202 // If we do any work, we may create more messages etc., and more work may |
|
203 // possibly be waiting in another task group. When we (for example) |
|
204 // ProcessNextWindowsMessage(), there is a good chance there are still more |
|
205 // messages waiting. On the other hand, when any of these methods return |
|
206 // having done no work, then it is pretty unlikely that calling them again |
|
207 // quickly will find any work to do. Finally, if they all say they had no |
|
208 // work, then it is a good time to consider sleeping (waiting) for more |
|
209 // work. |
|
210 |
|
211 bool more_work_is_plausible = ProcessNextWindowsMessage(); |
|
212 if (state_->should_quit) |
|
213 break; |
|
214 |
|
215 more_work_is_plausible |= state_->delegate->DoWork(); |
|
216 if (state_->should_quit) |
|
217 break; |
|
218 |
|
219 more_work_is_plausible |= |
|
220 state_->delegate->DoDelayedWork(&delayed_work_time_); |
|
221 // If we did not process any delayed work, then we can assume that our |
|
222 // existing WM_TIMER if any will fire when delayed work should run. We |
|
223 // don't want to disturb that timer if it is already in flight. However, |
|
224 // if we did do all remaining delayed work, then lets kill the WM_TIMER. |
|
225 if (more_work_is_plausible && delayed_work_time_.is_null()) |
|
226 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); |
|
227 if (state_->should_quit) |
|
228 break; |
|
229 |
|
230 if (more_work_is_plausible) |
|
231 continue; |
|
232 |
|
233 more_work_is_plausible = state_->delegate->DoIdleWork(); |
|
234 if (state_->should_quit) |
|
235 break; |
|
236 |
|
237 if (more_work_is_plausible) |
|
238 continue; |
|
239 |
|
240 WaitForWork(); // Wait (sleep) until we have work to do again. |
|
241 } |
|
242 } |
|
243 |
|
244 void MessagePumpForUI::InitMessageWnd() { |
|
245 HINSTANCE hinst = GetModuleHandle(NULL); |
|
246 |
|
247 WNDCLASSEX wc = {0}; |
|
248 wc.cbSize = sizeof(wc); |
|
249 wc.lpfnWndProc = WndProcThunk; |
|
250 wc.hInstance = hinst; |
|
251 wc.lpszClassName = kWndClass; |
|
252 RegisterClassEx(&wc); |
|
253 |
|
254 message_hwnd_ = |
|
255 CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, 0); |
|
256 DCHECK(message_hwnd_); |
|
257 } |
|
258 |
|
259 void MessagePumpForUI::WaitForWork() { |
|
260 // Wait until a message is available, up to the time needed by the timer |
|
261 // manager to fire the next set of timers. |
|
262 int delay = GetCurrentDelay(); |
|
263 if (delay < 0) // Negative value means no timers waiting. |
|
264 delay = INFINITE; |
|
265 |
|
266 DWORD result; |
|
267 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, |
|
268 MWMO_INPUTAVAILABLE); |
|
269 |
|
270 if (WAIT_OBJECT_0 == result) { |
|
271 // A WM_* message is available. |
|
272 // If a parent child relationship exists between windows across threads |
|
273 // then their thread inputs are implicitly attached. |
|
274 // This causes the MsgWaitForMultipleObjectsEx API to return indicating |
|
275 // that messages are ready for processing (specifically mouse messages |
|
276 // intended for the child window. Occurs if the child window has capture) |
|
277 // The subsequent PeekMessages call fails to return any messages thus |
|
278 // causing us to enter a tight loop at times. |
|
279 // The WaitMessage call below is a workaround to give the child window |
|
280 // sometime to process its input messages. |
|
281 MSG msg = {0}; |
|
282 DWORD queue_status = GetQueueStatus(QS_MOUSE); |
|
283 if (HIWORD(queue_status) & QS_MOUSE && |
|
284 !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) { |
|
285 WaitMessage(); |
|
286 } |
|
287 return; |
|
288 } |
|
289 |
|
290 DCHECK_NE(WAIT_FAILED, result) << GetLastError(); |
|
291 } |
|
292 |
|
293 void MessagePumpForUI::HandleWorkMessage() { |
|
294 // If we are being called outside of the context of Run, then don't try to do |
|
295 // any work. This could correspond to a MessageBox call or something of that |
|
296 // sort. |
|
297 if (!state_) { |
|
298 // Since we handled a kMsgHaveWork message, we must still update this flag. |
|
299 InterlockedExchange(&have_work_, 0); |
|
300 return; |
|
301 } |
|
302 |
|
303 // Let whatever would have run had we not been putting messages in the queue |
|
304 // run now. This is an attempt to make our dummy message not starve other |
|
305 // messages that may be in the Windows message queue. |
|
306 ProcessPumpReplacementMessage(); |
|
307 |
|
308 // Now give the delegate a chance to do some work. He'll let us know if he |
|
309 // needs to do more work. |
|
310 if (state_->delegate->DoWork()) |
|
311 ScheduleWork(); |
|
312 } |
|
313 |
|
314 void MessagePumpForUI::HandleTimerMessage() { |
|
315 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); |
|
316 |
|
317 // If we are being called outside of the context of Run, then don't do |
|
318 // anything. This could correspond to a MessageBox call or something of |
|
319 // that sort. |
|
320 if (!state_) |
|
321 return; |
|
322 |
|
323 state_->delegate->DoDelayedWork(&delayed_work_time_); |
|
324 if (!delayed_work_time_.is_null()) { |
|
325 // A bit gratuitous to set delayed_work_time_ again, but oh well. |
|
326 ScheduleDelayedWork(delayed_work_time_); |
|
327 } |
|
328 } |
|
329 |
|
330 bool MessagePumpForUI::ProcessNextWindowsMessage() { |
|
331 // If there are sent messages in the queue then PeekMessage internally |
|
332 // dispatches the message and returns false. We return true in this |
|
333 // case to ensure that the message loop peeks again instead of calling |
|
334 // MsgWaitForMultipleObjectsEx again. |
|
335 bool sent_messages_in_queue = false; |
|
336 DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE); |
|
337 if (HIWORD(queue_status) & QS_SENDMESSAGE) |
|
338 sent_messages_in_queue = true; |
|
339 |
|
340 MSG msg; |
|
341 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) |
|
342 return ProcessMessageHelper(msg); |
|
343 |
|
344 return sent_messages_in_queue; |
|
345 } |
|
346 |
|
347 bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) { |
|
348 if (WM_QUIT == msg.message) { |
|
349 // Repost the QUIT message so that it will be retrieved by the primary |
|
350 // GetMessage() loop. |
|
351 state_->should_quit = true; |
|
352 PostQuitMessage(static_cast<int>(msg.wParam)); |
|
353 return false; |
|
354 } |
|
355 |
|
356 // While running our main message pump, we discard kMsgHaveWork messages. |
|
357 if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_) |
|
358 return ProcessPumpReplacementMessage(); |
|
359 |
|
360 WillProcessMessage(msg); |
|
361 |
|
362 if (state_->dispatcher) { |
|
363 if (!state_->dispatcher->Dispatch(msg)) |
|
364 state_->should_quit = true; |
|
365 } else { |
|
366 TranslateMessage(&msg); |
|
367 DispatchMessage(&msg); |
|
368 } |
|
369 |
|
370 DidProcessMessage(msg); |
|
371 return true; |
|
372 } |
|
373 |
|
374 bool MessagePumpForUI::ProcessPumpReplacementMessage() { |
|
375 // When we encounter a kMsgHaveWork message, this method is called to peek |
|
376 // and process a replacement message, such as a WM_PAINT or WM_TIMER. The |
|
377 // goal is to make the kMsgHaveWork as non-intrusive as possible, even though |
|
378 // a continuous stream of such messages are posted. This method carefully |
|
379 // peeks a message while there is no chance for a kMsgHaveWork to be pending, |
|
380 // then resets the have_work_ flag (allowing a replacement kMsgHaveWork to |
|
381 // possibly be posted), and finally dispatches that peeked replacement. Note |
|
382 // that the re-post of kMsgHaveWork may be asynchronous to this thread!! |
|
383 |
|
384 MSG msg; |
|
385 bool have_message = false; |
|
386 if (MessageLoop::current()->os_modal_loop()) { |
|
387 // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above. |
|
388 have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) || |
|
389 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); |
|
390 } else { |
|
391 have_message = (0 != PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)); |
|
392 |
|
393 if (have_message && msg.message == WM_NULL) |
|
394 have_message = (0 != PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)); |
|
395 } |
|
396 |
|
397 DCHECK(!have_message || kMsgHaveWork != msg.message || |
|
398 msg.hwnd != message_hwnd_); |
|
399 |
|
400 // Since we discarded a kMsgHaveWork message, we must update the flag. |
|
401 int old_have_work = InterlockedExchange(&have_work_, 0); |
|
402 DCHECK(old_have_work); |
|
403 |
|
404 // We don't need a special time slice if we didn't have_message to process. |
|
405 if (!have_message) |
|
406 return false; |
|
407 |
|
408 // Guarantee we'll get another time slice in the case where we go into native |
|
409 // windows code. This ScheduleWork() may hurt performance a tiny bit when |
|
410 // tasks appear very infrequently, but when the event queue is busy, the |
|
411 // kMsgHaveWork events get (percentage wise) rarer and rarer. |
|
412 ScheduleWork(); |
|
413 return ProcessMessageHelper(msg); |
|
414 } |
|
415 |
|
416 //----------------------------------------------------------------------------- |
|
417 // MessagePumpForIO public: |
|
418 |
|
419 MessagePumpForIO::MessagePumpForIO() { |
|
420 port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1)); |
|
421 DCHECK(port_.IsValid()); |
|
422 } |
|
423 |
|
424 void MessagePumpForIO::ScheduleWork() { |
|
425 if (InterlockedExchange(&have_work_, 1)) |
|
426 return; // Someone else continued the pumping. |
|
427 |
|
428 // Make sure the MessagePump does some work for us. |
|
429 BOOL ret = PostQueuedCompletionStatus(port_, 0, |
|
430 reinterpret_cast<ULONG_PTR>(this), |
|
431 reinterpret_cast<OVERLAPPED*>(this)); |
|
432 DCHECK(ret); |
|
433 } |
|
434 |
|
435 void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { |
|
436 // We know that we can't be blocked right now since this method can only be |
|
437 // called on the same thread as Run, so we only need to update our record of |
|
438 // how long to sleep when we do sleep. |
|
439 delayed_work_time_ = delayed_work_time; |
|
440 } |
|
441 |
|
442 void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle, |
|
443 IOHandler* handler) { |
|
444 ULONG_PTR key = reinterpret_cast<ULONG_PTR>(handler); |
|
445 HANDLE port = CreateIoCompletionPort(file_handle, port_, key, 1); |
|
446 DCHECK(port == port_.Get()); |
|
447 } |
|
448 |
|
449 //----------------------------------------------------------------------------- |
|
450 // MessagePumpForIO private: |
|
451 |
|
452 void MessagePumpForIO::DoRunLoop() { |
|
453 for (;;) { |
|
454 // If we do any work, we may create more messages etc., and more work may |
|
455 // possibly be waiting in another task group. When we (for example) |
|
456 // WaitForIOCompletion(), there is a good chance there are still more |
|
457 // messages waiting. On the other hand, when any of these methods return |
|
458 // having done no work, then it is pretty unlikely that calling them |
|
459 // again quickly will find any work to do. Finally, if they all say they |
|
460 // had no work, then it is a good time to consider sleeping (waiting) for |
|
461 // more work. |
|
462 |
|
463 bool more_work_is_plausible = state_->delegate->DoWork(); |
|
464 if (state_->should_quit) |
|
465 break; |
|
466 |
|
467 more_work_is_plausible |= WaitForIOCompletion(0, NULL); |
|
468 if (state_->should_quit) |
|
469 break; |
|
470 |
|
471 more_work_is_plausible |= |
|
472 state_->delegate->DoDelayedWork(&delayed_work_time_); |
|
473 if (state_->should_quit) |
|
474 break; |
|
475 |
|
476 if (more_work_is_plausible) |
|
477 continue; |
|
478 |
|
479 more_work_is_plausible = state_->delegate->DoIdleWork(); |
|
480 if (state_->should_quit) |
|
481 break; |
|
482 |
|
483 if (more_work_is_plausible) |
|
484 continue; |
|
485 |
|
486 WaitForWork(); // Wait (sleep) until we have work to do again. |
|
487 } |
|
488 } |
|
489 |
|
490 // Wait until IO completes, up to the time needed by the timer manager to fire |
|
491 // the next set of timers. |
|
492 void MessagePumpForIO::WaitForWork() { |
|
493 // We do not support nested IO message loops. This is to avoid messy |
|
494 // recursion problems. |
|
495 DCHECK(state_->run_depth == 1) << "Cannot nest an IO message loop!"; |
|
496 |
|
497 int timeout = GetCurrentDelay(); |
|
498 if (timeout < 0) // Negative value means no timers waiting. |
|
499 timeout = INFINITE; |
|
500 |
|
501 WaitForIOCompletion(timeout, NULL); |
|
502 } |
|
503 |
|
504 bool MessagePumpForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) { |
|
505 IOItem item; |
|
506 if (completed_io_.empty() || !MatchCompletedIOItem(filter, &item)) { |
|
507 // We have to ask the system for another IO completion. |
|
508 if (!GetIOItem(timeout, &item)) |
|
509 return false; |
|
510 |
|
511 if (ProcessInternalIOItem(item)) |
|
512 return true; |
|
513 } |
|
514 |
|
515 if (item.context->handler) { |
|
516 if (filter && item.handler != filter) { |
|
517 // Save this item for later |
|
518 completed_io_.push_back(item); |
|
519 } else { |
|
520 DCHECK(item.context->handler == item.handler); |
|
521 item.handler->OnIOCompleted(item.context, item.bytes_transfered, |
|
522 item.error); |
|
523 } |
|
524 } else { |
|
525 // The handler must be gone by now, just cleanup the mess. |
|
526 delete item.context; |
|
527 } |
|
528 return true; |
|
529 } |
|
530 |
|
531 // Asks the OS for another IO completion result. |
|
532 bool MessagePumpForIO::GetIOItem(DWORD timeout, IOItem* item) { |
|
533 memset(item, 0, sizeof(*item)); |
|
534 ULONG_PTR key = 0; |
|
535 OVERLAPPED* overlapped = NULL; |
|
536 if (!GetQueuedCompletionStatus(port_.Get(), &item->bytes_transfered, &key, |
|
537 &overlapped, timeout)) { |
|
538 if (!overlapped) |
|
539 return false; // Nothing in the queue. |
|
540 item->error = GetLastError(); |
|
541 item->bytes_transfered = 0; |
|
542 } |
|
543 |
|
544 item->handler = reinterpret_cast<IOHandler*>(key); |
|
545 item->context = reinterpret_cast<IOContext*>(overlapped); |
|
546 return true; |
|
547 } |
|
548 |
|
549 bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) { |
|
550 if (this == reinterpret_cast<MessagePumpForIO*>(item.context) && |
|
551 this == reinterpret_cast<MessagePumpForIO*>(item.handler)) { |
|
552 // This is our internal completion. |
|
553 DCHECK(!item.bytes_transfered); |
|
554 InterlockedExchange(&have_work_, 0); |
|
555 return true; |
|
556 } |
|
557 return false; |
|
558 } |
|
559 |
|
560 // Returns a completion item that was previously received. |
|
561 bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) { |
|
562 DCHECK(!completed_io_.empty()); |
|
563 for (std::list<IOItem>::iterator it = completed_io_.begin(); |
|
564 it != completed_io_.end(); ++it) { |
|
565 if (!filter || it->handler == filter) { |
|
566 *item = *it; |
|
567 completed_io_.erase(it); |
|
568 return true; |
|
569 } |
|
570 } |
|
571 return false; |
|
572 } |
|
573 |
|
574 } // namespace base |