OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 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 "mojo/common/message_pump_mojo.h" |
| 6 |
| 7 #include <algorithm> |
| 8 #include <vector> |
| 9 |
| 10 #include "base/logging.h" |
| 11 #include "mojo/common/message_pump_mojo_handler.h" |
| 12 #include "mojo/common/scoped_message_pipe.h" |
| 13 |
| 14 namespace mojo { |
| 15 namespace common { |
| 16 |
| 17 // State needed for one iteration of MojoWaitMany. The first handle and flags |
| 18 // corresponds to that of the control pipe. |
| 19 struct MessagePumpMojo::WaitState { |
| 20 std::vector<MojoHandle> handles; |
| 21 std::vector<MojoWaitFlags> wait_flags; |
| 22 }; |
| 23 |
| 24 struct MessagePumpMojo::RunState { |
| 25 public: |
| 26 RunState() : should_quit(false) {} |
| 27 |
| 28 MojoHandle read_handle() const { return control_pipe.handle_0(); } |
| 29 MojoHandle write_handle() const { return control_pipe.handle_1(); } |
| 30 |
| 31 base::TimeTicks delayed_work_time; |
| 32 |
| 33 // Used to wake up WaitForWork(). |
| 34 ScopedMessagePipe control_pipe; |
| 35 |
| 36 bool should_quit; |
| 37 }; |
| 38 |
| 39 MessagePumpMojo::MessagePumpMojo() : run_state_(NULL) { |
| 40 } |
| 41 |
| 42 MessagePumpMojo::~MessagePumpMojo() { |
| 43 } |
| 44 |
| 45 void MessagePumpMojo::AddHandler(MessagePumpMojoHandler* handler, |
| 46 MojoHandle handle, |
| 47 MojoWaitFlags wait_flags) { |
| 48 DCHECK(handler); |
| 49 DCHECK_NE(MOJO_HANDLE_INVALID, handle); |
| 50 handlers_[handle].handler = handler; |
| 51 handlers_[handle].wait_flags = wait_flags; |
| 52 |
| 53 SignalControlPipe(); |
| 54 } |
| 55 |
| 56 void MessagePumpMojo::RemoveHandler(MojoHandle handle) { |
| 57 handlers_.erase(handle); |
| 58 SignalControlPipe(); |
| 59 } |
| 60 |
| 61 void MessagePumpMojo::Run(Delegate* delegate) { |
| 62 RunState* old_state = run_state_; |
| 63 RunState run_state; |
| 64 // TODO: better deal with error handling. |
| 65 CHECK_NE(run_state.control_pipe.handle_0(), MOJO_HANDLE_INVALID); |
| 66 CHECK_NE(run_state.control_pipe.handle_1(), MOJO_HANDLE_INVALID); |
| 67 run_state_ = &run_state; |
| 68 bool more_work_is_plausible = true; |
| 69 for (;;) { |
| 70 const bool block = !more_work_is_plausible; |
| 71 DoInternalWork(block); |
| 72 |
| 73 // There isn't a good way to know if there are more handles ready, we assume |
| 74 // not. |
| 75 more_work_is_plausible = false; |
| 76 |
| 77 if (run_state.should_quit) |
| 78 break; |
| 79 |
| 80 more_work_is_plausible |= delegate->DoWork(); |
| 81 if (run_state.should_quit) |
| 82 break; |
| 83 |
| 84 more_work_is_plausible |= delegate->DoDelayedWork( |
| 85 &run_state.delayed_work_time); |
| 86 if (run_state.should_quit) |
| 87 break; |
| 88 |
| 89 if (more_work_is_plausible) |
| 90 continue; |
| 91 |
| 92 more_work_is_plausible = delegate->DoIdleWork(); |
| 93 if (run_state.should_quit) |
| 94 break; |
| 95 } |
| 96 run_state_ = old_state; |
| 97 } |
| 98 |
| 99 void MessagePumpMojo::Quit() { |
| 100 if (run_state_) |
| 101 run_state_->should_quit = true; |
| 102 } |
| 103 |
| 104 void MessagePumpMojo::ScheduleWork() { |
| 105 SignalControlPipe(); |
| 106 } |
| 107 |
| 108 void MessagePumpMojo::ScheduleDelayedWork( |
| 109 const base::TimeTicks& delayed_work_time) { |
| 110 if (!run_state_) |
| 111 return; |
| 112 run_state_->delayed_work_time = delayed_work_time; |
| 113 SignalControlPipe(); |
| 114 } |
| 115 |
| 116 void MessagePumpMojo::DoInternalWork(bool block) { |
| 117 MojoDeadline deadline; |
| 118 if (block && !run_state_->delayed_work_time.is_null()) { |
| 119 const base::TimeDelta delta = run_state_->delayed_work_time - |
| 120 base::TimeTicks::Now(); |
| 121 deadline = std::max(static_cast<MojoDeadline>(0), |
| 122 static_cast<MojoDeadline>(delta.InMicroseconds())); |
| 123 } else { |
| 124 deadline = 0; |
| 125 } |
| 126 const WaitState wait_state = GetWaitState(); |
| 127 const MojoResult result = MojoWaitMany( |
| 128 &wait_state.handles.front(), |
| 129 &wait_state.wait_flags.front(), |
| 130 static_cast<uint32_t>(wait_state.handles.size()), |
| 131 deadline); |
| 132 if (result == 0) { |
| 133 // Control pipe was written to. |
| 134 uint32_t num_bytes = 0; |
| 135 MojoReadMessage(run_state_->read_handle(), NULL, &num_bytes, NULL, 0, |
| 136 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); |
| 137 } else if (result > 0) { |
| 138 const size_t index = static_cast<size_t>(result); |
| 139 DCHECK(handlers_.find(wait_state.handles[index]) != handlers_.end()); |
| 140 handlers_[wait_state.handles[index]].handler->OnHandleReady( |
| 141 wait_state.handles[index]); |
| 142 } else { |
| 143 switch (result) { |
| 144 case MOJO_RESULT_INVALID_ARGUMENT: |
| 145 case MOJO_RESULT_FAILED_PRECONDITION: |
| 146 RemoveFirstInvalidHandle(wait_state); |
| 147 break; |
| 148 case MOJO_RESULT_DEADLINE_EXCEEDED: |
| 149 break; |
| 150 default: |
| 151 NOTREACHED(); |
| 152 } |
| 153 } |
| 154 } |
| 155 |
| 156 void MessagePumpMojo::RemoveFirstInvalidHandle(const WaitState& wait_state) { |
| 157 // TODO(sky): deal with control pipe going bad. |
| 158 for (size_t i = 1; i < wait_state.handles.size(); ++i) { |
| 159 const MojoResult result = |
| 160 MojoWait(wait_state.handles[i], wait_state.wait_flags[i], 0); |
| 161 if (result == MOJO_RESULT_INVALID_ARGUMENT || |
| 162 result == MOJO_RESULT_FAILED_PRECONDITION) { |
| 163 DCHECK(handlers_.find(wait_state.handles[i]) != handlers_.end()); |
| 164 MessagePumpMojoHandler* handler = |
| 165 handlers_[wait_state.handles[i]].handler; |
| 166 handlers_.erase(wait_state.handles[i]); |
| 167 handler->OnHandleError(wait_state.handles[i], result); |
| 168 return; |
| 169 } else { |
| 170 DCHECK_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, result); |
| 171 } |
| 172 } |
| 173 } |
| 174 |
| 175 void MessagePumpMojo::SignalControlPipe() { |
| 176 if (!run_state_) |
| 177 return; |
| 178 |
| 179 // TODO(sky): deal with error? |
| 180 MojoWriteMessage(run_state_->write_handle(), NULL, 0, NULL, 0, |
| 181 MOJO_WRITE_MESSAGE_FLAG_NONE); |
| 182 } |
| 183 |
| 184 MessagePumpMojo::WaitState MessagePumpMojo::GetWaitState() const { |
| 185 WaitState wait_state; |
| 186 wait_state.handles.push_back(run_state_->write_handle()); |
| 187 wait_state.wait_flags.push_back(MOJO_WAIT_FLAG_READABLE); |
| 188 |
| 189 for (HandleToHandler::const_iterator i = handlers_.begin(); |
| 190 i != handlers_.end(); ++i) { |
| 191 wait_state.handles.push_back(i->first); |
| 192 wait_state.wait_flags.push_back(i->second.wait_flags); |
| 193 } |
| 194 return wait_state; |
| 195 } |
| 196 |
| 197 } // namespace common |
| 198 } // namespace mojo |
OLD | NEW |