Chromium Code Reviews| 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, | |
|
Ben Goodger (Google)
2013/11/08 21:24:35
mojo::Handle, mojo::WriteMessage etc?
| |
| 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(&wait_state.handles.front(), | |
| 128 &wait_state.wait_flags.front(), | |
| 129 wait_state.handles.size(), | |
|
darin (slow to review)
2013/11/09 00:47:50
nit: win64 build will complain here. need static_c
sky
2013/11/11 15:14:17
Done.
| |
| 130 deadline); | |
| 131 if (result == 0) { | |
| 132 // Control pipe was written to. | |
| 133 uint32_t num_bytes = 0; | |
| 134 MojoReadMessage(run_state_->read_handle(), NULL, &num_bytes, NULL, 0, | |
| 135 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); | |
| 136 } else if (result > 0) { | |
| 137 const size_t index = static_cast<size_t>(result); | |
| 138 DCHECK(handlers_.find(wait_state.handles[index]) != handlers_.end()); | |
| 139 handlers_[wait_state.handles[index]].handler->OnHandleReady( | |
| 140 wait_state.handles[index]); | |
| 141 } else { | |
| 142 switch (result) { | |
| 143 case MOJO_RESULT_INVALID_ARGUMENT: | |
| 144 case MOJO_RESULT_FAILED_PRECONDITION: | |
| 145 RemoveFirstInvalidHandle(wait_state); | |
| 146 break; | |
| 147 case MOJO_RESULT_DEADLINE_EXCEEDED: | |
| 148 break; | |
| 149 default: | |
| 150 NOTREACHED(); | |
| 151 } | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 void MessagePumpMojo::RemoveFirstInvalidHandle(const WaitState& wait_state) { | |
| 156 // TODO(sky): deal with control pipe going bad. | |
| 157 for (size_t i = 1; i < wait_state.handles.size(); ++i) { | |
| 158 const MojoResult result = | |
| 159 MojoWait(wait_state.handles[i], wait_state.wait_flags[i], 0); | |
| 160 if (result == MOJO_RESULT_INVALID_ARGUMENT || | |
| 161 result == MOJO_RESULT_FAILED_PRECONDITION) { | |
| 162 DCHECK(handlers_.find(wait_state.handles[i]) != handlers_.end()); | |
| 163 MessagePumpMojoHandler* handler = | |
| 164 handlers_[wait_state.handles[i]].handler; | |
| 165 handlers_.erase(wait_state.handles[i]); | |
| 166 handler->OnHandleInvalid(wait_state.handles[i], result); | |
| 167 return; | |
| 168 } else { | |
| 169 DCHECK_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, result); | |
| 170 } | |
| 171 } | |
| 172 } | |
| 173 | |
| 174 void MessagePumpMojo::SignalControlPipe() { | |
| 175 if (!run_state_) | |
| 176 return; | |
| 177 | |
| 178 // TODO(sky): deal with error? | |
| 179 MojoWriteMessage(run_state_->write_handle(), NULL, 0, NULL, 0, | |
| 180 MOJO_WRITE_MESSAGE_FLAG_NONE); | |
| 181 } | |
| 182 | |
| 183 MessagePumpMojo::WaitState MessagePumpMojo::GetWaitState() const { | |
| 184 WaitState wait_state; | |
| 185 wait_state.handles.push_back(run_state_->write_handle()); | |
| 186 wait_state.wait_flags.push_back(MOJO_WAIT_FLAG_READABLE); | |
| 187 | |
| 188 for (HandleToHandler::const_iterator i = handlers_.begin(); | |
| 189 i != handlers_.end(); ++i) { | |
| 190 wait_state.handles.push_back(i->first); | |
| 191 wait_state.wait_flags.push_back(i->second.wait_flags); | |
| 192 } | |
| 193 return wait_state; | |
| 194 } | |
| 195 | |
| 196 } // namespace common | |
| 197 } // namespace mojo | |
| OLD | NEW |