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