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