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 |