Index: mojo/common/message_pump_mojo.cc |
diff --git a/mojo/common/message_pump_mojo.cc b/mojo/common/message_pump_mojo.cc |
index 7b5b16302c07dbdb6864adc907717a474dabbd33..64e1396f874b24320103a4979e35274422fa7e1a 100644 |
--- a/mojo/common/message_pump_mojo.cc |
+++ b/mojo/common/message_pump_mojo.cc |
@@ -37,7 +37,7 @@ struct MessagePumpMojo::RunState { |
bool should_quit; |
}; |
-MessagePumpMojo::MessagePumpMojo() : run_state_(NULL) { |
+MessagePumpMojo::MessagePumpMojo() : run_state_(NULL), next_handler_id_(0) { |
} |
MessagePumpMojo::~MessagePumpMojo() { |
@@ -45,18 +45,22 @@ MessagePumpMojo::~MessagePumpMojo() { |
void MessagePumpMojo::AddHandler(MessagePumpMojoHandler* handler, |
MojoHandle handle, |
- MojoWaitFlags wait_flags) { |
+ MojoWaitFlags wait_flags, |
+ base::TimeTicks deadline) { |
DCHECK(handler); |
DCHECK_NE(MOJO_HANDLE_INVALID, handle); |
- handlers_[handle].handler = handler; |
- handlers_[handle].wait_flags = wait_flags; |
- |
- SignalControlPipe(); |
+ // Assume it's an error if someone tries to reregister an existing handle. |
+ DCHECK_EQ(0u, handlers_.count(handle)); |
+ Handler handler_data; |
+ handler_data.handler = handler; |
+ handler_data.wait_flags = wait_flags; |
+ handler_data.deadline = deadline; |
+ handler_data.id = next_handler_id_++; |
+ handlers_[handle] = handler_data; |
} |
void MessagePumpMojo::RemoveHandler(MojoHandle handle) { |
handlers_.erase(handle); |
- SignalControlPipe(); |
} |
void MessagePumpMojo::Run(Delegate* delegate) { |
@@ -115,15 +119,7 @@ void MessagePumpMojo::ScheduleDelayedWork( |
} |
void MessagePumpMojo::DoInternalWork(bool block) { |
- MojoDeadline deadline; |
- if (block && !run_state_->delayed_work_time.is_null()) { |
- const base::TimeDelta delta = run_state_->delayed_work_time - |
- base::TimeTicks::Now(); |
- deadline = std::max(static_cast<MojoDeadline>(0), |
- static_cast<MojoDeadline>(delta.InMicroseconds())); |
- } else { |
- deadline = 0; |
- } |
+ const MojoDeadline deadline = block ? GetDeadlineForWait() : 0; |
const WaitState wait_state = GetWaitState(); |
const MojoResult result = MojoWaitMany( |
&wait_state.handles.front(), |
@@ -152,6 +148,21 @@ void MessagePumpMojo::DoInternalWork(bool block) { |
NOTREACHED(); |
} |
} |
+ |
+ // Notify and remove any handlers whose time has expired. Make a copy in case |
+ // someone tries to add/remove new handlers from notification. |
+ const HandleToHandler cloned_handlers(handlers_); |
+ const base::TimeTicks now(base::TimeTicks::Now()); |
+ for (HandleToHandler::const_iterator i = cloned_handlers.begin(); |
+ i != cloned_handlers.end(); ++i) { |
+ // Since we're iterating over a clone of the handlers, verify the handler is |
+ // still valid before notifying. |
+ if (!i->second.deadline.is_null() && i->second.deadline < now && |
+ handlers_.find(i->first) != handlers_.end() && |
+ handlers_[i->first].id == i->second.id) { |
+ i->second.handler->OnHandleError(i->first, MOJO_RESULT_DEADLINE_EXCEEDED); |
+ } |
+ } |
} |
void MessagePumpMojo::RemoveFirstInvalidHandle(const WaitState& wait_state) { |
@@ -161,6 +172,8 @@ void MessagePumpMojo::RemoveFirstInvalidHandle(const WaitState& wait_state) { |
MojoWait(wait_state.handles[i], wait_state.wait_flags[i], 0); |
if (result == MOJO_RESULT_INVALID_ARGUMENT || |
result == MOJO_RESULT_FAILED_PRECONDITION) { |
+ // Remove the handle first, this way if OnHandleError() tries to remove |
+ // the handle our iterator isn't invalidated. |
DCHECK(handlers_.find(wait_state.handles[i]) != handlers_.end()); |
MessagePumpMojoHandler* handler = |
handlers_[wait_state.handles[i]].handler; |
@@ -195,5 +208,18 @@ MessagePumpMojo::WaitState MessagePumpMojo::GetWaitState() const { |
return wait_state; |
} |
+MojoDeadline MessagePumpMojo::GetDeadlineForWait() const { |
+ base::TimeTicks min_time = run_state_->delayed_work_time; |
+ for (HandleToHandler::const_iterator i = handlers_.begin(); |
+ i != handlers_.end(); ++i) { |
+ if (min_time.is_null() && i->second.deadline < min_time) |
+ min_time = i->second.deadline; |
+ } |
+ return min_time.is_null() ? MOJO_DEADLINE_INDEFINITE : |
+ std::max(static_cast<MojoDeadline>(0), |
+ static_cast<MojoDeadline>( |
+ (min_time - base::TimeTicks::Now()).InMicroseconds())); |
+} |
+ |
} // namespace common |
} // namespace mojo |