| 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 |