| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/message_loop/message_pump_win.h" | 5 #include "base/message_loop/message_pump_win.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <limits> | 10 #include <limits> |
| (...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 393 | 393 |
| 394 // Guarantee we'll get another time slice in the case where we go into native | 394 // Guarantee we'll get another time slice in the case where we go into native |
| 395 // windows code. This ScheduleWork() may hurt performance a tiny bit when | 395 // windows code. This ScheduleWork() may hurt performance a tiny bit when |
| 396 // tasks appear very infrequently, but when the event queue is busy, the | 396 // tasks appear very infrequently, but when the event queue is busy, the |
| 397 // kMsgHaveWork events get (percentage wise) rarer and rarer. | 397 // kMsgHaveWork events get (percentage wise) rarer and rarer. |
| 398 ScheduleWork(); | 398 ScheduleWork(); |
| 399 return ProcessMessageHelper(msg); | 399 return ProcessMessageHelper(msg); |
| 400 } | 400 } |
| 401 | 401 |
| 402 //----------------------------------------------------------------------------- | 402 //----------------------------------------------------------------------------- |
| 403 // MessagePumpForGpu public: | |
| 404 | |
| 405 MessagePumpForGpu::MessagePumpForGpu() { | |
| 406 event_.Set(CreateEvent(nullptr, FALSE, FALSE, nullptr)); | |
| 407 } | |
| 408 | |
| 409 MessagePumpForGpu::~MessagePumpForGpu() = default; | |
| 410 | |
| 411 // static | |
| 412 void MessagePumpForGpu::InitFactory() { | |
| 413 bool init_result = MessageLoop::InitMessagePumpForUIFactory( | |
| 414 &MessagePumpForGpu::CreateMessagePumpForGpu); | |
| 415 DCHECK(init_result); | |
| 416 } | |
| 417 | |
| 418 // static | |
| 419 std::unique_ptr<MessagePump> MessagePumpForGpu::CreateMessagePumpForGpu() { | |
| 420 return WrapUnique<MessagePump>(new MessagePumpForGpu); | |
| 421 } | |
| 422 | |
| 423 void MessagePumpForGpu::ScheduleWork() { | |
| 424 if (InterlockedExchange(&work_state_, HAVE_WORK) != READY) | |
| 425 return; // Someone else continued the pumping. | |
| 426 | |
| 427 // TODO(stanisc): crbug.com/596190: Preserve for crash dump analysis. | |
| 428 // Remove this when the bug is fixed. | |
| 429 last_set_event_timeticks_ = TimeTicks::Now(); | |
| 430 | |
| 431 // Make sure the MessagePump does some work for us. | |
| 432 SetEvent(event_.Get()); | |
| 433 } | |
| 434 | |
| 435 void MessagePumpForGpu::ScheduleDelayedWork( | |
| 436 const TimeTicks& delayed_work_time) { | |
| 437 // We know that we can't be blocked right now since this method can only be | |
| 438 // called on the same thread as Run, so we only need to update our record of | |
| 439 // how long to sleep when we do sleep. | |
| 440 delayed_work_time_ = delayed_work_time; | |
| 441 } | |
| 442 | |
| 443 //----------------------------------------------------------------------------- | |
| 444 // MessagePumpForGpu private: | |
| 445 | |
| 446 void MessagePumpForGpu::DoRunLoop() { | |
| 447 while (!state_->should_quit) { | |
| 448 // Indicate that the loop is handling the work. | |
| 449 // If there is a race condition between switching to WORKING state here and | |
| 450 // the producer thread setting the HAVE_WORK state after exiting the wait, | |
| 451 // the event might remain in the signalled state. That might be less than | |
| 452 // optimal but wouldn't result in failing to handle the work. | |
| 453 InterlockedExchange(&work_state_, WORKING); | |
| 454 | |
| 455 bool more_work_is_plausible = ProcessNextMessage(); | |
| 456 if (state_->should_quit) | |
| 457 break; | |
| 458 | |
| 459 more_work_is_plausible |= state_->delegate->DoWork(); | |
| 460 if (state_->should_quit) | |
| 461 break; | |
| 462 | |
| 463 more_work_is_plausible |= | |
| 464 state_->delegate->DoDelayedWork(&delayed_work_time_); | |
| 465 if (state_->should_quit) | |
| 466 break; | |
| 467 | |
| 468 if (more_work_is_plausible) | |
| 469 continue; | |
| 470 | |
| 471 more_work_is_plausible = state_->delegate->DoIdleWork(); | |
| 472 if (state_->should_quit) | |
| 473 break; | |
| 474 | |
| 475 if (more_work_is_plausible) | |
| 476 continue; | |
| 477 | |
| 478 // Switch that working state to READY to indicate that the loop is | |
| 479 // waiting for accepting new work if it is still in WORKING state and hasn't | |
| 480 // been signalled. Otherwise if it is in HAVE_WORK state skip the wait | |
| 481 // and proceed to handing the work. | |
| 482 if (InterlockedCompareExchange(&work_state_, READY, WORKING) == HAVE_WORK) | |
| 483 continue; // Skip wait, more work was requested. | |
| 484 | |
| 485 WaitForWork(); // Wait (sleep) until we have work to do again. | |
| 486 } | |
| 487 } | |
| 488 | |
| 489 void MessagePumpForGpu::WaitForWork() { | |
| 490 // Wait until a message is available, up to the time needed by the timer | |
| 491 // manager to fire the next set of timers. | |
| 492 int delay; | |
| 493 | |
| 494 // The while loop handles the situation where on Windows 7 and later versions | |
| 495 // MsgWaitForMultipleObjectsEx might time out slightly earlier (less than one | |
| 496 // ms) than the specified |delay|. In that situation it is more optimal to | |
| 497 // just wait again rather than waste a DoRunLoop cycle. | |
| 498 while ((delay = GetCurrentDelay()) != 0) { | |
| 499 if (delay < 0) // Negative value means no timers waiting. | |
| 500 delay = INFINITE; | |
| 501 | |
| 502 // TODO(stanisc): crbug.com/596190: Preserve for crash dump analysis. | |
| 503 // Remove this when the bug is fixed. | |
| 504 TimeTicks wait_for_work_timeticks = TimeTicks::Now(); | |
| 505 debug::Alias(&wait_for_work_timeticks); | |
| 506 debug::Alias(&delay); | |
| 507 | |
| 508 HANDLE handle = event_.Get(); | |
| 509 DWORD result = | |
| 510 MsgWaitForMultipleObjectsEx(1, &handle, delay, QS_ALLINPUT, 0); | |
| 511 DCHECK_NE(WAIT_FAILED, result) << GetLastError(); | |
| 512 if (result != WAIT_TIMEOUT) { | |
| 513 // Either work or message available. | |
| 514 return; | |
| 515 } | |
| 516 } | |
| 517 } | |
| 518 | |
| 519 bool MessagePumpForGpu::ProcessNextMessage() { | |
| 520 MSG msg; | |
| 521 if (!PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) | |
| 522 return false; | |
| 523 | |
| 524 if (msg.message == WM_QUIT) { | |
| 525 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", | |
| 526 RECEIVED_WM_QUIT_ERROR, MESSAGE_LOOP_PROBLEM_MAX); | |
| 527 // WM_QUIT messages shouldn't be received by any threads in the GPU | |
| 528 // process. If they are, just ignore them instead of causing threads to | |
| 529 // exit prematurely. | |
| 530 return true; | |
| 531 } | |
| 532 | |
| 533 TranslateMessage(&msg); | |
| 534 DispatchMessage(&msg); | |
| 535 | |
| 536 return true; | |
| 537 } | |
| 538 | |
| 539 //----------------------------------------------------------------------------- | |
| 540 // MessagePumpForIO public: | 403 // MessagePumpForIO public: |
| 541 | 404 |
| 542 MessagePumpForIO::IOContext::IOContext() { | 405 MessagePumpForIO::IOContext::IOContext() { |
| 543 memset(&overlapped, 0, sizeof(overlapped)); | 406 memset(&overlapped, 0, sizeof(overlapped)); |
| 544 } | 407 } |
| 545 | 408 |
| 546 MessagePumpForIO::MessagePumpForIO() { | 409 MessagePumpForIO::MessagePumpForIO() { |
| 547 port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, | 410 port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, |
| 548 reinterpret_cast<ULONG_PTR>(nullptr), 1)); | 411 reinterpret_cast<ULONG_PTR>(nullptr), 1)); |
| 549 DCHECK(port_.IsValid()); | 412 DCHECK(port_.IsValid()); |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 708 if (!filter || it->handler == filter) { | 571 if (!filter || it->handler == filter) { |
| 709 *item = *it; | 572 *item = *it; |
| 710 completed_io_.erase(it); | 573 completed_io_.erase(it); |
| 711 return true; | 574 return true; |
| 712 } | 575 } |
| 713 } | 576 } |
| 714 return false; | 577 return false; |
| 715 } | 578 } |
| 716 | 579 |
| 717 } // namespace base | 580 } // namespace base |
| OLD | NEW |