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/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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |