Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: mojo/system/core_impl.cc

Issue 216893005: Mojo: Move the handle table details out of CoreImpl into its own class. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix compile assert Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « mojo/system/core_impl.h ('k') | mojo/system/dispatcher.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/system/core_impl.h" 5 #include "mojo/system/core_impl.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/time/time.h" 10 #include "base/time/time.h"
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
80 CoreImpl::HandleTableEntry::HandleTableEntry( 80 CoreImpl::HandleTableEntry::HandleTableEntry(
81 const scoped_refptr<Dispatcher>& dispatcher) 81 const scoped_refptr<Dispatcher>& dispatcher)
82 : dispatcher(dispatcher), 82 : dispatcher(dispatcher),
83 busy(false) { 83 busy(false) {
84 } 84 }
85 85
86 CoreImpl::HandleTableEntry::~HandleTableEntry() { 86 CoreImpl::HandleTableEntry::~HandleTableEntry() {
87 DCHECK(!busy); 87 DCHECK(!busy);
88 } 88 }
89 89
90 CoreImpl::CoreImpl() 90 CoreImpl::CoreImpl() {
91 : next_handle_(MOJO_HANDLE_INVALID + 1) {
92 } 91 }
93 92
94 CoreImpl::~CoreImpl() { 93 CoreImpl::~CoreImpl() {
95 // This should usually not be reached (the singleton lives forever), except in 94 // This should usually not be reached (the singleton lives forever), except in
96 // tests. 95 // tests.
97 } 96 }
98 97
99 MojoHandle CoreImpl::AddDispatcher( 98 MojoHandle CoreImpl::AddDispatcher(
100 const scoped_refptr<Dispatcher>& dispatcher) { 99 const scoped_refptr<Dispatcher>& dispatcher) {
101 base::AutoLock locker(handle_table_lock_); 100 base::AutoLock locker(handle_table_lock_);
102 return AddDispatcherNoLock(dispatcher); 101 return handle_table_.AddDispatcher(dispatcher);
103 } 102 }
104 103
105 MojoTimeTicks CoreImpl::GetTimeTicksNow() { 104 MojoTimeTicks CoreImpl::GetTimeTicksNow() {
106 return base::TimeTicks::Now().ToInternalValue(); 105 return base::TimeTicks::Now().ToInternalValue();
107 } 106 }
108 107
109 MojoResult CoreImpl::Close(MojoHandle handle) { 108 MojoResult CoreImpl::Close(MojoHandle handle) {
110 if (handle == MOJO_HANDLE_INVALID) 109 if (handle == MOJO_HANDLE_INVALID)
111 return MOJO_RESULT_INVALID_ARGUMENT; 110 return MOJO_RESULT_INVALID_ARGUMENT;
112 111
113 scoped_refptr<Dispatcher> dispatcher; 112 scoped_refptr<Dispatcher> dispatcher;
114 { 113 {
115 base::AutoLock locker(handle_table_lock_); 114 base::AutoLock locker(handle_table_lock_);
116 HandleTableMap::iterator it = handle_table_.find(handle); 115 MojoResult result = handle_table_.GetAndRemoveDispatcher(handle,
117 if (it == handle_table_.end()) 116 &dispatcher);
118 return MOJO_RESULT_INVALID_ARGUMENT; 117 if (result != MOJO_RESULT_OK)
119 if (it->second.busy) 118 return result;
120 return MOJO_RESULT_BUSY;
121 dispatcher = it->second.dispatcher;
122 handle_table_.erase(it);
123 } 119 }
124 120
125 // The dispatcher doesn't have a say in being closed, but gets notified of it. 121 // The dispatcher doesn't have a say in being closed, but gets notified of it.
126 // Note: This is done outside of |handle_table_lock_|. As a result, there's a 122 // Note: This is done outside of |handle_table_lock_|. As a result, there's a
127 // race condition that the dispatcher must handle; see the comment in 123 // race condition that the dispatcher must handle; see the comment in
128 // |Dispatcher| in dispatcher.h. 124 // |Dispatcher| in dispatcher.h.
129 return dispatcher->Close(); 125 return dispatcher->Close();
130 } 126 }
131 127
132 MojoResult CoreImpl::Wait(MojoHandle handle, 128 MojoResult CoreImpl::Wait(MojoHandle handle,
(...skipping 20 matching lines...) Expand all
153 MojoResult CoreImpl::CreateMessagePipe(MojoHandle* message_pipe_handle0, 149 MojoResult CoreImpl::CreateMessagePipe(MojoHandle* message_pipe_handle0,
154 MojoHandle* message_pipe_handle1) { 150 MojoHandle* message_pipe_handle1) {
155 if (!VerifyUserPointer<MojoHandle>(message_pipe_handle0, 1)) 151 if (!VerifyUserPointer<MojoHandle>(message_pipe_handle0, 1))
156 return MOJO_RESULT_INVALID_ARGUMENT; 152 return MOJO_RESULT_INVALID_ARGUMENT;
157 if (!VerifyUserPointer<MojoHandle>(message_pipe_handle1, 1)) 153 if (!VerifyUserPointer<MojoHandle>(message_pipe_handle1, 1))
158 return MOJO_RESULT_INVALID_ARGUMENT; 154 return MOJO_RESULT_INVALID_ARGUMENT;
159 155
160 scoped_refptr<MessagePipeDispatcher> dispatcher0(new MessagePipeDispatcher()); 156 scoped_refptr<MessagePipeDispatcher> dispatcher0(new MessagePipeDispatcher());
161 scoped_refptr<MessagePipeDispatcher> dispatcher1(new MessagePipeDispatcher()); 157 scoped_refptr<MessagePipeDispatcher> dispatcher1(new MessagePipeDispatcher());
162 158
163 MojoHandle h0, h1; 159 std::pair<MojoHandle, MojoHandle> handle_pair;
164 { 160 {
165 base::AutoLock locker(handle_table_lock_); 161 base::AutoLock locker(handle_table_lock_);
166 162 handle_pair = handle_table_.AddDispatcherPair(dispatcher0, dispatcher1);
167 // TODO(vtl): crbug.com/345911: On failure, we should close the dispatcher 163 }
168 // (outside the table lock). 164 if (handle_pair.first == MOJO_HANDLE_INVALID) {
169 h0 = AddDispatcherNoLock(dispatcher0); 165 DCHECK_EQ(handle_pair.second, MOJO_HANDLE_INVALID);
170 if (h0 == MOJO_HANDLE_INVALID) 166 LOG(ERROR) << "Handle table full";
171 return MOJO_RESULT_RESOURCE_EXHAUSTED; 167 dispatcher0->Close();
172 168 dispatcher1->Close();
173 // TODO(vtl): crbug.com/345911: On failure, we should close both dispatchers 169 return MOJO_RESULT_RESOURCE_EXHAUSTED;
174 // (outside the table lock).
175 h1 = AddDispatcherNoLock(dispatcher1);
176 if (h1 == MOJO_HANDLE_INVALID) {
177 handle_table_.erase(h0);
178 return MOJO_RESULT_RESOURCE_EXHAUSTED;
179 }
180 } 170 }
181 171
182 scoped_refptr<MessagePipe> message_pipe(new MessagePipe()); 172 scoped_refptr<MessagePipe> message_pipe(new MessagePipe());
183 dispatcher0->Init(message_pipe, 0); 173 dispatcher0->Init(message_pipe, 0);
184 dispatcher1->Init(message_pipe, 1); 174 dispatcher1->Init(message_pipe, 1);
185 175
186 *message_pipe_handle0 = h0; 176 *message_pipe_handle0 = handle_pair.first;
187 *message_pipe_handle1 = h1; 177 *message_pipe_handle1 = handle_pair.second;
188 return MOJO_RESULT_OK; 178 return MOJO_RESULT_OK;
189 } 179 }
190 180
191 // Implementation note: To properly cancel waiters and avoid other races, this 181 // Implementation note: To properly cancel waiters and avoid other races, this
192 // does not transfer dispatchers from one handle to another, even when sending a 182 // does not transfer dispatchers from one handle to another, even when sending a
193 // message in-process. Instead, it must transfer the "contents" of the 183 // message in-process. Instead, it must transfer the "contents" of the
194 // dispatcher to a new dispatcher, and then close the old dispatcher. If this 184 // dispatcher to a new dispatcher, and then close the old dispatcher. If this
195 // isn't done, in the in-process case, calls on the old handle may complete 185 // isn't done, in the in-process case, calls on the old handle may complete
196 // after the the message has been received and a new handle created (and 186 // after the the message has been received and a new handle created (and
197 // possibly even after calls have been made on the new handle). 187 // possibly even after calls have been made on the new handle).
(...skipping 29 matching lines...) Expand all
227 // without accessing the handle table. These can be dumb pointers, since their 217 // without accessing the handle table. These can be dumb pointers, since their
228 // entries in the handle table won't get removed (since they'll be marked as 218 // entries in the handle table won't get removed (since they'll be marked as
229 // busy). 219 // busy).
230 std::vector<DispatcherTransport> transports(num_handles); 220 std::vector<DispatcherTransport> transports(num_handles);
231 221
232 // When we pass handles, we have to try to take all their dispatchers' locks 222 // When we pass handles, we have to try to take all their dispatchers' locks
233 // and mark the handles as busy. If the call succeeds, we then remove the 223 // and mark the handles as busy. If the call succeeds, we then remove the
234 // handles from the handle table. 224 // handles from the handle table.
235 { 225 {
236 base::AutoLock locker(handle_table_lock_); 226 base::AutoLock locker(handle_table_lock_);
237 227 MojoResult result = handle_table_.MarkBusyAndStartTransport(
238 std::vector<HandleTableEntry*> entries(num_handles); 228 message_pipe_handle, handles, num_handles, &transports);
239 229 if (result != MOJO_RESULT_OK)
240 // First verify all the handles and get their dispatchers. 230 return result;
241 uint32_t i;
242 MojoResult error_result = MOJO_RESULT_INTERNAL;
243 for (i = 0; i < num_handles; i++) {
244 // Sending your own handle is not allowed (and, for consistency, returns
245 // "busy").
246 if (handles[i] == message_pipe_handle) {
247 error_result = MOJO_RESULT_BUSY;
248 break;
249 }
250
251 HandleTableMap::iterator it = handle_table_.find(handles[i]);
252 if (it == handle_table_.end()) {
253 error_result = MOJO_RESULT_INVALID_ARGUMENT;
254 break;
255 }
256
257 entries[i] = &it->second;
258 if (entries[i]->busy) {
259 error_result = MOJO_RESULT_BUSY;
260 break;
261 }
262 // Note: By marking the handle as busy here, we're also preventing the
263 // same handle from being sent multiple times in the same message.
264 entries[i]->busy = true;
265
266 // Try to start the transport.
267 DispatcherTransport transport =
268 Dispatcher::CoreImplAccess::TryStartTransport(
269 entries[i]->dispatcher.get());
270 if (!transport.is_valid()) {
271 // Unset the busy flag (since it won't be unset below).
272 entries[i]->busy = false;
273 error_result = MOJO_RESULT_BUSY;
274 break;
275 }
276
277 // Check if the dispatcher is busy (e.g., in a two-phase read/write).
278 // (Note that this must be done after the dispatcher's lock is acquired.)
279 if (transport.IsBusy()) {
280 // Unset the busy flag and end the transport (since it won't be done
281 // below).
282 entries[i]->busy = false;
283 transport.End();
284 error_result = MOJO_RESULT_BUSY;
285 break;
286 }
287
288 // Hang on to the transport (which we'll need to end the transport).
289 transports[i] = transport;
290 }
291 if (i < num_handles) {
292 DCHECK_NE(error_result, MOJO_RESULT_INTERNAL);
293
294 // Unset the busy flags and release the locks.
295 for (uint32_t j = 0; j < i; j++) {
296 DCHECK(entries[j]->busy);
297 entries[j]->busy = false;
298 transports[j].End();
299 }
300 return error_result;
301 }
302 } 231 }
303 232
304 MojoResult rv = dispatcher->WriteMessage(bytes, num_bytes, &transports, 233 MojoResult rv = dispatcher->WriteMessage(bytes, num_bytes, &transports,
305 flags); 234 flags);
306 235
307 // We need to release the dispatcher locks before we take the handle table 236 // We need to release the dispatcher locks before we take the handle table
308 // lock. 237 // lock.
309 for (uint32_t i = 0; i < num_handles; i++) 238 for (uint32_t i = 0; i < num_handles; i++)
310 transports[i].End(); 239 transports[i].End();
311 240
312 if (rv == MOJO_RESULT_OK) { 241 {
313 base::AutoLock locker(handle_table_lock_); 242 base::AutoLock locker(handle_table_lock_);
314 243 if (rv == MOJO_RESULT_OK)
315 // Succeeded, so the handles should be removed from the handle table. (The 244 handle_table_.RemoveBusyHandles(handles, num_handles);
316 // transferring to new dispatchers/closing must have already been done.) 245 else
317 for (uint32_t i = 0; i < num_handles; i++) { 246 handle_table_.RestoreBusyHandles(handles, num_handles);
318 HandleTableMap::iterator it = handle_table_.find(handles[i]);
319 DCHECK(it != handle_table_.end());
320 DCHECK(it->second.busy);
321 it->second.busy = false; // For the sake of a |DCHECK()|.
322 handle_table_.erase(it);
323 }
324 } else {
325 base::AutoLock locker(handle_table_lock_);
326
327 // Failed, so the handles should go back to their normal state.
328 for (uint32_t i = 0; i < num_handles; i++) {
329 HandleTableMap::iterator it = handle_table_.find(handles[i]);
330 DCHECK(it != handle_table_.end());
331 DCHECK(it->second.busy);
332 it->second.busy = false;
333 }
334 } 247 }
335 248
336 return rv; 249 return rv;
337 } 250 }
338 251
339 MojoResult CoreImpl::ReadMessage(MojoHandle message_pipe_handle, 252 MojoResult CoreImpl::ReadMessage(MojoHandle message_pipe_handle,
340 void* bytes, 253 void* bytes,
341 uint32_t* num_bytes, 254 uint32_t* num_bytes,
342 MojoHandle* handles, 255 MojoHandle* handles,
343 uint32_t* num_handles, 256 uint32_t* num_handles,
(...skipping 15 matching lines...) Expand all
359 272
360 std::vector<scoped_refptr<Dispatcher> > dispatchers; 273 std::vector<scoped_refptr<Dispatcher> > dispatchers;
361 MojoResult rv = dispatcher->ReadMessage(bytes, num_bytes, 274 MojoResult rv = dispatcher->ReadMessage(bytes, num_bytes,
362 &dispatchers, num_handles, 275 &dispatchers, num_handles,
363 flags); 276 flags);
364 if (!dispatchers.empty()) { 277 if (!dispatchers.empty()) {
365 DCHECK_EQ(rv, MOJO_RESULT_OK); 278 DCHECK_EQ(rv, MOJO_RESULT_OK);
366 DCHECK(num_handles); 279 DCHECK(num_handles);
367 DCHECK_LE(dispatchers.size(), static_cast<size_t>(*num_handles)); 280 DCHECK_LE(dispatchers.size(), static_cast<size_t>(*num_handles));
368 281
369 base::AutoLock locker(handle_table_lock_); 282 bool success;
370 283 {
371 for (size_t i = 0; i < dispatchers.size(); i++) { 284 base::AutoLock locker(handle_table_lock_);
372 // TODO(vtl): What should we do if we hit the maximum handle table size 285 success = handle_table_.AddDispatcherVector(dispatchers, handles);
373 // here? Currently, we'll just fill in those handles with 286 }
374 // |MOJO_HANDLE_INVALID| (and return success anyway). 287 if (!success) {
375 // TODO(vtl): crbug.com/345911: On failure, we should close the dispatcher 288 LOG(ERROR) << "Received message with " << dispatchers.size()
376 // (outside the table lock). 289 << " handles, but handle table full";
377 handles[i] = AddDispatcherNoLock(dispatchers[i]); 290 // Close dispatchers (outside the lock).
378 LOG_IF(ERROR, handles[i] == MOJO_HANDLE_INVALID) 291 for (size_t i = 0; i < dispatchers.size(); i++) {
379 << "Failed to add dispatcher (" << dispatchers[i].get() << ")"; 292 if (dispatchers[i])
293 dispatchers[i]->Close();
294 }
380 } 295 }
381 } 296 }
382 297
383 return rv; 298 return rv;
384 } 299 }
385 300
386 MojoResult CoreImpl::CreateDataPipe(const MojoCreateDataPipeOptions* options, 301 MojoResult CoreImpl::CreateDataPipe(const MojoCreateDataPipeOptions* options,
387 MojoHandle* data_pipe_producer_handle, 302 MojoHandle* data_pipe_producer_handle,
388 MojoHandle* data_pipe_consumer_handle) { 303 MojoHandle* data_pipe_consumer_handle) {
389 if (options) { 304 if (options) {
(...skipping 12 matching lines...) Expand all
402 MojoCreateDataPipeOptions validated_options = { 0 }; 317 MojoCreateDataPipeOptions validated_options = { 0 };
403 MojoResult result = DataPipe::ValidateOptions(options, &validated_options); 318 MojoResult result = DataPipe::ValidateOptions(options, &validated_options);
404 if (result != MOJO_RESULT_OK) 319 if (result != MOJO_RESULT_OK)
405 return result; 320 return result;
406 321
407 scoped_refptr<DataPipeProducerDispatcher> producer_dispatcher( 322 scoped_refptr<DataPipeProducerDispatcher> producer_dispatcher(
408 new DataPipeProducerDispatcher()); 323 new DataPipeProducerDispatcher());
409 scoped_refptr<DataPipeConsumerDispatcher> consumer_dispatcher( 324 scoped_refptr<DataPipeConsumerDispatcher> consumer_dispatcher(
410 new DataPipeConsumerDispatcher()); 325 new DataPipeConsumerDispatcher());
411 326
412 MojoHandle producer_handle, consumer_handle; 327 std::pair<MojoHandle, MojoHandle> handle_pair;
413 { 328 {
414 base::AutoLock locker(handle_table_lock_); 329 base::AutoLock locker(handle_table_lock_);
415 330 handle_pair = handle_table_.AddDispatcherPair(producer_dispatcher,
416 // TODO(vtl): crbug.com/345911: On failure, we should close the dispatcher 331 consumer_dispatcher);
417 // (outside the table lock).
418 producer_handle = AddDispatcherNoLock(producer_dispatcher);
419 if (producer_handle == MOJO_HANDLE_INVALID)
420 return MOJO_RESULT_RESOURCE_EXHAUSTED;
421
422 // TODO(vtl): crbug.com/345911: On failure, we should close both dispatchers
423 // (outside the table lock).
424 consumer_handle = AddDispatcherNoLock(consumer_dispatcher);
425 if (consumer_handle == MOJO_HANDLE_INVALID) {
426 handle_table_.erase(producer_handle);
427 return MOJO_RESULT_RESOURCE_EXHAUSTED;
428 }
429 } 332 }
333 if (handle_pair.first == MOJO_HANDLE_INVALID) {
334 DCHECK_EQ(handle_pair.second, MOJO_HANDLE_INVALID);
335 LOG(ERROR) << "Handle table full";
336 producer_dispatcher->Close();
337 consumer_dispatcher->Close();
338 return MOJO_RESULT_RESOURCE_EXHAUSTED;
339 }
340 DCHECK_NE(handle_pair.second, MOJO_HANDLE_INVALID);
430 341
431 scoped_refptr<DataPipe> data_pipe(new LocalDataPipe(validated_options)); 342 scoped_refptr<DataPipe> data_pipe(new LocalDataPipe(validated_options));
432 producer_dispatcher->Init(data_pipe); 343 producer_dispatcher->Init(data_pipe);
433 consumer_dispatcher->Init(data_pipe); 344 consumer_dispatcher->Init(data_pipe);
434 345
435 *data_pipe_producer_handle = producer_handle; 346 *data_pipe_producer_handle = handle_pair.first;
436 *data_pipe_consumer_handle = consumer_handle; 347 *data_pipe_consumer_handle = handle_pair.second;
437 return MOJO_RESULT_OK; 348 return MOJO_RESULT_OK;
438 } 349 }
439 350
440 MojoResult CoreImpl::WriteData(MojoHandle data_pipe_producer_handle, 351 MojoResult CoreImpl::WriteData(MojoHandle data_pipe_producer_handle,
441 const void* elements, 352 const void* elements,
442 uint32_t* num_bytes, 353 uint32_t* num_bytes,
443 MojoWriteDataFlags flags) { 354 MojoWriteDataFlags flags) {
444 scoped_refptr<Dispatcher> dispatcher( 355 scoped_refptr<Dispatcher> dispatcher(
445 GetDispatcher(data_pipe_producer_handle)); 356 GetDispatcher(data_pipe_producer_handle));
446 if (!dispatcher.get()) 357 if (!dispatcher.get())
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
527 return result; 438 return result;
528 439
529 scoped_refptr<SharedBufferDispatcher> dispatcher; 440 scoped_refptr<SharedBufferDispatcher> dispatcher;
530 result = SharedBufferDispatcher::Create(validated_options, num_bytes, 441 result = SharedBufferDispatcher::Create(validated_options, num_bytes,
531 &dispatcher); 442 &dispatcher);
532 if (result != MOJO_RESULT_OK) { 443 if (result != MOJO_RESULT_OK) {
533 DCHECK(!dispatcher); 444 DCHECK(!dispatcher);
534 return result; 445 return result;
535 } 446 }
536 447
537 MojoHandle h; 448 MojoHandle h = AddDispatcher(dispatcher);
538 { 449 if (h == MOJO_HANDLE_INVALID) {
539 base::AutoLock locker(handle_table_lock_); 450 LOG(ERROR) << "Handle table full";
540 451 dispatcher->Close();
541 // TODO(vtl): crbug.com/345911: On failure, we should close the dispatcher 452 return MOJO_RESULT_RESOURCE_EXHAUSTED;
542 // (outside the table lock).
543 h = AddDispatcherNoLock(dispatcher);
544 if (h == MOJO_HANDLE_INVALID)
545 return MOJO_RESULT_RESOURCE_EXHAUSTED;
546 } 453 }
547 454
548 *shared_buffer_handle = h; 455 *shared_buffer_handle = h;
549 return MOJO_RESULT_OK; 456 return MOJO_RESULT_OK;
550 } 457 }
551 458
552 MojoResult CoreImpl::DuplicateBufferHandle( 459 MojoResult CoreImpl::DuplicateBufferHandle(
553 MojoHandle buffer_handle, 460 MojoHandle buffer_handle,
554 const MojoDuplicateBufferHandleOptions* options, 461 const MojoDuplicateBufferHandleOptions* options,
555 MojoHandle* new_buffer_handle) { 462 MojoHandle* new_buffer_handle) {
556 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle)); 463 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
557 if (!dispatcher.get()) 464 if (!dispatcher.get())
558 return MOJO_RESULT_INVALID_ARGUMENT; 465 return MOJO_RESULT_INVALID_ARGUMENT;
559 466
560 // Don't verify |options| here; that's the dispatcher's job. 467 // Don't verify |options| here; that's the dispatcher's job.
561 if (!VerifyUserPointer<MojoHandle>(new_buffer_handle, 1)) 468 if (!VerifyUserPointer<MojoHandle>(new_buffer_handle, 1))
562 return MOJO_RESULT_INVALID_ARGUMENT; 469 return MOJO_RESULT_INVALID_ARGUMENT;
563 470
564 scoped_refptr<Dispatcher> new_dispatcher; 471 scoped_refptr<Dispatcher> new_dispatcher;
565 MojoResult result = dispatcher->DuplicateBufferHandle(options, 472 MojoResult result = dispatcher->DuplicateBufferHandle(options,
566 &new_dispatcher); 473 &new_dispatcher);
567 if (result != MOJO_RESULT_OK) 474 if (result != MOJO_RESULT_OK)
568 return result; 475 return result;
569 476
570 MojoHandle new_handle; 477 MojoHandle new_handle = AddDispatcher(new_dispatcher);
571 { 478 if (new_handle == MOJO_HANDLE_INVALID) {
572 base::AutoLock locker(handle_table_lock_); 479 LOG(ERROR) << "Handle table full";
573 480 dispatcher->Close();
574 // TODO(vtl): crbug.com/345911: On failure, we should close the dispatcher 481 return MOJO_RESULT_RESOURCE_EXHAUSTED;
575 // (outside the table lock).
576 new_handle = AddDispatcherNoLock(new_dispatcher);
577 if (new_handle == MOJO_HANDLE_INVALID)
578 return MOJO_RESULT_RESOURCE_EXHAUSTED;
579 } 482 }
580 483
581 *new_buffer_handle = new_handle; 484 *new_buffer_handle = new_handle;
582 return MOJO_RESULT_OK; 485 return MOJO_RESULT_OK;
583 } 486 }
584 487
585 MojoResult CoreImpl::MapBuffer(MojoHandle buffer_handle, 488 MojoResult CoreImpl::MapBuffer(MojoHandle buffer_handle,
586 uint64_t offset, 489 uint64_t offset,
587 uint64_t num_bytes, 490 uint64_t num_bytes,
588 void** buffer, 491 void** buffer,
(...skipping 24 matching lines...) Expand all
613 // TODO(vtl): FIXME 516 // TODO(vtl): FIXME
614 NOTIMPLEMENTED(); 517 NOTIMPLEMENTED();
615 return MOJO_RESULT_UNIMPLEMENTED; 518 return MOJO_RESULT_UNIMPLEMENTED;
616 } 519 }
617 520
618 scoped_refptr<Dispatcher> CoreImpl::GetDispatcher(MojoHandle handle) { 521 scoped_refptr<Dispatcher> CoreImpl::GetDispatcher(MojoHandle handle) {
619 if (handle == MOJO_HANDLE_INVALID) 522 if (handle == MOJO_HANDLE_INVALID)
620 return NULL; 523 return NULL;
621 524
622 base::AutoLock locker(handle_table_lock_); 525 base::AutoLock locker(handle_table_lock_);
623 HandleTableMap::iterator it = handle_table_.find(handle); 526 return handle_table_.GetDispatcher(handle);
624 if (it == handle_table_.end())
625 return NULL;
626
627 return it->second.dispatcher;
628 }
629
630 MojoHandle CoreImpl::AddDispatcherNoLock(
631 const scoped_refptr<Dispatcher>& dispatcher) {
632 handle_table_lock_.AssertAcquired();
633 DCHECK_NE(next_handle_, MOJO_HANDLE_INVALID);
634
635 if (!dispatcher.get() || handle_table_.size() >= kMaxHandleTableSize)
636 return MOJO_HANDLE_INVALID;
637
638 // TODO(vtl): Maybe we want to do something different/smarter. (Or maybe try
639 // assigning randomly?)
640 while (handle_table_.find(next_handle_) != handle_table_.end()) {
641 next_handle_++;
642 if (next_handle_ == MOJO_HANDLE_INVALID)
643 next_handle_++;
644 }
645
646 MojoHandle new_handle = next_handle_;
647 handle_table_[new_handle] = HandleTableEntry(dispatcher);
648
649 next_handle_++;
650 if (next_handle_ == MOJO_HANDLE_INVALID)
651 next_handle_++;
652
653 return new_handle;
654 } 527 }
655 528
656 // Note: We allow |handles| to repeat the same handle multiple times, since 529 // Note: We allow |handles| to repeat the same handle multiple times, since
657 // different flags may be specified. 530 // different flags may be specified.
658 // TODO(vtl): This incurs a performance cost in |RemoveWaiter()|. Analyze this 531 // TODO(vtl): This incurs a performance cost in |RemoveWaiter()|. Analyze this
659 // more carefully and address it if necessary. 532 // more carefully and address it if necessary.
660 MojoResult CoreImpl::WaitManyInternal(const MojoHandle* handles, 533 MojoResult CoreImpl::WaitManyInternal(const MojoHandle* handles,
661 const MojoWaitFlags* flags, 534 const MojoWaitFlags* flags,
662 uint32_t num_handles, 535 uint32_t num_handles,
663 MojoDeadline deadline) { 536 MojoDeadline deadline) {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
696 // |Wait()|/|WaitMany()| call. (Only after doing this can |waiter| be 569 // |Wait()|/|WaitMany()| call. (Only after doing this can |waiter| be
697 // destroyed, but this would still be required if the waiter were in TLS.) 570 // destroyed, but this would still be required if the waiter were in TLS.)
698 for (i = 0; i < num_added; i++) 571 for (i = 0; i < num_added; i++)
699 dispatchers[i]->RemoveWaiter(&waiter); 572 dispatchers[i]->RemoveWaiter(&waiter);
700 573
701 return rv; 574 return rv;
702 } 575 }
703 576
704 } // namespace system 577 } // namespace system
705 } // namespace mojo 578 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/system/core_impl.h ('k') | mojo/system/dispatcher.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698