| 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/edk/system/core.h" | 5 #include "mojo/edk/system/core.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <string.h> |
| 8 #include <stdint.h> | |
| 9 | 8 |
| 10 #include <utility> | 9 #include <utility> |
| 11 #include <vector> | |
| 12 | 10 |
| 11 #include "base/bind.h" |
| 13 #include "base/containers/stack_container.h" | 12 #include "base/containers/stack_container.h" |
| 13 #include "base/location.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/macros.h" |
| 16 #include "base/message_loop/message_loop.h" |
| 15 #include "base/rand_util.h" | 17 #include "base/rand_util.h" |
| 18 #include "base/thread_task_runner_handle.h" |
| 16 #include "base/time/time.h" | 19 #include "base/time/time.h" |
| 20 #include "crypto/random.h" |
| 21 #include "mojo/edk/embedder/embedder.h" |
| 17 #include "mojo/edk/embedder/embedder_internal.h" | 22 #include "mojo/edk/embedder/embedder_internal.h" |
| 18 #include "mojo/edk/embedder/platform_channel_pair.h" | |
| 19 #include "mojo/edk/embedder/platform_shared_buffer.h" | 23 #include "mojo/edk/embedder/platform_shared_buffer.h" |
| 20 #include "mojo/edk/embedder/platform_support.h" | 24 #include "mojo/edk/embedder/platform_support.h" |
| 21 #include "mojo/edk/system/async_waiter.h" | 25 #include "mojo/edk/system/async_waiter.h" |
| 22 #include "mojo/edk/system/broker.h" | 26 #include "mojo/edk/system/channel.h" |
| 23 #include "mojo/edk/system/configuration.h" | 27 #include "mojo/edk/system/configuration.h" |
| 24 #include "mojo/edk/system/data_pipe.h" | |
| 25 #include "mojo/edk/system/data_pipe_consumer_dispatcher.h" | 28 #include "mojo/edk/system/data_pipe_consumer_dispatcher.h" |
| 26 #include "mojo/edk/system/data_pipe_producer_dispatcher.h" | 29 #include "mojo/edk/system/data_pipe_producer_dispatcher.h" |
| 27 #include "mojo/edk/system/dispatcher.h" | |
| 28 #include "mojo/edk/system/handle_signals_state.h" | 30 #include "mojo/edk/system/handle_signals_state.h" |
| 29 #include "mojo/edk/system/message_pipe_dispatcher.h" | 31 #include "mojo/edk/system/message_pipe_dispatcher.h" |
| 32 #include "mojo/edk/system/platform_handle_dispatcher.h" |
| 33 #include "mojo/edk/system/ports/node.h" |
| 34 #include "mojo/edk/system/remote_message_pipe_bootstrap.h" |
| 30 #include "mojo/edk/system/shared_buffer_dispatcher.h" | 35 #include "mojo/edk/system/shared_buffer_dispatcher.h" |
| 31 #include "mojo/edk/system/wait_set_dispatcher.h" | 36 #include "mojo/edk/system/wait_set_dispatcher.h" |
| 32 #include "mojo/edk/system/waiter.h" | 37 #include "mojo/edk/system/waiter.h" |
| 33 #include "mojo/public/c/system/macros.h" | |
| 34 #include "mojo/public/cpp/system/macros.h" | |
| 35 | 38 |
| 36 namespace mojo { | 39 namespace mojo { |
| 37 namespace edk { | 40 namespace edk { |
| 38 | 41 |
| 39 // Implementation notes | 42 namespace { |
| 40 // | |
| 41 // Mojo primitives are implemented by the singleton |Core| object. Most calls | |
| 42 // are for a "primary" handle (the first argument). |Core::GetDispatcher()| is | |
| 43 // used to look up a |Dispatcher| object for a given handle. That object | |
| 44 // implements most primitives for that object. The wait primitives are not | |
| 45 // attached to objects and are implemented by |Core| itself. | |
| 46 // | |
| 47 // Some objects have multiple handles associated to them, e.g., message pipes | |
| 48 // (which have two). In such a case, there is still a |Dispatcher| (e.g., | |
| 49 // |MessagePipeDispatcher|) for each handle, with each handle having a strong | |
| 50 // reference to the common "secondary" object (e.g., |MessagePipe|). This | |
| 51 // secondary object does NOT have any references to the |Dispatcher|s (even if | |
| 52 // it did, it wouldn't be able to do anything with them due to lock order | |
| 53 // requirements -- see below). | |
| 54 // | |
| 55 // Waiting is implemented by having the thread that wants to wait call the | |
| 56 // |Dispatcher|s for the handles that it wants to wait on with a |Waiter| | |
| 57 // object; this |Waiter| object may be created on the stack of that thread or be | |
| 58 // kept in thread local storage for that thread (TODO(vtl): future improvement). | |
| 59 // The |Dispatcher| then adds the |Waiter| to an |AwakableList| that's either | |
| 60 // owned by that |Dispatcher| (see |SimpleDispatcher|) or by a secondary object | |
| 61 // (e.g., |MessagePipe|). To signal/wake a |Waiter|, the object in question -- | |
| 62 // either a |SimpleDispatcher| or a secondary object -- talks to its | |
| 63 // |AwakableList|. | |
| 64 | 43 |
| 65 // Thread-safety notes | 44 // This is an unnecessarily large limit that is relatively easy to enforce. |
| 66 // | 45 const uint32_t kMaxHandlesPerMessage = 1024 * 1024; |
| 67 // Mojo primitives calls are thread-safe. We achieve this with relatively | |
| 68 // fine-grained locking. There is a global handle table lock. This lock should | |
| 69 // be held as briefly as possible (TODO(vtl): a future improvement would be to | |
| 70 // switch it to a reader-writer lock). Each |Dispatcher| object then has a lock | |
| 71 // (which subclasses can use to protect their data). | |
| 72 // | |
| 73 // The lock ordering is as follows: | |
| 74 // 1. global handle table lock, global mapping table lock | |
| 75 // 2. |Dispatcher| locks | |
| 76 // 3. secondary object locks | |
| 77 // ... | |
| 78 // INF. |Waiter| locks | |
| 79 // | |
| 80 // Notes: | |
| 81 // - While holding a |Dispatcher| lock, you may not unconditionally attempt | |
| 82 // to take another |Dispatcher| lock. (This has consequences on the | |
| 83 // concurrency semantics of |MojoWriteMessage()| when passing handles.) | |
| 84 // Doing so would lead to deadlock. | |
| 85 // - Locks at the "INF" level may not have any locks taken while they are | |
| 86 // held. | |
| 87 | 46 |
| 88 // TODO(vtl): This should take a |scoped_ptr<PlatformSupport>| as a parameter. | 47 void OnPortConnected( |
| 89 Core::Core(PlatformSupport* platform_support) | 48 Core* core, |
| 90 : platform_support_(platform_support) { | 49 int endpoint, |
| 50 const base::Callback<void(ScopedMessagePipeHandle)>& callback, |
| 51 const ports::PortRef& port) { |
| 52 // TODO: Maybe we could negotiate a pipe ID for cross-process pipes too; |
| 53 // for now we just use 0x7F7F7F7F7F7F7F7F. In practice these are used for |
| 54 // bootstrap and aren't passed around, so tracking them is less important. |
| 55 MojoHandle handle = core->AddDispatcher( |
| 56 new MessagePipeDispatcher(core->GetNodeController(), port, |
| 57 0x7f7f7f7f7f7f7f7fUL, endpoint)); |
| 58 callback.Run(ScopedMessagePipeHandle(MessagePipeHandle(handle))); |
| 91 } | 59 } |
| 92 | 60 |
| 61 } // namespace |
| 62 |
| 63 Core::Core() {} |
| 64 |
| 93 Core::~Core() { | 65 Core::~Core() { |
| 66 if (node_controller_ && node_controller_->io_task_runner()) { |
| 67 // If this races with IO thread shutdown the callback will be dropped and |
| 68 // the NodeController will be shutdown on this thread anyway, which is also |
| 69 // just fine. |
| 70 scoped_refptr<base::TaskRunner> io_task_runner = |
| 71 node_controller_->io_task_runner(); |
| 72 io_task_runner->PostTask(FROM_HERE, |
| 73 base::Bind(&Core::PassNodeControllerToIOThread, |
| 74 base::Passed(&node_controller_))); |
| 75 } |
| 94 } | 76 } |
| 95 | 77 |
| 96 MojoHandle Core::AddDispatcher(const scoped_refptr<Dispatcher>& dispatcher) { | 78 void Core::SetIOTaskRunner(scoped_refptr<base::TaskRunner> io_task_runner) { |
| 97 base::AutoLock locker(handle_table_lock_); | 79 GetNodeController()->SetIOTaskRunner(io_task_runner); |
| 98 return handle_table_.AddDispatcher(dispatcher); | 80 } |
| 81 |
| 82 NodeController* Core::GetNodeController() { |
| 83 if (!node_controller_) |
| 84 node_controller_.reset(new NodeController(this)); |
| 85 return node_controller_.get(); |
| 99 } | 86 } |
| 100 | 87 |
| 101 scoped_refptr<Dispatcher> Core::GetDispatcher(MojoHandle handle) { | 88 scoped_refptr<Dispatcher> Core::GetDispatcher(MojoHandle handle) { |
| 102 if (handle == MOJO_HANDLE_INVALID) | 89 base::AutoLock lock(handles_lock_); |
| 103 return nullptr; | 90 return handles_.GetDispatcher(handle); |
| 91 } |
| 104 | 92 |
| 105 base::AutoLock locker(handle_table_lock_); | 93 void Core::AddChild(base::ProcessHandle process_handle, |
| 106 return handle_table_.GetDispatcher(handle); | 94 ScopedPlatformHandle platform_handle) { |
| 95 GetNodeController()->ConnectToChild(process_handle, |
| 96 std::move(platform_handle)); |
| 97 } |
| 98 |
| 99 void Core::InitChild(ScopedPlatformHandle platform_handle) { |
| 100 GetNodeController()->ConnectToParent(std::move(platform_handle)); |
| 101 } |
| 102 |
| 103 MojoHandle Core::AddDispatcher(scoped_refptr<Dispatcher> dispatcher) { |
| 104 base::AutoLock lock(handles_lock_); |
| 105 return handles_.AddDispatcher(dispatcher); |
| 106 } |
| 107 |
| 108 bool Core::AddDispatchersFromTransit( |
| 109 const std::vector<Dispatcher::DispatcherInTransit>& dispatchers, |
| 110 MojoHandle* handles) { |
| 111 bool failed = false; |
| 112 { |
| 113 base::AutoLock lock(handles_lock_); |
| 114 if (!handles_.AddDispatchersFromTransit(dispatchers, handles)) |
| 115 failed = true; |
| 116 } |
| 117 if (failed) { |
| 118 for (auto d : dispatchers) |
| 119 d.dispatcher->Close(); |
| 120 return false; |
| 121 } |
| 122 return true; |
| 123 } |
| 124 |
| 125 MojoResult Core::CreatePlatformHandleWrapper( |
| 126 ScopedPlatformHandle platform_handle, |
| 127 MojoHandle* wrapper_handle) { |
| 128 MojoHandle h = AddDispatcher( |
| 129 PlatformHandleDispatcher::Create(std::move(platform_handle))); |
| 130 if (h == MOJO_HANDLE_INVALID) |
| 131 return MOJO_RESULT_RESOURCE_EXHAUSTED; |
| 132 *wrapper_handle = h; |
| 133 return MOJO_RESULT_OK; |
| 134 } |
| 135 |
| 136 MojoResult Core::PassWrappedPlatformHandle( |
| 137 MojoHandle wrapper_handle, |
| 138 ScopedPlatformHandle* platform_handle) { |
| 139 base::AutoLock lock(handles_lock_); |
| 140 scoped_refptr<Dispatcher> d; |
| 141 MojoResult result = handles_.GetAndRemoveDispatcher(wrapper_handle, &d); |
| 142 if (result != MOJO_RESULT_OK) |
| 143 return result; |
| 144 PlatformHandleDispatcher* phd = |
| 145 static_cast<PlatformHandleDispatcher*>(d.get()); |
| 146 *platform_handle = phd->PassPlatformHandle(); |
| 147 phd->Close(); |
| 148 return MOJO_RESULT_OK; |
| 149 } |
| 150 |
| 151 void Core::RequestShutdown(const base::Closure& callback) { |
| 152 base::Closure on_shutdown; |
| 153 if (base::ThreadTaskRunnerHandle::IsSet()) { |
| 154 on_shutdown = base::Bind(base::IgnoreResult(&base::TaskRunner::PostTask), |
| 155 base::ThreadTaskRunnerHandle::Get(), |
| 156 FROM_HERE, callback); |
| 157 } else { |
| 158 on_shutdown = callback; |
| 159 } |
| 160 GetNodeController()->RequestShutdown(on_shutdown); |
| 161 } |
| 162 |
| 163 void Core::CreateParentMessagePipe( |
| 164 ScopedPlatformHandle platform_handle, |
| 165 const base::Callback<void(ScopedMessagePipeHandle)>& callback) { |
| 166 std::string token = GenerateRandomToken(); |
| 167 CreateParentMessagePipe(token, callback); |
| 168 RemoteMessagePipeBootstrap::CreateForParent( |
| 169 GetNodeController(), std::move(platform_handle), token); |
| 170 } |
| 171 |
| 172 void Core::CreateChildMessagePipe( |
| 173 ScopedPlatformHandle platform_handle, |
| 174 const base::Callback<void(ScopedMessagePipeHandle)>& callback) { |
| 175 ports::PortRef port; |
| 176 GetNodeController()->node()->CreateUninitializedPort(&port); |
| 177 RemoteMessagePipeBootstrap::CreateForChild( |
| 178 GetNodeController(), std::move(platform_handle), port, |
| 179 base::Bind(&OnPortConnected, base::Unretained(this), 1, callback, port)); |
| 180 } |
| 181 |
| 182 void Core::CreateParentMessagePipe( |
| 183 const std::string& token, |
| 184 const base::Callback<void(ScopedMessagePipeHandle)>& callback) { |
| 185 GetNodeController()->ReservePort( |
| 186 token, |
| 187 base::Bind(&OnPortConnected, base::Unretained(this), 0, callback)); |
| 188 } |
| 189 |
| 190 void Core::CreateChildMessagePipe( |
| 191 const std::string& token, |
| 192 const base::Callback<void(ScopedMessagePipeHandle)>& callback) { |
| 193 ports::PortRef port; |
| 194 GetNodeController()->node()->CreateUninitializedPort(&port); |
| 195 GetNodeController()->ConnectToParentPort( |
| 196 port, token, |
| 197 base::Bind(&OnPortConnected, base::Unretained(this), 1, callback, port)); |
| 107 } | 198 } |
| 108 | 199 |
| 109 MojoResult Core::AsyncWait(MojoHandle handle, | 200 MojoResult Core::AsyncWait(MojoHandle handle, |
| 110 MojoHandleSignals signals, | 201 MojoHandleSignals signals, |
| 111 const base::Callback<void(MojoResult)>& callback) { | 202 const base::Callback<void(MojoResult)>& callback) { |
| 112 scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle); | 203 scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle); |
| 113 DCHECK(dispatcher); | 204 DCHECK(dispatcher); |
| 114 | 205 |
| 115 scoped_ptr<AsyncWaiter> waiter = make_scoped_ptr(new AsyncWaiter(callback)); | 206 scoped_ptr<AsyncWaiter> waiter = make_scoped_ptr(new AsyncWaiter(callback)); |
| 116 MojoResult rv = dispatcher->AddAwakable(waiter.get(), signals, 0, nullptr); | 207 MojoResult rv = dispatcher->AddAwakable(waiter.get(), signals, 0, nullptr); |
| 117 if (rv == MOJO_RESULT_OK) | 208 if (rv == MOJO_RESULT_OK) |
| 118 ignore_result(waiter.release()); | 209 ignore_result(waiter.release()); |
| 119 return rv; | 210 return rv; |
| 120 } | 211 } |
| 121 | 212 |
| 122 MojoTimeTicks Core::GetTimeTicksNow() { | 213 MojoTimeTicks Core::GetTimeTicksNow() { |
| 123 return base::TimeTicks::Now().ToInternalValue(); | 214 return base::TimeTicks::Now().ToInternalValue(); |
| 124 } | 215 } |
| 125 | 216 |
| 126 MojoResult Core::Close(MojoHandle handle) { | 217 MojoResult Core::Close(MojoHandle handle) { |
| 127 if (handle == MOJO_HANDLE_INVALID) | |
| 128 return MOJO_RESULT_INVALID_ARGUMENT; | |
| 129 | |
| 130 scoped_refptr<Dispatcher> dispatcher; | 218 scoped_refptr<Dispatcher> dispatcher; |
| 131 { | 219 { |
| 132 base::AutoLock locker(handle_table_lock_); | 220 base::AutoLock lock(handles_lock_); |
| 133 MojoResult result = | 221 MojoResult rv = handles_.GetAndRemoveDispatcher(handle, &dispatcher); |
| 134 handle_table_.GetAndRemoveDispatcher(handle, &dispatcher); | 222 if (rv != MOJO_RESULT_OK) |
| 135 if (result != MOJO_RESULT_OK) | 223 return rv; |
| 136 return result; | |
| 137 } | 224 } |
| 138 | 225 dispatcher->Close(); |
| 139 // The dispatcher doesn't have a say in being closed, but gets notified of it. | 226 return MOJO_RESULT_OK; |
| 140 // Note: This is done outside of |handle_table_lock_|. As a result, there's a | |
| 141 // race condition that the dispatcher must handle; see the comment in | |
| 142 // |Dispatcher| in dispatcher.h. | |
| 143 return dispatcher->Close(); | |
| 144 } | 227 } |
| 145 | 228 |
| 146 MojoResult Core::Wait(MojoHandle handle, | 229 MojoResult Core::Wait(MojoHandle handle, |
| 147 MojoHandleSignals signals, | 230 MojoHandleSignals signals, |
| 148 MojoDeadline deadline, | 231 MojoDeadline deadline, |
| 149 MojoHandleSignalsState* signals_state) { | 232 MojoHandleSignalsState* signals_state) { |
| 150 uint32_t unused = static_cast<uint32_t>(-1); | 233 uint32_t unused = static_cast<uint32_t>(-1); |
| 151 HandleSignalsState hss; | 234 HandleSignalsState hss; |
| 152 MojoResult rv = WaitManyInternal(&handle, &signals, 1, deadline, &unused, | 235 MojoResult rv = WaitManyInternal(&handle, &signals, 1, deadline, &unused, |
| 153 signals_state ? &hss : nullptr); | 236 signals_state ? &hss : nullptr); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 if (!dispatcher) | 306 if (!dispatcher) |
| 224 return MOJO_RESULT_INVALID_ARGUMENT; | 307 return MOJO_RESULT_INVALID_ARGUMENT; |
| 225 | 308 |
| 226 return wait_set_dispatcher->RemoveWaitingDispatcher(dispatcher); | 309 return wait_set_dispatcher->RemoveWaitingDispatcher(dispatcher); |
| 227 } | 310 } |
| 228 | 311 |
| 229 MojoResult Core::GetReadyHandles(MojoHandle wait_set_handle, | 312 MojoResult Core::GetReadyHandles(MojoHandle wait_set_handle, |
| 230 uint32_t* count, | 313 uint32_t* count, |
| 231 MojoHandle* handles, | 314 MojoHandle* handles, |
| 232 MojoResult* results, | 315 MojoResult* results, |
| 233 MojoHandleSignalsState* signals_state) { | 316 MojoHandleSignalsState* signals_states) { |
| 234 if (!handles || !count || !(*count) || !results) | 317 if (!handles || !count || !(*count) || !results) |
| 235 return MOJO_RESULT_INVALID_ARGUMENT; | 318 return MOJO_RESULT_INVALID_ARGUMENT; |
| 236 | 319 |
| 237 scoped_refptr<Dispatcher> wait_set_dispatcher(GetDispatcher(wait_set_handle)); | 320 scoped_refptr<Dispatcher> wait_set_dispatcher(GetDispatcher(wait_set_handle)); |
| 238 if (!wait_set_dispatcher) | 321 if (!wait_set_dispatcher) |
| 239 return MOJO_RESULT_INVALID_ARGUMENT; | 322 return MOJO_RESULT_INVALID_ARGUMENT; |
| 240 | 323 |
| 241 DispatcherVector awoken_dispatchers; | 324 DispatcherVector awoken_dispatchers; |
| 242 base::StackVector<uintptr_t, 16> contexts; | 325 base::StackVector<uintptr_t, 16> contexts; |
| 243 contexts->assign(*count, MOJO_HANDLE_INVALID); | 326 contexts->assign(*count, MOJO_HANDLE_INVALID); |
| 244 | 327 |
| 245 MojoResult result = wait_set_dispatcher->GetReadyDispatchers( | 328 MojoResult result = wait_set_dispatcher->GetReadyDispatchers( |
| 246 count, &awoken_dispatchers, results, contexts->data()); | 329 count, &awoken_dispatchers, results, contexts->data()); |
| 247 | 330 |
| 248 if (result == MOJO_RESULT_OK) { | 331 if (result == MOJO_RESULT_OK) { |
| 249 for (size_t i = 0; i < *count; i++) { | 332 for (size_t i = 0; i < *count; i++) { |
| 250 handles[i] = static_cast<MojoHandle>(contexts[i]); | 333 handles[i] = static_cast<MojoHandle>(contexts[i]); |
| 251 if (signals_state) | 334 if (signals_states) |
| 252 signals_state[i] = awoken_dispatchers[i]->GetHandleSignalsState(); | 335 signals_states[i] = awoken_dispatchers[i]->GetHandleSignalsState(); |
| 253 } | 336 } |
| 254 } | 337 } |
| 255 | 338 |
| 256 return result; | 339 return result; |
| 257 } | 340 } |
| 258 | 341 |
| 259 MojoResult Core::CreateMessagePipe( | 342 MojoResult Core::CreateMessagePipe( |
| 260 const MojoCreateMessagePipeOptions* options, | 343 const MojoCreateMessagePipeOptions* options, |
| 261 MojoHandle* message_pipe_handle0, | 344 MojoHandle* message_pipe_handle0, |
| 262 MojoHandle* message_pipe_handle1) { | 345 MojoHandle* message_pipe_handle1) { |
| 346 ports::PortRef port0, port1; |
| 347 GetNodeController()->node()->CreatePortPair(&port0, &port1); |
| 348 |
| 263 CHECK(message_pipe_handle0); | 349 CHECK(message_pipe_handle0); |
| 264 CHECK(message_pipe_handle1); | 350 CHECK(message_pipe_handle1); |
| 265 MojoCreateMessagePipeOptions validated_options = {}; | |
| 266 MojoResult result = | |
| 267 MessagePipeDispatcher::ValidateCreateOptions(options, &validated_options); | |
| 268 if (result != MOJO_RESULT_OK) | |
| 269 return result; | |
| 270 | 351 |
| 271 scoped_refptr<MessagePipeDispatcher> dispatcher0 = | 352 uint64_t pipe_id = base::RandUint64(); |
| 272 MessagePipeDispatcher::Create(validated_options); | |
| 273 scoped_refptr<MessagePipeDispatcher> dispatcher1 = | |
| 274 MessagePipeDispatcher::Create(validated_options); | |
| 275 | 353 |
| 276 std::pair<MojoHandle, MojoHandle> handle_pair; | 354 *message_pipe_handle0 = AddDispatcher( |
| 277 { | 355 new MessagePipeDispatcher(GetNodeController(), port0, pipe_id, 0)); |
| 278 base::AutoLock locker(handle_table_lock_); | 356 if (*message_pipe_handle0 == MOJO_HANDLE_INVALID) |
| 279 handle_pair = handle_table_.AddDispatcherPair(dispatcher0, dispatcher1); | 357 return MOJO_RESULT_RESOURCE_EXHAUSTED; |
| 280 } | 358 |
| 281 if (handle_pair.first == MOJO_HANDLE_INVALID) { | 359 *message_pipe_handle1 = AddDispatcher( |
| 282 DCHECK_EQ(handle_pair.second, MOJO_HANDLE_INVALID); | 360 new MessagePipeDispatcher(GetNodeController(), port1, pipe_id, 1)); |
| 283 LOG(ERROR) << "Handle table full"; | 361 if (*message_pipe_handle1 == MOJO_HANDLE_INVALID) { |
| 284 dispatcher0->Close(); | 362 scoped_refptr<Dispatcher> unused; |
| 285 dispatcher1->Close(); | 363 unused->Close(); |
| 364 handles_.GetAndRemoveDispatcher(*message_pipe_handle0, &unused); |
| 286 return MOJO_RESULT_RESOURCE_EXHAUSTED; | 365 return MOJO_RESULT_RESOURCE_EXHAUSTED; |
| 287 } | 366 } |
| 288 | 367 |
| 289 if (validated_options.flags & | |
| 290 MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE) { | |
| 291 ScopedPlatformHandle server_handle, client_handle; | |
| 292 #if defined(OS_WIN) | |
| 293 internal::g_broker->CreatePlatformChannelPair(&server_handle, | |
| 294 &client_handle); | |
| 295 #else | |
| 296 PlatformChannelPair channel_pair; | |
| 297 server_handle = channel_pair.PassServerHandle(); | |
| 298 client_handle = channel_pair.PassClientHandle(); | |
| 299 #endif | |
| 300 dispatcher0->Init(std::move(server_handle), nullptr, 0u, nullptr, 0u, | |
| 301 nullptr, nullptr); | |
| 302 dispatcher1->Init(std::move(client_handle), nullptr, 0u, nullptr, 0u, | |
| 303 nullptr, nullptr); | |
| 304 } else { | |
| 305 uint64_t pipe_id = 0; | |
| 306 // route_id 0 is used internally in RoutedRawChannel. See kInternalRouteId | |
| 307 // in routed_raw_channel.cc. | |
| 308 // route_id 1 is used by broker communication. See kBrokerRouteId in | |
| 309 // broker_messages.h. | |
| 310 while (pipe_id < 2) | |
| 311 pipe_id = base::RandUint64(); | |
| 312 dispatcher0->InitNonTransferable(pipe_id); | |
| 313 dispatcher1->InitNonTransferable(pipe_id); | |
| 314 } | |
| 315 | |
| 316 *message_pipe_handle0 = handle_pair.first; | |
| 317 *message_pipe_handle1 = handle_pair.second; | |
| 318 return MOJO_RESULT_OK; | 368 return MOJO_RESULT_OK; |
| 319 } | 369 } |
| 320 | 370 |
| 321 // Implementation note: To properly cancel waiters and avoid other races, this | |
| 322 // does not transfer dispatchers from one handle to another, even when sending a | |
| 323 // message in-process. Instead, it must transfer the "contents" of the | |
| 324 // dispatcher to a new dispatcher, and then close the old dispatcher. If this | |
| 325 // isn't done, in the in-process case, calls on the old handle may complete | |
| 326 // after the the message has been received and a new handle created (and | |
| 327 // possibly even after calls have been made on the new handle). | |
| 328 MojoResult Core::WriteMessage(MojoHandle message_pipe_handle, | 371 MojoResult Core::WriteMessage(MojoHandle message_pipe_handle, |
| 329 const void* bytes, | 372 const void* bytes, |
| 330 uint32_t num_bytes, | 373 uint32_t num_bytes, |
| 331 const MojoHandle* handles, | 374 const MojoHandle* handles, |
| 332 uint32_t num_handles, | 375 uint32_t num_handles, |
| 333 MojoWriteMessageFlags flags) { | 376 MojoWriteMessageFlags flags) { |
| 334 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(message_pipe_handle)); | 377 auto dispatcher = GetDispatcher(message_pipe_handle); |
| 335 if (!dispatcher) | 378 if (!dispatcher) |
| 336 return MOJO_RESULT_INVALID_ARGUMENT; | 379 return MOJO_RESULT_INVALID_ARGUMENT; |
| 337 | 380 |
| 338 // Easy case: not sending any handles. | 381 if (num_handles == 0) // Fast path: no handles. |
| 339 if (num_handles == 0) | 382 return dispatcher->WriteMessage(bytes, num_bytes, nullptr, 0, flags); |
| 340 return dispatcher->WriteMessage(bytes, num_bytes, nullptr, flags); | |
| 341 | 383 |
| 342 // We have to handle |handles| here, since we have to mark them busy in the | 384 CHECK(handles); |
| 343 // global handle table. We can't delegate this to the dispatcher, since the | 385 |
| 344 // handle table lock must be acquired before the dispatcher lock. | 386 if (num_handles > kMaxHandlesPerMessage) |
| 345 // | |
| 346 // (This leads to an oddity: |handles|/|num_handles| are always verified for | |
| 347 // validity, even for dispatchers that don't support |WriteMessage()| and will | |
| 348 // simply return failure unconditionally. It also breaks the usual | |
| 349 // left-to-right verification order of arguments.) | |
| 350 if (num_handles > GetConfiguration().max_message_num_handles) | |
| 351 return MOJO_RESULT_RESOURCE_EXHAUSTED; | 387 return MOJO_RESULT_RESOURCE_EXHAUSTED; |
| 352 | 388 |
| 353 // We'll need to hold on to the dispatchers so that we can pass them on to | 389 for (size_t i = 0; i < num_handles; ++i) { |
| 354 // |WriteMessage()| and also so that we can unlock their locks afterwards | 390 if (message_pipe_handle == handles[i]) |
| 355 // without accessing the handle table. These can be dumb pointers, since their | 391 return MOJO_RESULT_BUSY; |
| 356 // entries in the handle table won't get removed (since they'll be marked as | |
| 357 // busy). | |
| 358 std::vector<DispatcherTransport> transports(num_handles); | |
| 359 | |
| 360 // When we pass handles, we have to try to take all their dispatchers' locks | |
| 361 // and mark the handles as busy. If the call succeeds, we then remove the | |
| 362 // handles from the handle table. | |
| 363 { | |
| 364 base::AutoLock locker(handle_table_lock_); | |
| 365 MojoResult result = handle_table_.MarkBusyAndStartTransport( | |
| 366 message_pipe_handle, handles, num_handles, &transports); | |
| 367 if (result != MOJO_RESULT_OK) | |
| 368 return result; | |
| 369 } | 392 } |
| 370 | 393 |
| 371 MojoResult rv = | 394 std::vector<Dispatcher::DispatcherInTransit> dispatchers; |
| 372 dispatcher->WriteMessage(bytes, num_bytes, &transports, flags); | 395 { |
| 396 base::AutoLock lock(handles_lock_); |
| 397 MojoResult rv = handles_.BeginTransit(handles, num_handles, &dispatchers); |
| 398 if (rv != MOJO_RESULT_OK) { |
| 399 handles_.CancelTransit(dispatchers); |
| 400 return rv; |
| 401 } |
| 402 } |
| 403 DCHECK_EQ(num_handles, dispatchers.size()); |
| 373 | 404 |
| 374 // We need to release the dispatcher locks before we take the handle table | 405 MojoResult rv = dispatcher->WriteMessage( |
| 375 // lock. | 406 bytes, num_bytes, dispatchers.data(), num_handles, flags); |
| 376 for (uint32_t i = 0; i < num_handles; i++) | |
| 377 transports[i].End(); | |
| 378 | 407 |
| 379 { | 408 { |
| 380 base::AutoLock locker(handle_table_lock_); | 409 base::AutoLock lock(handles_lock_); |
| 381 if (rv == MOJO_RESULT_OK) { | 410 if (rv == MOJO_RESULT_OK) { |
| 382 handle_table_.RemoveBusyHandles(handles, num_handles); | 411 handles_.CompleteTransitAndClose(dispatchers); |
| 383 } else { | 412 } else { |
| 384 handle_table_.RestoreBusyHandles(handles, num_handles); | 413 handles_.CancelTransit(dispatchers); |
| 385 } | 414 } |
| 386 } | 415 } |
| 387 | 416 |
| 388 return rv; | 417 return rv; |
| 389 } | 418 } |
| 390 | 419 |
| 391 MojoResult Core::ReadMessage(MojoHandle message_pipe_handle, | 420 MojoResult Core::ReadMessage(MojoHandle message_pipe_handle, |
| 392 void* bytes, | 421 void* bytes, |
| 393 uint32_t* num_bytes, | 422 uint32_t* num_bytes, |
| 394 MojoHandle* handles, | 423 MojoHandle* handles, |
| 395 uint32_t* num_handles, | 424 uint32_t* num_handles, |
| 396 MojoReadMessageFlags flags) { | 425 MojoReadMessageFlags flags) { |
| 397 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(message_pipe_handle)); | 426 CHECK((!num_handles || !*num_handles || handles) && |
| 427 (!num_bytes || !*num_bytes || bytes)); |
| 428 auto dispatcher = GetDispatcher(message_pipe_handle); |
| 398 if (!dispatcher) | 429 if (!dispatcher) |
| 399 return MOJO_RESULT_INVALID_ARGUMENT; | 430 return MOJO_RESULT_INVALID_ARGUMENT; |
| 400 | 431 return dispatcher->ReadMessage(bytes, num_bytes, handles, num_handles, flags); |
| 401 MojoResult rv; | |
| 402 uint32_t num_handles_value = num_handles ? *num_handles : 0; | |
| 403 if (num_handles_value == 0) { | |
| 404 // Easy case: won't receive any handles. | |
| 405 rv = dispatcher->ReadMessage(bytes, num_bytes, nullptr, &num_handles_value, | |
| 406 flags); | |
| 407 } else { | |
| 408 DispatcherVector dispatchers; | |
| 409 rv = dispatcher->ReadMessage(bytes, num_bytes, &dispatchers, | |
| 410 &num_handles_value, flags); | |
| 411 if (!dispatchers.empty()) { | |
| 412 DCHECK_EQ(rv, MOJO_RESULT_OK); | |
| 413 DCHECK(num_handles); | |
| 414 DCHECK_LE(dispatchers.size(), static_cast<size_t>(num_handles_value)); | |
| 415 | |
| 416 bool success; | |
| 417 { | |
| 418 base::AutoLock locker(handle_table_lock_); | |
| 419 success = handle_table_.AddDispatcherVector(dispatchers, handles); | |
| 420 } | |
| 421 if (!success) { | |
| 422 LOG(ERROR) << "Received message with " << dispatchers.size() | |
| 423 << " handles, but handle table full"; | |
| 424 // Close dispatchers (outside the lock). | |
| 425 for (size_t i = 0; i < dispatchers.size(); i++) { | |
| 426 if (dispatchers[i]) | |
| 427 dispatchers[i]->Close(); | |
| 428 } | |
| 429 if (rv == MOJO_RESULT_OK) | |
| 430 rv = MOJO_RESULT_RESOURCE_EXHAUSTED; | |
| 431 } | |
| 432 } | |
| 433 } | |
| 434 | |
| 435 if (num_handles) | |
| 436 *num_handles = num_handles_value; | |
| 437 return rv; | |
| 438 } | 432 } |
| 439 | 433 |
| 440 MojoResult Core::CreateDataPipe( | 434 MojoResult Core::CreateDataPipe( |
| 441 const MojoCreateDataPipeOptions* options, | 435 const MojoCreateDataPipeOptions* options, |
| 442 MojoHandle* data_pipe_producer_handle, | 436 MojoHandle* data_pipe_producer_handle, |
| 443 MojoHandle* data_pipe_consumer_handle) { | 437 MojoHandle* data_pipe_consumer_handle) { |
| 444 MojoCreateDataPipeOptions validated_options = {}; | 438 if (options && options->struct_size != sizeof(MojoCreateDataPipeOptions)) |
| 445 MojoResult result = | 439 return MOJO_RESULT_INVALID_ARGUMENT; |
| 446 DataPipe::ValidateCreateOptions(options, &validated_options); | |
| 447 if (result != MOJO_RESULT_OK) | |
| 448 return result; | |
| 449 | 440 |
| 450 scoped_refptr<DataPipeProducerDispatcher> producer_dispatcher = | 441 MojoCreateDataPipeOptions create_options; |
| 451 DataPipeProducerDispatcher::Create(validated_options); | 442 create_options.struct_size = sizeof(MojoCreateDataPipeOptions); |
| 452 scoped_refptr<DataPipeConsumerDispatcher> consumer_dispatcher = | 443 create_options.flags = options ? options->flags : 0; |
| 453 DataPipeConsumerDispatcher::Create(validated_options); | 444 create_options.element_num_bytes = options ? options->element_num_bytes : 1; |
| 445 // TODO: Use Configuration to get default data pipe capacity. |
| 446 create_options.capacity_num_bytes = |
| 447 options && options->capacity_num_bytes ? options->capacity_num_bytes |
| 448 : 64 * 1024; |
| 454 | 449 |
| 455 std::pair<MojoHandle, MojoHandle> handle_pair; | 450 // TODO: Broker through the parent when necessary. |
| 456 { | 451 scoped_refptr<PlatformSharedBuffer> ring_buffer = |
| 457 base::AutoLock locker(handle_table_lock_); | 452 GetNodeController()->CreateSharedBuffer( |
| 458 handle_pair = handle_table_.AddDispatcherPair(producer_dispatcher, | 453 create_options.capacity_num_bytes); |
| 459 consumer_dispatcher); | 454 if (!ring_buffer) |
| 460 } | 455 return MOJO_RESULT_RESOURCE_EXHAUSTED; |
| 461 if (handle_pair.first == MOJO_HANDLE_INVALID) { | 456 |
| 462 DCHECK_EQ(handle_pair.second, MOJO_HANDLE_INVALID); | 457 ports::PortRef port0, port1; |
| 463 LOG(ERROR) << "Handle table full"; | 458 GetNodeController()->node()->CreatePortPair(&port0, &port1); |
| 464 producer_dispatcher->Close(); | 459 |
| 465 consumer_dispatcher->Close(); | 460 CHECK(data_pipe_producer_handle); |
| 461 CHECK(data_pipe_consumer_handle); |
| 462 |
| 463 uint64_t pipe_id = base::RandUint64(); |
| 464 |
| 465 scoped_refptr<Dispatcher> producer = new DataPipeProducerDispatcher( |
| 466 GetNodeController(), port0, ring_buffer, create_options, |
| 467 true /* initialized */, pipe_id); |
| 468 scoped_refptr<Dispatcher> consumer = new DataPipeConsumerDispatcher( |
| 469 GetNodeController(), port1, ring_buffer, create_options, |
| 470 true /* initialized */, pipe_id); |
| 471 |
| 472 *data_pipe_producer_handle = AddDispatcher(producer); |
| 473 *data_pipe_consumer_handle = AddDispatcher(consumer); |
| 474 if (*data_pipe_producer_handle == MOJO_HANDLE_INVALID || |
| 475 *data_pipe_consumer_handle == MOJO_HANDLE_INVALID) { |
| 476 if (*data_pipe_producer_handle != MOJO_HANDLE_INVALID) { |
| 477 scoped_refptr<Dispatcher> unused; |
| 478 handles_.GetAndRemoveDispatcher(*data_pipe_producer_handle, &unused); |
| 479 } |
| 480 producer->Close(); |
| 481 consumer->Close(); |
| 466 return MOJO_RESULT_RESOURCE_EXHAUSTED; | 482 return MOJO_RESULT_RESOURCE_EXHAUSTED; |
| 467 } | 483 } |
| 468 DCHECK_NE(handle_pair.second, MOJO_HANDLE_INVALID); | |
| 469 | 484 |
| 470 ScopedPlatformHandle server_handle, client_handle; | |
| 471 #if defined(OS_WIN) | |
| 472 internal::g_broker->CreatePlatformChannelPair(&server_handle, &client_handle); | |
| 473 #else | |
| 474 PlatformChannelPair channel_pair; | |
| 475 server_handle = channel_pair.PassServerHandle(); | |
| 476 client_handle = channel_pair.PassClientHandle(); | |
| 477 #endif | |
| 478 producer_dispatcher->Init(std::move(server_handle), nullptr, 0u); | |
| 479 consumer_dispatcher->Init(std::move(client_handle), nullptr, 0u); | |
| 480 | |
| 481 *data_pipe_producer_handle = handle_pair.first; | |
| 482 *data_pipe_consumer_handle = handle_pair.second; | |
| 483 return MOJO_RESULT_OK; | 485 return MOJO_RESULT_OK; |
| 484 } | 486 } |
| 485 | 487 |
| 486 MojoResult Core::WriteData(MojoHandle data_pipe_producer_handle, | 488 MojoResult Core::WriteData(MojoHandle data_pipe_producer_handle, |
| 487 const void* elements, | 489 const void* elements, |
| 488 uint32_t* num_bytes, | 490 uint32_t* num_bytes, |
| 489 MojoWriteDataFlags flags) { | 491 MojoWriteDataFlags flags) { |
| 490 scoped_refptr<Dispatcher> dispatcher( | 492 scoped_refptr<Dispatcher> dispatcher( |
| 491 GetDispatcher(data_pipe_producer_handle)); | 493 GetDispatcher(data_pipe_producer_handle)); |
| 492 if (!dispatcher) | 494 if (!dispatcher) |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 555 const MojoCreateSharedBufferOptions* options, | 557 const MojoCreateSharedBufferOptions* options, |
| 556 uint64_t num_bytes, | 558 uint64_t num_bytes, |
| 557 MojoHandle* shared_buffer_handle) { | 559 MojoHandle* shared_buffer_handle) { |
| 558 MojoCreateSharedBufferOptions validated_options = {}; | 560 MojoCreateSharedBufferOptions validated_options = {}; |
| 559 MojoResult result = SharedBufferDispatcher::ValidateCreateOptions( | 561 MojoResult result = SharedBufferDispatcher::ValidateCreateOptions( |
| 560 options, &validated_options); | 562 options, &validated_options); |
| 561 if (result != MOJO_RESULT_OK) | 563 if (result != MOJO_RESULT_OK) |
| 562 return result; | 564 return result; |
| 563 | 565 |
| 564 scoped_refptr<SharedBufferDispatcher> dispatcher; | 566 scoped_refptr<SharedBufferDispatcher> dispatcher; |
| 565 result = SharedBufferDispatcher::Create(platform_support_, validated_options, | 567 result = SharedBufferDispatcher::Create( |
| 566 num_bytes, &dispatcher); | 568 internal::g_platform_support, validated_options, num_bytes, &dispatcher); |
| 567 if (result != MOJO_RESULT_OK) { | 569 if (result != MOJO_RESULT_OK) { |
| 568 DCHECK(!dispatcher); | 570 DCHECK(!dispatcher); |
| 569 return result; | 571 return result; |
| 570 } | 572 } |
| 571 | 573 |
| 572 *shared_buffer_handle = AddDispatcher(dispatcher); | 574 *shared_buffer_handle = AddDispatcher(dispatcher); |
| 573 if (*shared_buffer_handle == MOJO_HANDLE_INVALID) { | 575 if (*shared_buffer_handle == MOJO_HANDLE_INVALID) { |
| 574 LOG(ERROR) << "Handle table full"; | 576 LOG(ERROR) << "Handle table full"; |
| 575 dispatcher->Close(); | 577 dispatcher->Close(); |
| 576 return MOJO_RESULT_RESOURCE_EXHAUSTED; | 578 return MOJO_RESULT_RESOURCE_EXHAUSTED; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 625 result = mapping_table_.AddMapping(std::move(mapping)); | 627 result = mapping_table_.AddMapping(std::move(mapping)); |
| 626 } | 628 } |
| 627 if (result != MOJO_RESULT_OK) | 629 if (result != MOJO_RESULT_OK) |
| 628 return result; | 630 return result; |
| 629 | 631 |
| 630 *buffer = address; | 632 *buffer = address; |
| 631 return MOJO_RESULT_OK; | 633 return MOJO_RESULT_OK; |
| 632 } | 634 } |
| 633 | 635 |
| 634 MojoResult Core::UnmapBuffer(void* buffer) { | 636 MojoResult Core::UnmapBuffer(void* buffer) { |
| 635 base::AutoLock locker(mapping_table_lock_); | 637 base::AutoLock lock(mapping_table_lock_); |
| 636 return mapping_table_.RemoveMapping(buffer); | 638 return mapping_table_.RemoveMapping(buffer); |
| 637 } | 639 } |
| 638 | 640 |
| 639 // Note: We allow |handles| to repeat the same handle multiple times, since | 641 void Core::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) { |
| 640 // different flags may be specified. | 642 base::AutoLock lock(handles_lock_); |
| 641 // TODO(vtl): This incurs a performance cost in |Remove()|. Analyze this | 643 handles_.GetActiveHandlesForTest(handles); |
| 642 // more carefully and address it if necessary. | 644 } |
| 645 |
| 643 MojoResult Core::WaitManyInternal(const MojoHandle* handles, | 646 MojoResult Core::WaitManyInternal(const MojoHandle* handles, |
| 644 const MojoHandleSignals* signals, | 647 const MojoHandleSignals* signals, |
| 645 uint32_t num_handles, | 648 uint32_t num_handles, |
| 646 MojoDeadline deadline, | 649 MojoDeadline deadline, |
| 647 uint32_t* result_index, | 650 uint32_t *result_index, |
| 648 HandleSignalsState* signals_states) { | 651 HandleSignalsState* signals_states) { |
| 649 CHECK(handles); | 652 CHECK(handles); |
| 650 CHECK(signals); | 653 CHECK(signals); |
| 651 DCHECK_GT(num_handles, 0u); | 654 DCHECK_GT(num_handles, 0u); |
| 652 if (result_index) { | 655 if (result_index) { |
| 653 DCHECK_EQ(*result_index, static_cast<uint32_t>(-1)); | 656 DCHECK_EQ(*result_index, static_cast<uint32_t>(-1)); |
| 654 } | 657 } |
| 655 | 658 |
| 656 DispatcherVector dispatchers; | 659 DispatcherVector dispatchers; |
| 657 dispatchers.reserve(num_handles); | 660 dispatchers.reserve(num_handles); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 698 &waiter, signals_states ? &signals_states[i] : nullptr); | 701 &waiter, signals_states ? &signals_states[i] : nullptr); |
| 699 } | 702 } |
| 700 if (signals_states) { | 703 if (signals_states) { |
| 701 for (; i < num_handles; i++) | 704 for (; i < num_handles; i++) |
| 702 signals_states[i] = dispatchers[i]->GetHandleSignalsState(); | 705 signals_states[i] = dispatchers[i]->GetHandleSignalsState(); |
| 703 } | 706 } |
| 704 | 707 |
| 705 return rv; | 708 return rv; |
| 706 } | 709 } |
| 707 | 710 |
| 711 // static |
| 712 void Core::PassNodeControllerToIOThread( |
| 713 scoped_ptr<NodeController> node_controller) { |
| 714 // It's OK to leak this reference. At this point we know the IO loop is still |
| 715 // running, and we know the NodeController will observe its eventual |
| 716 // destruction. This tells the NodeController to delete itself when that |
| 717 // happens. |
| 718 node_controller.release()->DestroyOnIOThreadShutdown(); |
| 719 } |
| 720 |
| 708 } // namespace edk | 721 } // namespace edk |
| 709 } // namespace mojo | 722 } // namespace mojo |
| OLD | NEW |