Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(218)

Side by Side Diff: base/message_loop/message_pump_win.cc

Issue 1714263002: Version of MessagePumpForUI optimized for GPU process (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Handle messages for other threads without exiting WaitForWork Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
87 InitMessageWnd(); 87 InitMessageWnd();
88 } 88 }
89 89
90 MessagePumpForUI::~MessagePumpForUI() { 90 MessagePumpForUI::~MessagePumpForUI() {
91 DestroyWindow(message_hwnd_); 91 DestroyWindow(message_hwnd_);
92 UnregisterClass(MAKEINTATOM(atom_), 92 UnregisterClass(MAKEINTATOM(atom_),
93 GetModuleFromAddress(&WndProcThunk)); 93 GetModuleFromAddress(&WndProcThunk));
94 } 94 }
95 95
96 void MessagePumpForUI::ScheduleWork() { 96 void MessagePumpForUI::ScheduleWork() {
97 if (InterlockedExchange(&have_work_, 1)) 97 if (READY != InterlockedExchange(&work_state_, HAVE_WORK))
Lei Zhang 2016/04/07 21:32:26 nit: Just write it normally with "READY" on the ri
stanisc 2016/04/08 01:07:12 Done.
98 return; // Someone else continued the pumping. 98 return; // Someone else continued the pumping.
99 99
100 // Make sure the MessagePump does some work for us. 100 // Make sure the MessagePump does some work for us.
101 BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork, 101 BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork,
102 reinterpret_cast<WPARAM>(this), 0); 102 reinterpret_cast<WPARAM>(this), 0);
103 if (ret) 103 if (ret)
104 return; // There was room in the Window Message queue. 104 return; // There was room in the Window Message queue.
105 105
106 // We have failed to insert a have-work message, so there is a chance that we 106 // We have failed to insert a have-work message, so there is a chance that we
107 // will starve tasks/timers while sitting in a nested message loop. Nested 107 // will starve tasks/timers while sitting in a nested message loop. Nested
108 // loops only look at Windows Message queues, and don't look at *our* task 108 // loops only look at Windows Message queues, and don't look at *our* task
109 // queues, etc., so we might not get a time slice in such. :-( 109 // queues, etc., so we might not get a time slice in such. :-(
110 // We could abort here, but the fear is that this failure mode is plausibly 110 // We could abort here, but the fear is that this failure mode is plausibly
111 // common (queue is full, of about 2000 messages), so we'll do a near-graceful 111 // common (queue is full, of about 2000 messages), so we'll do a near-graceful
112 // recovery. Nested loops are pretty transient (we think), so this will 112 // recovery. Nested loops are pretty transient (we think), so this will
113 // probably be recoverable. 113 // probably be recoverable.
114 InterlockedExchange(&have_work_, 0); // Clarify that we didn't really insert. 114
115 // Clarify that we didn't really insert.
116 InterlockedExchange(&work_state_, READY);
115 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR, 117 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR,
116 MESSAGE_LOOP_PROBLEM_MAX); 118 MESSAGE_LOOP_PROBLEM_MAX);
117 } 119 }
118 120
119 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { 121 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
120 delayed_work_time_ = delayed_work_time; 122 delayed_work_time_ = delayed_work_time;
121 RescheduleTimer(); 123 RescheduleTimer();
122 } 124 }
123 125
124 //----------------------------------------------------------------------------- 126 //-----------------------------------------------------------------------------
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 249
248 DCHECK_NE(WAIT_FAILED, result) << GetLastError(); 250 DCHECK_NE(WAIT_FAILED, result) << GetLastError();
249 } 251 }
250 252
251 void MessagePumpForUI::HandleWorkMessage() { 253 void MessagePumpForUI::HandleWorkMessage() {
252 // If we are being called outside of the context of Run, then don't try to do 254 // If we are being called outside of the context of Run, then don't try to do
253 // any work. This could correspond to a MessageBox call or something of that 255 // any work. This could correspond to a MessageBox call or something of that
254 // sort. 256 // sort.
255 if (!state_) { 257 if (!state_) {
256 // Since we handled a kMsgHaveWork message, we must still update this flag. 258 // Since we handled a kMsgHaveWork message, we must still update this flag.
257 InterlockedExchange(&have_work_, 0); 259 InterlockedExchange(&work_state_, READY);
258 return; 260 return;
259 } 261 }
260 262
261 // Let whatever would have run had we not been putting messages in the queue 263 // Let whatever would have run had we not been putting messages in the queue
262 // run now. This is an attempt to make our dummy message not starve other 264 // run now. This is an attempt to make our dummy message not starve other
263 // messages that may be in the Windows message queue. 265 // messages that may be in the Windows message queue.
264 ProcessPumpReplacementMessage(); 266 ProcessPumpReplacementMessage();
265 267
266 // Now give the delegate a chance to do some work. He'll let us know if he 268 // Now give the delegate a chance to do some work. He'll let us know if he
267 // needs to do more work. 269 // needs to do more work.
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
390 have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) || 392 have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) ||
391 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); 393 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE);
392 } else { 394 } else {
393 have_message = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE; 395 have_message = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE;
394 } 396 }
395 397
396 DCHECK(!have_message || kMsgHaveWork != msg.message || 398 DCHECK(!have_message || kMsgHaveWork != msg.message ||
397 msg.hwnd != message_hwnd_); 399 msg.hwnd != message_hwnd_);
398 400
399 // Since we discarded a kMsgHaveWork message, we must update the flag. 401 // Since we discarded a kMsgHaveWork message, we must update the flag.
400 int old_have_work = InterlockedExchange(&have_work_, 0); 402 int old_work_state_ = InterlockedExchange(&work_state_, READY);
401 DCHECK(old_have_work); 403 DCHECK_EQ(HAVE_WORK, old_work_state_);
402 404
403 // We don't need a special time slice if we didn't have_message to process. 405 // We don't need a special time slice if we didn't have_message to process.
404 if (!have_message) 406 if (!have_message)
405 return false; 407 return false;
406 408
407 // Guarantee we'll get another time slice in the case where we go into native 409 // Guarantee we'll get another time slice in the case where we go into native
408 // windows code. This ScheduleWork() may hurt performance a tiny bit when 410 // windows code. This ScheduleWork() may hurt performance a tiny bit when
409 // tasks appear very infrequently, but when the event queue is busy, the 411 // tasks appear very infrequently, but when the event queue is busy, the
410 // kMsgHaveWork events get (percentage wise) rarer and rarer. 412 // kMsgHaveWork events get (percentage wise) rarer and rarer.
411 ScheduleWork(); 413 ScheduleWork();
412 return ProcessMessageHelper(msg); 414 return ProcessMessageHelper(msg);
413 } 415 }
414 416
415 //----------------------------------------------------------------------------- 417 //-----------------------------------------------------------------------------
418 // MessagePumpForGpu public:
419
420 MessagePumpForGpu::MessagePumpForGpu()
421 : thread_id_(GetCurrentThreadId()) {
422 // Init the message queue.
423 MSG msg;
424 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
Lei Zhang 2016/04/07 21:32:26 nullptr in new code please.
stanisc 2016/04/08 01:07:12 Done.
425 }
426
427 MessagePumpForGpu::~MessagePumpForGpu() {
428 }
429
430 // static
431 void MessagePumpForGpu::InitFactory() {
432 MessageLoop::InitMessagePumpForUIFactory(
Lei Zhang 2016/04/07 21:32:26 DCHECK() the return result?
stanisc 2016/04/08 01:07:12 Done.
433 &MessagePumpForGpu::CreateMessagePumpForGpu);
434 }
435
436 // static
437 scoped_ptr<MessagePump> MessagePumpForGpu::CreateMessagePumpForGpu() {
438 return scoped_ptr<MessagePump>(new MessagePumpForGpu);
Lei Zhang 2016/04/07 21:32:26 Use base::WrapUnique
stanisc 2016/04/08 01:07:12 Done.
439 }
440
441 void MessagePumpForGpu::ScheduleWork() {
442 if (READY != InterlockedExchange(&work_state_, HAVE_WORK))
443 return; // Someone else continued the pumping.
444
445 // Make sure the MessagePump does some work for us.
446 BOOL ret = PostThreadMessage(thread_id_, kMsgHaveWork, 0, 0);
447 if (ret)
448 return; // There was room in the Window Message queue.
449
450 // We have failed to insert a have-work message, so there is a chance that we
Lei Zhang 2016/04/07 21:32:26 Do you really want to repeat this paragraph from M
stanisc 2016/04/08 01:07:12 Replaced the comment with a short one that referen
451 // will starve tasks/timers while sitting in a nested message loop. Nested
452 // loops only look at Windows Message queues, and don't look at *our* task
453 // queues, etc., so we might not get a time slice in such. :-(
454 // We could abort here, but the fear is that this failure mode is plausibly
455 // common (queue is full, of about 2000 messages), so we'll do a near-graceful
456 // recovery. Nested loops are pretty transient (we think), so this will
457 // probably be recoverable.
458
459 // Clarify that we didn't really insert.
460 InterlockedExchange(&work_state_, READY);
461 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR,
Lei Zhang 2016/04/07 21:32:26 I'm not familiar with this histogram, but do you c
stanisc 2016/04/08 01:07:12 Good question. I think it should be OK to reuse th
462 MESSAGE_LOOP_PROBLEM_MAX);
463 }
464
465 void MessagePumpForGpu::ScheduleDelayedWork(
466 const TimeTicks& delayed_work_time) {
467 // We know that we can't be blocked right now since this method can only be
468 // called on the same thread as Run, so we only need to update our record of
469 // how long to sleep when we do sleep.
470 delayed_work_time_ = delayed_work_time;
471 }
472
473 //-----------------------------------------------------------------------------
474 // MessagePumpForGpu private:
475
476 void MessagePumpForGpu::DoRunLoop() {
477 while (!state_->should_quit) {
478 // Indicate that the loop is handling the work.
479 // If there is a race condition between switching to WORKING state here and
480 // the producer thread setting the HAVE_WORK state after exiting the wait,
481 // the event might remain in the signalled state. That might be less than
482 // optimal but wouldn't result in failing to handle the work.
483 InterlockedExchange(&work_state_, WORKING);
484
485 bool more_work_is_plausible = state_->delegate->DoWork();
486 if (state_->should_quit)
487 break;
488
489 more_work_is_plausible |=
490 state_->delegate->DoDelayedWork(&delayed_work_time_);
491 if (state_->should_quit)
492 break;
493
494 if (more_work_is_plausible)
495 continue;
496
497 more_work_is_plausible = state_->delegate->DoIdleWork();
498 if (state_->should_quit)
499 break;
500
501 if (more_work_is_plausible)
502 continue;
503
504 // Switch that working state to READY to indicate that the loop is
505 // waiting for accepting new work if it is still in WORKING state and hasn't
506 // been signalled. Otherwise if it is in HAVE_WORK state skip the wait
507 // and proceed to handing the work.
508 if (HAVE_WORK == InterlockedCompareExchange(&work_state_, READY, WORKING))
509 continue; // Skip wait, more work was requested.
510
511 WaitForWork(); // Wait (sleep) until we have work to do again.
512 }
513 }
514
515 void MessagePumpForGpu::WaitForWork() {
516 // Wait until a message is available, up to the time needed by the timer
517 // manager to fire the next set of timers.
518 int delay;
519
520 // The while loop handles the situation where on Windows 7 and later versions
521 // MsgWaitForMultipleObjectsEx might time out slightly earlier (less than one
522 // ms) than the specified |delay|. In that situation it is more optimal to
523 // just wait again rather than waste a DoRunLoop cycle.
524 while((delay = GetCurrentDelay()) != 0) {
Lei Zhang 2016/04/07 21:32:26 nit: space after "while" - remember to run: git cl
stanisc 2016/04/08 01:07:12 Done.
525 if (delay < 0) // Negative value means no timers waiting.
526 delay = INFINITE;
527
528 DWORD result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, 0);
529 if (WAIT_OBJECT_0 == result) {
530 // A WM_* message is available.
531 if (ProcessMessages())
532 return;
533 }
534
535 DCHECK_NE(WAIT_FAILED, result) << GetLastError();
536 }
537 }
538
539 bool MessagePumpForGpu::ProcessMessages() {
540 MSG msg;
541 bool have_work = false;
542 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE) {
543 if (WM_QUIT == msg.message) {
544 // Repost the QUIT message so that it will be retrieved by the primary
545 // GetMessage() loop.
546 state_->should_quit = true;
547 PostQuitMessage(static_cast<int>(msg.wParam));
548 return true;
549 }
550
551 if (msg.hwnd == NULL && msg.message == kMsgHaveWork) {
552 have_work = true;
553 } else {
554 TranslateMessage(&msg);
555 DispatchMessage(&msg);
556 }
557 }
558
559 return have_work;
560 }
561
562 //-----------------------------------------------------------------------------
416 // MessagePumpForIO public: 563 // MessagePumpForIO public:
417 564
418 MessagePumpForIO::MessagePumpForIO() { 565 MessagePumpForIO::MessagePumpForIO() {
419 port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1)); 566 port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1));
420 DCHECK(port_.IsValid()); 567 DCHECK(port_.IsValid());
421 } 568 }
422 569
423 MessagePumpForIO::~MessagePumpForIO() { 570 MessagePumpForIO::~MessagePumpForIO() {
424 } 571 }
425 572
426 void MessagePumpForIO::ScheduleWork() { 573 void MessagePumpForIO::ScheduleWork() {
427 if (InterlockedExchange(&have_work_, 1)) 574 if (READY != InterlockedExchange(&work_state_, HAVE_WORK))
428 return; // Someone else continued the pumping. 575 return; // Someone else continued the pumping.
429 576
430 // Make sure the MessagePump does some work for us. 577 // Make sure the MessagePump does some work for us.
431 BOOL ret = PostQueuedCompletionStatus(port_.Get(), 0, 578 BOOL ret = PostQueuedCompletionStatus(port_.Get(), 0,
432 reinterpret_cast<ULONG_PTR>(this), 579 reinterpret_cast<ULONG_PTR>(this),
433 reinterpret_cast<OVERLAPPED*>(this)); 580 reinterpret_cast<OVERLAPPED*>(this));
434 if (ret) 581 if (ret)
435 return; // Post worked perfectly. 582 return; // Post worked perfectly.
436 583
437 // See comment in MessagePumpForUI::ScheduleWork() for this error recovery. 584 // See comment in MessagePumpForUI::ScheduleWork() for this error recovery.
438 InterlockedExchange(&have_work_, 0); // Clarify that we didn't succeed. 585 InterlockedExchange(&work_state_, READY); // Clarify that we didn't succeed.
439 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR, 586 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR,
440 MESSAGE_LOOP_PROBLEM_MAX); 587 MESSAGE_LOOP_PROBLEM_MAX);
441 } 588 }
442 589
443 void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { 590 void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
444 // We know that we can't be blocked right now since this method can only be 591 // We know that we can't be blocked right now since this method can only be
445 // called on the same thread as Run, so we only need to update our record of 592 // called on the same thread as Run, so we only need to update our record of
446 // how long to sleep when we do sleep. 593 // how long to sleep when we do sleep.
447 delayed_work_time_ = delayed_work_time; 594 delayed_work_time_ = delayed_work_time;
448 } 595 }
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
573 item->handler = KeyToHandler(key, &item->has_valid_io_context); 720 item->handler = KeyToHandler(key, &item->has_valid_io_context);
574 item->context = reinterpret_cast<IOContext*>(overlapped); 721 item->context = reinterpret_cast<IOContext*>(overlapped);
575 return true; 722 return true;
576 } 723 }
577 724
578 bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) { 725 bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) {
579 if (reinterpret_cast<void*>(this) == reinterpret_cast<void*>(item.context) && 726 if (reinterpret_cast<void*>(this) == reinterpret_cast<void*>(item.context) &&
580 reinterpret_cast<void*>(this) == reinterpret_cast<void*>(item.handler)) { 727 reinterpret_cast<void*>(this) == reinterpret_cast<void*>(item.handler)) {
581 // This is our internal completion. 728 // This is our internal completion.
582 DCHECK(!item.bytes_transfered); 729 DCHECK(!item.bytes_transfered);
583 InterlockedExchange(&have_work_, 0); 730 InterlockedExchange(&work_state_, READY);
584 return true; 731 return true;
585 } 732 }
586 return false; 733 return false;
587 } 734 }
588 735
589 // Returns a completion item that was previously received. 736 // Returns a completion item that was previously received.
590 bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) { 737 bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) {
591 DCHECK(!completed_io_.empty()); 738 DCHECK(!completed_io_.empty());
592 for (std::list<IOItem>::iterator it = completed_io_.begin(); 739 for (std::list<IOItem>::iterator it = completed_io_.begin();
593 it != completed_io_.end(); ++it) { 740 it != completed_io_.end(); ++it) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
634 781
635 // static 782 // static
636 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( 783 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler(
637 ULONG_PTR key, 784 ULONG_PTR key,
638 bool* has_valid_io_context) { 785 bool* has_valid_io_context) {
639 *has_valid_io_context = ((key & 1) == 0); 786 *has_valid_io_context = ((key & 1) == 0);
640 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); 787 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1));
641 } 788 }
642 789
643 } // namespace base 790 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698