Chromium Code Reviews| 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 402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 413 // windows code. This ScheduleWork() may hurt performance a tiny bit when | 413 // windows code. This ScheduleWork() may hurt performance a tiny bit when |
| 414 // tasks appear very infrequently, but when the event queue is busy, the | 414 // tasks appear very infrequently, but when the event queue is busy, the |
| 415 // kMsgHaveWork events get (percentage wise) rarer and rarer. | 415 // kMsgHaveWork events get (percentage wise) rarer and rarer. |
| 416 ScheduleWork(); | 416 ScheduleWork(); |
| 417 return ProcessMessageHelper(msg); | 417 return ProcessMessageHelper(msg); |
| 418 } | 418 } |
| 419 | 419 |
| 420 //----------------------------------------------------------------------------- | 420 //----------------------------------------------------------------------------- |
| 421 // MessagePumpForIO public: | 421 // MessagePumpForIO public: |
| 422 | 422 |
| 423 MessagePumpForIO::IOContext::IOContext() { | |
| 424 memset(&overlapped, 0, sizeof(overlapped)); | |
| 425 } | |
| 426 | |
| 423 MessagePumpForIO::MessagePumpForIO() { | 427 MessagePumpForIO::MessagePumpForIO() { |
| 424 port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1)); | 428 port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1)); |
| 425 DCHECK(port_.IsValid()); | 429 DCHECK(port_.IsValid()); |
| 426 } | 430 } |
| 427 | 431 |
| 428 MessagePumpForIO::~MessagePumpForIO() { | 432 MessagePumpForIO::~MessagePumpForIO() = default; |
| 429 } | |
| 430 | 433 |
| 431 void MessagePumpForIO::ScheduleWork() { | 434 void MessagePumpForIO::ScheduleWork() { |
| 432 if (InterlockedExchange(&have_work_, 1)) | 435 if (InterlockedExchange(&have_work_, 1)) |
| 433 return; // Someone else continued the pumping. | 436 return; // Someone else continued the pumping. |
| 434 | 437 |
| 435 // Make sure the MessagePump does some work for us. | 438 // Make sure the MessagePump does some work for us. |
| 436 BOOL ret = PostQueuedCompletionStatus(port_.Get(), 0, | 439 BOOL ret = PostQueuedCompletionStatus(port_.Get(), 0, |
| 437 reinterpret_cast<ULONG_PTR>(this), | 440 reinterpret_cast<ULONG_PTR>(this), |
| 438 reinterpret_cast<OVERLAPPED*>(this)); | 441 reinterpret_cast<OVERLAPPED*>(this)); |
| 439 if (ret) | 442 if (ret) |
| 440 return; // Post worked perfectly. | 443 return; // Post worked perfectly. |
| 441 | 444 |
| 442 // See comment in MessagePumpForUI::ScheduleWork() for this error recovery. | 445 // See comment in MessagePumpForUI::ScheduleWork() for this error recovery. |
| 443 InterlockedExchange(&have_work_, 0); // Clarify that we didn't succeed. | 446 InterlockedExchange(&have_work_, 0); // Clarify that we didn't succeed. |
| 444 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR, | 447 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR, |
| 445 MESSAGE_LOOP_PROBLEM_MAX); | 448 MESSAGE_LOOP_PROBLEM_MAX); |
| 446 state_->schedule_work_error_count++; | 449 state_->schedule_work_error_count++; |
| 447 state_->last_schedule_work_error_time = Time::Now(); | 450 state_->last_schedule_work_error_time = Time::Now(); |
| 448 } | 451 } |
| 449 | 452 |
| 450 void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { | 453 void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { |
| 451 // We know that we can't be blocked right now since this method can only be | 454 // We know that we can't be blocked right now since this method can only be |
| 452 // called on the same thread as Run, so we only need to update our record of | 455 // called on the same thread as Run, so we only need to update our record of |
| 453 // how long to sleep when we do sleep. | 456 // how long to sleep when we do sleep. |
| 454 delayed_work_time_ = delayed_work_time; | 457 delayed_work_time_ = delayed_work_time; |
| 455 } | 458 } |
| 456 | 459 |
| 457 void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle, | 460 void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle, |
| 458 IOHandler* handler) { | 461 IOHandler* handler) { |
| 459 ULONG_PTR key = HandlerToKey(handler, true); | 462 HANDLE port = CreateIoCompletionPort(file_handle, port_.Get(), |
| 460 HANDLE port = CreateIoCompletionPort(file_handle, port_.Get(), key, 1); | 463 reinterpret_cast<ULONG_PTR>(handler), 1); |
| 461 DPCHECK(port); | 464 DPCHECK(port); |
| 462 } | 465 } |
| 463 | 466 |
| 464 bool MessagePumpForIO::RegisterJobObject(HANDLE job_handle, | 467 bool MessagePumpForIO::RegisterJobObject(HANDLE job_handle, |
| 465 IOHandler* handler) { | 468 IOHandler* handler) { |
| 466 // Job object notifications use the OVERLAPPED pointer to carry the message | |
| 467 // data. Mark the completion key correspondingly, so we will not try to | |
| 468 // convert OVERLAPPED* to IOContext*. | |
| 469 ULONG_PTR key = HandlerToKey(handler, false); | |
| 470 JOBOBJECT_ASSOCIATE_COMPLETION_PORT info; | 469 JOBOBJECT_ASSOCIATE_COMPLETION_PORT info; |
| 471 info.CompletionKey = reinterpret_cast<void*>(key); | 470 info.CompletionKey = reinterpret_cast<void*>(handler); |
|
Lei Zhang
2016/05/09 22:41:30
reinterpret_cast no longer needed?
fdoray
2016/05/10 16:33:17
Done.
Lei Zhang
2016/05/10 19:15:25
Nope. :-P
fdoray
2016/05/10 19:40:20
Done for realz.
| |
| 472 info.CompletionPort = port_.Get(); | 471 info.CompletionPort = port_.Get(); |
| 473 return SetInformationJobObject(job_handle, | 472 return SetInformationJobObject(job_handle, |
| 474 JobObjectAssociateCompletionPortInformation, | 473 JobObjectAssociateCompletionPortInformation, |
| 475 &info, | 474 &info, |
| 476 sizeof(info)) != FALSE; | 475 sizeof(info)) != FALSE; |
| 477 } | 476 } |
| 478 | 477 |
| 479 //----------------------------------------------------------------------------- | 478 //----------------------------------------------------------------------------- |
| 480 // MessagePumpForIO private: | 479 // MessagePumpForIO private: |
| 481 | 480 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 535 IOItem item; | 534 IOItem item; |
| 536 if (completed_io_.empty() || !MatchCompletedIOItem(filter, &item)) { | 535 if (completed_io_.empty() || !MatchCompletedIOItem(filter, &item)) { |
| 537 // We have to ask the system for another IO completion. | 536 // We have to ask the system for another IO completion. |
| 538 if (!GetIOItem(timeout, &item)) | 537 if (!GetIOItem(timeout, &item)) |
| 539 return false; | 538 return false; |
| 540 | 539 |
| 541 if (ProcessInternalIOItem(item)) | 540 if (ProcessInternalIOItem(item)) |
| 542 return true; | 541 return true; |
| 543 } | 542 } |
| 544 | 543 |
| 545 // If |item.has_valid_io_context| is false then |item.context| does not point | 544 if (filter && item.handler != filter) { |
| 546 // to a context structure, and so should not be dereferenced, although it may | 545 // Save this item for later |
| 547 // still hold valid non-pointer data. | 546 completed_io_.push_back(item); |
| 548 if (!item.has_valid_io_context || item.context->handler) { | |
|
Lei Zhang
2016/05/09 22:41:30
So I didn't write this code and I'm only looking a
fdoray
2016/05/10 16:33:17
yes, it's always non-null
| |
| 549 if (filter && item.handler != filter) { | |
| 550 // Save this item for later | |
| 551 completed_io_.push_back(item); | |
| 552 } else { | |
| 553 DCHECK(!item.has_valid_io_context || | |
| 554 (item.context->handler == item.handler)); | |
| 555 item.handler->OnIOCompleted(item.context, item.bytes_transfered, | |
| 556 item.error); | |
| 557 } | |
| 558 } else { | 547 } else { |
| 559 // The handler must be gone by now, just cleanup the mess. | 548 item.handler->OnIOCompleted(item.context, item.bytes_transfered, |
| 560 delete item.context; | 549 item.error); |
| 561 } | 550 } |
| 562 return true; | 551 return true; |
| 563 } | 552 } |
| 564 | 553 |
| 565 // Asks the OS for another IO completion result. | 554 // Asks the OS for another IO completion result. |
| 566 bool MessagePumpForIO::GetIOItem(DWORD timeout, IOItem* item) { | 555 bool MessagePumpForIO::GetIOItem(DWORD timeout, IOItem* item) { |
| 567 memset(item, 0, sizeof(*item)); | 556 memset(item, 0, sizeof(*item)); |
| 568 ULONG_PTR key = NULL; | 557 ULONG_PTR key = NULL; |
| 569 OVERLAPPED* overlapped = NULL; | 558 OVERLAPPED* overlapped = NULL; |
| 570 if (!GetQueuedCompletionStatus(port_.Get(), &item->bytes_transfered, &key, | 559 if (!GetQueuedCompletionStatus(port_.Get(), &item->bytes_transfered, &key, |
| 571 &overlapped, timeout)) { | 560 &overlapped, timeout)) { |
| 572 if (!overlapped) | 561 if (!overlapped) |
| 573 return false; // Nothing in the queue. | 562 return false; // Nothing in the queue. |
| 574 item->error = GetLastError(); | 563 item->error = GetLastError(); |
| 575 item->bytes_transfered = 0; | 564 item->bytes_transfered = 0; |
| 576 } | 565 } |
| 577 | 566 |
| 578 item->handler = KeyToHandler(key, &item->has_valid_io_context); | 567 item->handler = reinterpret_cast<IOHandler*>(key); |
| 579 item->context = reinterpret_cast<IOContext*>(overlapped); | 568 item->context = reinterpret_cast<IOContext*>(overlapped); |
| 580 return true; | 569 return true; |
| 581 } | 570 } |
| 582 | 571 |
| 583 bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) { | 572 bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) { |
| 584 if (reinterpret_cast<void*>(this) == reinterpret_cast<void*>(item.context) && | 573 if (reinterpret_cast<void*>(this) == reinterpret_cast<void*>(item.context) && |
| 585 reinterpret_cast<void*>(this) == reinterpret_cast<void*>(item.handler)) { | 574 reinterpret_cast<void*>(this) == reinterpret_cast<void*>(item.handler)) { |
| 586 // This is our internal completion. | 575 // This is our internal completion. |
| 587 DCHECK(!item.bytes_transfered); | 576 DCHECK(!item.bytes_transfered); |
| 588 InterlockedExchange(&have_work_, 0); | 577 InterlockedExchange(&have_work_, 0); |
| 589 return true; | 578 return true; |
| 590 } | 579 } |
| 591 return false; | 580 return false; |
| 592 } | 581 } |
| 593 | 582 |
| 594 // Returns a completion item that was previously received. | 583 // Returns a completion item that was previously received. |
| 595 bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) { | 584 bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) { |
| 596 DCHECK(!completed_io_.empty()); | 585 DCHECK(!completed_io_.empty()); |
| 597 for (std::list<IOItem>::iterator it = completed_io_.begin(); | 586 for (std::list<IOItem>::iterator it = completed_io_.begin(); |
| 598 it != completed_io_.end(); ++it) { | 587 it != completed_io_.end(); ++it) { |
| 599 if (!filter || it->handler == filter) { | 588 if (!filter || it->handler == filter) { |
| 600 *item = *it; | 589 *item = *it; |
| 601 completed_io_.erase(it); | 590 completed_io_.erase(it); |
| 602 return true; | 591 return true; |
| 603 } | 592 } |
| 604 } | 593 } |
| 605 return false; | 594 return false; |
| 606 } | 595 } |
| 607 | 596 |
| 608 // static | |
| 609 ULONG_PTR MessagePumpForIO::HandlerToKey(IOHandler* handler, | |
| 610 bool has_valid_io_context) { | |
| 611 ULONG_PTR key = reinterpret_cast<ULONG_PTR>(handler); | |
| 612 | |
| 613 // |IOHandler| is at least pointer-size aligned, so the lowest two bits are | |
| 614 // always cleared. We use the lowest bit to distinguish completion keys with | |
| 615 // and without the associated |IOContext|. | |
| 616 DCHECK_EQ(key & 1, 0u); | |
| 617 | |
| 618 // Mark the completion key as context-less. | |
| 619 if (!has_valid_io_context) | |
| 620 key = key | 1; | |
| 621 return key; | |
| 622 } | |
| 623 | |
| 624 // static | |
| 625 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( | |
| 626 ULONG_PTR key, | |
| 627 bool* has_valid_io_context) { | |
| 628 *has_valid_io_context = ((key & 1) == 0); | |
| 629 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); | |
| 630 } | |
| 631 | |
| 632 } // namespace base | 597 } // namespace base |
| OLD | NEW |