Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 "mojo/common/message_pump_mojo.h" | 5 #include "mojo/common/message_pump_mojo.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/debug/alias.h" | 10 #include "base/debug/alias.h" |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 46 RunState() : should_quit(false) { | 46 RunState() : should_quit(false) { |
| 47 CreateMessagePipe(NULL, &read_handle, &write_handle); | 47 CreateMessagePipe(NULL, &read_handle, &write_handle); |
| 48 } | 48 } |
| 49 | 49 |
| 50 base::TimeTicks delayed_work_time; | 50 base::TimeTicks delayed_work_time; |
| 51 | 51 |
| 52 // Used to wake up WaitForWork(). | 52 // Used to wake up WaitForWork(). |
| 53 ScopedMessagePipeHandle read_handle; | 53 ScopedMessagePipeHandle read_handle; |
| 54 ScopedMessagePipeHandle write_handle; | 54 ScopedMessagePipeHandle write_handle; |
| 55 | 55 |
| 56 // Cached structures to avoid the heap allocation cost of std::vector<>. | |
| 57 scoped_ptr<WaitState> wait_state; | |
| 58 scoped_ptr<HandleToHandlerList> cloned_handlers; | |
| 59 | |
| 56 bool should_quit; | 60 bool should_quit; |
| 57 }; | 61 }; |
| 58 | 62 |
| 59 MessagePumpMojo::MessagePumpMojo() : run_state_(NULL), next_handler_id_(0) { | 63 MessagePumpMojo::MessagePumpMojo() : run_state_(NULL), next_handler_id_(0) { |
| 60 DCHECK(!current()) | 64 DCHECK(!current()) |
| 61 << "There is already a MessagePumpMojo instance on this thread."; | 65 << "There is already a MessagePumpMojo instance on this thread."; |
| 62 g_tls_current_pump.Pointer()->Set(this); | 66 g_tls_current_pump.Pointer()->Set(this); |
| 63 } | 67 } |
| 64 | 68 |
| 65 MessagePumpMojo::~MessagePumpMojo() { | 69 MessagePumpMojo::~MessagePumpMojo() { |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 165 continue; | 169 continue; |
| 166 | 170 |
| 167 more_work_is_plausible = delegate->DoIdleWork(); | 171 more_work_is_plausible = delegate->DoIdleWork(); |
| 168 if (run_state->should_quit) | 172 if (run_state->should_quit) |
| 169 break; | 173 break; |
| 170 } | 174 } |
| 171 } | 175 } |
| 172 | 176 |
| 173 bool MessagePumpMojo::DoInternalWork(const RunState& run_state, bool block) { | 177 bool MessagePumpMojo::DoInternalWork(const RunState& run_state, bool block) { |
| 174 const MojoDeadline deadline = block ? GetDeadlineForWait(run_state) : 0; | 178 const MojoDeadline deadline = block ? GetDeadlineForWait(run_state) : 0; |
| 175 const WaitState wait_state = GetWaitState(run_state); | 179 if (!run_state_->wait_state) |
| 180 run_state_->wait_state.reset(new WaitState); | |
| 181 GetWaitState(run_state, run_state_->wait_state.get()); | |
| 176 | 182 |
| 177 const WaitManyResult wait_many_result = | 183 const WaitManyResult wait_many_result = |
| 178 WaitMany(wait_state.handles, wait_state.wait_signals, deadline, nullptr); | 184 WaitMany(run_state_->wait_state->handles, |
| 185 run_state_->wait_state->wait_signals, deadline, nullptr); | |
| 179 const MojoResult result = wait_many_result.result; | 186 const MojoResult result = wait_many_result.result; |
| 180 bool did_work = true; | 187 bool did_work = true; |
| 181 if (result == MOJO_RESULT_OK) { | 188 if (result == MOJO_RESULT_OK) { |
| 182 if (wait_many_result.index == 0) { | 189 if (wait_many_result.index == 0) { |
| 183 // Control pipe was written to. | 190 // Control pipe was written to. |
| 184 ReadMessageRaw(run_state.read_handle.get(), NULL, NULL, NULL, NULL, | 191 ReadMessageRaw(run_state.read_handle.get(), NULL, NULL, NULL, NULL, |
| 185 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); | 192 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); |
| 186 } else { | 193 } else { |
| 187 DCHECK(handlers_.find(wait_state.handles[wait_many_result.index]) != | 194 DCHECK(handlers_.find( |
| 195 run_state_->wait_state->handles[wait_many_result.index]) != | |
| 188 handlers_.end()); | 196 handlers_.end()); |
| 189 WillSignalHandler(); | 197 WillSignalHandler(); |
| 190 handlers_[wait_state.handles[wait_many_result.index]] | 198 handlers_[run_state_->wait_state->handles[wait_many_result.index]] |
| 191 .handler->OnHandleReady(wait_state.handles[wait_many_result.index]); | 199 .handler->OnHandleReady( |
| 200 run_state_->wait_state->handles[wait_many_result.index]); | |
| 192 DidSignalHandler(); | 201 DidSignalHandler(); |
| 193 } | 202 } |
| 194 } else { | 203 } else { |
| 195 switch (result) { | 204 switch (result) { |
| 196 case MOJO_RESULT_CANCELLED: | 205 case MOJO_RESULT_CANCELLED: |
| 197 case MOJO_RESULT_FAILED_PRECONDITION: | 206 case MOJO_RESULT_FAILED_PRECONDITION: |
| 198 RemoveInvalidHandle(wait_state, result, wait_many_result.index); | 207 RemoveInvalidHandle(*run_state_->wait_state, result, |
| 208 wait_many_result.index); | |
| 199 break; | 209 break; |
| 200 case MOJO_RESULT_DEADLINE_EXCEEDED: | 210 case MOJO_RESULT_DEADLINE_EXCEEDED: |
| 201 did_work = false; | 211 did_work = false; |
| 202 break; | 212 break; |
| 203 default: | 213 default: |
| 204 base::debug::Alias(&result); | 214 base::debug::Alias(&result); |
| 205 // Unexpected result is likely fatal, crash so we can determine cause. | 215 // Unexpected result is likely fatal, crash so we can determine cause. |
| 206 CHECK(false); | 216 CHECK(false); |
| 207 } | 217 } |
| 208 } | 218 } |
| 219 // To keep memory usage under control, delete the WaitState object at the end | |
| 220 // if it's vectors are too big by a factor of 2. Pre-C++11 doesn't have a way | |
| 221 // to shrink vectors, so just get rid of them and re-create on the next round. | |
| 222 if (run_state_->wait_state->handles.capacity() > | |
| 223 2 * run_state_->wait_state->handles.size() || | |
| 224 run_state_->wait_state->wait_signals.capacity() > | |
| 225 2 * run_state_->wait_state->wait_signals.size()) { | |
|
qsr
2015/05/28 09:33:48
Not sure the || is needed here. The 2 vectors shou
Anand Mistry (off Chromium)
2015/05/28 23:27:45
Good point. They should be in sync.
| |
| 226 run_state_->wait_state.reset(); | |
| 227 } | |
| 209 | 228 |
| 210 // Notify and remove any handlers whose time has expired. Make a copy in case | 229 // Notify and remove any handlers whose time has expired. Make a copy in case |
| 211 // someone tries to add/remove new handlers from notification. | 230 // someone tries to add/remove new handlers from notification. |
| 212 const HandleToHandler cloned_handlers(handlers_); | 231 if (!run_state_->cloned_handlers) { |
| 232 run_state_->cloned_handlers.reset(new HandleToHandlerList); | |
| 233 run_state_->cloned_handlers->reserve(handlers_.size()); | |
|
qsr
2015/05/28 09:33:48
Isn't the reserve always useful, whether the list
Anand Mistry (off Chromium)
2015/05/28 23:27:45
Done.
| |
| 234 } else { | |
| 235 run_state_->cloned_handlers->clear(); | |
| 236 } | |
| 237 for (const auto& handler : handlers_) { | |
| 238 run_state_->cloned_handlers->push_back(handler); | |
| 239 } | |
| 213 const base::TimeTicks now(internal::NowTicks()); | 240 const base::TimeTicks now(internal::NowTicks()); |
| 214 for (HandleToHandler::const_iterator i = cloned_handlers.begin(); | 241 for (HandleToHandlerList::const_iterator i = |
| 215 i != cloned_handlers.end(); ++i) { | 242 run_state_->cloned_handlers->begin(); |
| 243 i != run_state_->cloned_handlers->end(); ++i) { | |
| 216 // Since we're iterating over a clone of the handlers, verify the handler is | 244 // Since we're iterating over a clone of the handlers, verify the handler is |
| 217 // still valid before notifying. | 245 // still valid before notifying. |
| 218 if (!i->second.deadline.is_null() && i->second.deadline < now && | 246 if (!i->second.deadline.is_null() && i->second.deadline < now && |
| 219 handlers_.find(i->first) != handlers_.end() && | 247 handlers_.find(i->first) != handlers_.end() && |
| 220 handlers_[i->first].id == i->second.id) { | 248 handlers_[i->first].id == i->second.id) { |
| 221 WillSignalHandler(); | 249 WillSignalHandler(); |
| 222 i->second.handler->OnHandleError(i->first, MOJO_RESULT_DEADLINE_EXCEEDED); | 250 i->second.handler->OnHandleError(i->first, MOJO_RESULT_DEADLINE_EXCEEDED); |
| 223 DidSignalHandler(); | 251 DidSignalHandler(); |
| 224 handlers_.erase(i->first); | 252 handlers_.erase(i->first); |
| 225 did_work = true; | 253 did_work = true; |
| 226 } | 254 } |
| 227 } | 255 } |
| 256 if (run_state_->cloned_handlers->capacity() > | |
| 257 2 * run_state_->cloned_handlers->size()) { | |
| 258 run_state_->cloned_handlers.reset(); | |
| 259 } | |
| 228 return did_work; | 260 return did_work; |
| 229 } | 261 } |
| 230 | 262 |
| 231 void MessagePumpMojo::RemoveInvalidHandle(const WaitState& wait_state, | 263 void MessagePumpMojo::RemoveInvalidHandle(const WaitState& wait_state, |
| 232 MojoResult result, | 264 MojoResult result, |
| 233 uint32_t index) { | 265 uint32_t index) { |
| 234 // TODO(sky): deal with control pipe going bad. | 266 // TODO(sky): deal with control pipe going bad. |
| 235 CHECK(result == MOJO_RESULT_FAILED_PRECONDITION || | 267 CHECK(result == MOJO_RESULT_FAILED_PRECONDITION || |
| 236 result == MOJO_RESULT_CANCELLED); | 268 result == MOJO_RESULT_CANCELLED); |
| 237 CHECK_NE(index, 0u); // Indicates the control pipe went bad. | 269 CHECK_NE(index, 0u); // Indicates the control pipe went bad. |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 249 | 281 |
| 250 void MessagePumpMojo::SignalControlPipe(const RunState& run_state) { | 282 void MessagePumpMojo::SignalControlPipe(const RunState& run_state) { |
| 251 const MojoResult result = | 283 const MojoResult result = |
| 252 WriteMessageRaw(run_state.write_handle.get(), NULL, 0, NULL, 0, | 284 WriteMessageRaw(run_state.write_handle.get(), NULL, 0, NULL, 0, |
| 253 MOJO_WRITE_MESSAGE_FLAG_NONE); | 285 MOJO_WRITE_MESSAGE_FLAG_NONE); |
| 254 // If we can't write we likely won't wake up the thread and there is a strong | 286 // If we can't write we likely won't wake up the thread and there is a strong |
| 255 // chance we'll deadlock. | 287 // chance we'll deadlock. |
| 256 CHECK_EQ(MOJO_RESULT_OK, result); | 288 CHECK_EQ(MOJO_RESULT_OK, result); |
| 257 } | 289 } |
| 258 | 290 |
| 259 MessagePumpMojo::WaitState MessagePumpMojo::GetWaitState( | 291 void MessagePumpMojo::GetWaitState( |
| 260 const RunState& run_state) const { | 292 const RunState& run_state, |
| 261 WaitState wait_state; | 293 MessagePumpMojo::WaitState* wait_state) const { |
| 262 wait_state.handles.push_back(run_state.read_handle.get()); | 294 wait_state->handles.clear(); |
| 263 wait_state.wait_signals.push_back(MOJO_HANDLE_SIGNAL_READABLE); | 295 wait_state->wait_signals.clear(); |
|
qsr
2015/05/28 09:33:48
Do you want to use resize here?
Anand Mistry (off Chromium)
2015/05/28 23:27:45
Nah. That would change the logic here and I don't
qsr
2015/05/29 07:56:08
Sorry, I meant reserve, not resize. That will not
Anand Mistry (off Chromium)
2015/05/29 09:00:57
Done.
| |
| 296 wait_state->handles.push_back(run_state.read_handle.get()); | |
| 297 wait_state->wait_signals.push_back(MOJO_HANDLE_SIGNAL_READABLE); | |
| 264 | 298 |
| 265 for (HandleToHandler::const_iterator i = handlers_.begin(); | 299 for (HandleToHandler::const_iterator i = handlers_.begin(); |
| 266 i != handlers_.end(); ++i) { | 300 i != handlers_.end(); ++i) { |
| 267 wait_state.handles.push_back(i->first); | 301 wait_state->handles.push_back(i->first); |
| 268 wait_state.wait_signals.push_back(i->second.wait_signals); | 302 wait_state->wait_signals.push_back(i->second.wait_signals); |
| 269 } | 303 } |
| 270 return wait_state; | |
| 271 } | 304 } |
| 272 | 305 |
| 273 MojoDeadline MessagePumpMojo::GetDeadlineForWait( | 306 MojoDeadline MessagePumpMojo::GetDeadlineForWait( |
| 274 const RunState& run_state) const { | 307 const RunState& run_state) const { |
| 275 const base::TimeTicks now(internal::NowTicks()); | 308 const base::TimeTicks now(internal::NowTicks()); |
| 276 MojoDeadline deadline = TimeTicksToMojoDeadline(run_state.delayed_work_time, | 309 MojoDeadline deadline = TimeTicksToMojoDeadline(run_state.delayed_work_time, |
| 277 now); | 310 now); |
| 278 for (HandleToHandler::const_iterator i = handlers_.begin(); | 311 for (HandleToHandler::const_iterator i = handlers_.begin(); |
| 279 i != handlers_.end(); ++i) { | 312 i != handlers_.end(); ++i) { |
| 280 deadline = std::min( | 313 deadline = std::min( |
| 281 TimeTicksToMojoDeadline(i->second.deadline, now), deadline); | 314 TimeTicksToMojoDeadline(i->second.deadline, now), deadline); |
| 282 } | 315 } |
| 283 return deadline; | 316 return deadline; |
| 284 } | 317 } |
| 285 | 318 |
| 286 void MessagePumpMojo::WillSignalHandler() { | 319 void MessagePumpMojo::WillSignalHandler() { |
| 287 FOR_EACH_OBSERVER(Observer, observers_, WillSignalHandler()); | 320 FOR_EACH_OBSERVER(Observer, observers_, WillSignalHandler()); |
| 288 } | 321 } |
| 289 | 322 |
| 290 void MessagePumpMojo::DidSignalHandler() { | 323 void MessagePumpMojo::DidSignalHandler() { |
| 291 FOR_EACH_OBSERVER(Observer, observers_, DidSignalHandler()); | 324 FOR_EACH_OBSERVER(Observer, observers_, DidSignalHandler()); |
| 292 } | 325 } |
| 293 | 326 |
| 294 } // namespace common | 327 } // namespace common |
| 295 } // namespace mojo | 328 } // namespace mojo |
| OLD | NEW |