OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "mojo/system/core_impl.h" |
| 6 |
| 7 #include <vector> |
| 8 |
| 9 #include "base/logging.h" |
| 10 #include "mojo/system/dispatcher.h" |
| 11 #include "mojo/system/limits.h" |
| 12 #include "mojo/system/memory.h" |
| 13 #include "mojo/system/message_pipe.h" |
| 14 #include "mojo/system/message_pipe_dispatcher.h" |
| 15 #include "mojo/system/waiter.h" |
| 16 |
| 17 namespace mojo { |
| 18 namespace system { |
| 19 |
| 20 // Implementation notes |
| 21 // |
| 22 // Mojo primitives are implemented by the singleton |CoreImpl| object. Most |
| 23 // calls are for a "primary" handle (the first argument). |
| 24 // |CoreImpl::GetDispatcher()| is used to look up a |Dispatcher| object for a |
| 25 // given handle. That object implements most primitives for that object. The |
| 26 // wait primitives are not attached to objects and are implemented by |CoreImpl| |
| 27 // itself. |
| 28 // |
| 29 // Some objects have multiple handles associated to them, e.g., message pipes |
| 30 // (which have two). In such a case, there is still a |Dispatcher| (e.g., |
| 31 // |MessagePipeDispatcher|) for each handle, with each handle having a strong |
| 32 // reference to the common "secondary" object (e.g., |MessagePipe|). This |
| 33 // secondary object does NOT have any references to the |Dispatcher|s (even if |
| 34 // it did, it wouldn't be able to do anything with them due to lock order |
| 35 // requirements -- see below). |
| 36 // |
| 37 // Waiting is implemented by having the thread that wants to wait call the |
| 38 // |Dispatcher|s for the handles that it wants to wait on with a |Waiter| |
| 39 // object; this |Waiter| object may be created on the stack of that thread or be |
| 40 // kept in thread local storage for that thread (TODO(vtl): future improvement). |
| 41 // The |Dispatcher| then adds the |Waiter| to a |WaiterList| that's either owned |
| 42 // by that |Dispatcher| (see |SimpleDispatcher|) or by a secondary object (e.g., |
| 43 // |MessagePipe|). To signal/wake a |Waiter|, the object in question -- either a |
| 44 // |SimpleDispatcher| or a secondary object -- talks to its |WaiterList|. |
| 45 |
| 46 // Thread-safety notes |
| 47 // |
| 48 // Mojo primitives calls are thread-safe. We achieve this with relatively |
| 49 // fine-grained locking. There is a global handle table lock. This lock should |
| 50 // be held as briefly as possible (TODO(vtl): a future improvement would be to |
| 51 // switch it to a reader-writer lock). Each |Dispatcher| object then has a lock |
| 52 // (which subclasses can use to protect their data). |
| 53 // |
| 54 // The lock ordering is as follows: |
| 55 // 1. global handle table lock |
| 56 // 2. |Dispatcher| locks |
| 57 // 3. secondary object locks |
| 58 // ... |
| 59 // INF. |Waiter| locks |
| 60 // |
| 61 // Notes: |
| 62 // - While holding a |Dispatcher| lock, you may not unconditionally attempt |
| 63 // to take another |Dispatcher| lock. (This has consequences on the |
| 64 // concurrency semantics of |MojoWriteMessage()| when passing handles.) |
| 65 // Doing so would lead to deadlock. |
| 66 // - Locks at the "INF" level may not have any locks taken while they are |
| 67 // held. |
| 68 |
| 69 // static |
| 70 CoreImpl* CoreImpl::singleton_ = NULL; |
| 71 |
| 72 // static |
| 73 void CoreImpl::Init() { |
| 74 CHECK(!singleton_); |
| 75 singleton_ = new CoreImpl(); |
| 76 } |
| 77 |
| 78 MojoResult CoreImpl::Close(MojoHandle handle) { |
| 79 if (handle == MOJO_HANDLE_INVALID) |
| 80 return MOJO_RESULT_INVALID_ARGUMENT; |
| 81 |
| 82 scoped_refptr<Dispatcher> dispatcher; |
| 83 { |
| 84 base::AutoLock locker(handle_table_lock_); |
| 85 HandleTableMap::iterator it = handle_table_.find(handle); |
| 86 if (it == handle_table_.end()) |
| 87 return MOJO_RESULT_INVALID_ARGUMENT; |
| 88 dispatcher = it->second; |
| 89 handle_table_.erase(it); |
| 90 } |
| 91 |
| 92 // The dispatcher doesn't have a say in being closed, but gets notified of it. |
| 93 // Note: This is done outside of |handle_table_lock_|. As a result, there's a |
| 94 // race condition that the dispatcher must handle; see the comment in |
| 95 // |Dispatcher| in dispatcher.h. |
| 96 return dispatcher->Close(); |
| 97 } |
| 98 |
| 99 MojoResult CoreImpl::Wait(MojoHandle handle, |
| 100 MojoWaitFlags flags, |
| 101 MojoDeadline deadline) { |
| 102 return WaitManyInternal(&handle, &flags, 1, deadline); |
| 103 } |
| 104 |
| 105 MojoResult CoreImpl::WaitMany(const MojoHandle* handles, |
| 106 const MojoWaitFlags* flags, |
| 107 uint32_t num_handles, |
| 108 MojoDeadline deadline) { |
| 109 if (!VerifyUserPointer(handles, num_handles, sizeof(handles[0]))) |
| 110 return MOJO_RESULT_INVALID_ARGUMENT; |
| 111 if (!VerifyUserPointer(flags, num_handles, sizeof(flags[0]))) |
| 112 return MOJO_RESULT_INVALID_ARGUMENT; |
| 113 if (num_handles < 1) |
| 114 return MOJO_RESULT_INVALID_ARGUMENT; |
| 115 if (num_handles > kMaxWaitManyNumHandles) |
| 116 return MOJO_RESULT_RESOURCE_EXHAUSTED; |
| 117 return WaitManyInternal(handles, flags, num_handles, deadline); |
| 118 } |
| 119 |
| 120 MojoResult CoreImpl::CreateMessagePipe(MojoHandle* handle_0, |
| 121 MojoHandle* handle_1) { |
| 122 scoped_refptr<MessagePipeDispatcher> dispatcher_0( |
| 123 new MessagePipeDispatcher()); |
| 124 scoped_refptr<MessagePipeDispatcher> dispatcher_1( |
| 125 new MessagePipeDispatcher()); |
| 126 |
| 127 MojoHandle h0, h1; |
| 128 { |
| 129 base::AutoLock locker(handle_table_lock_); |
| 130 |
| 131 h0 = AddDispatcherNoLock(dispatcher_0); |
| 132 if (h0 == MOJO_HANDLE_INVALID) |
| 133 return MOJO_RESULT_RESOURCE_EXHAUSTED; |
| 134 |
| 135 h1 = AddDispatcherNoLock(dispatcher_1); |
| 136 if (h1 == MOJO_HANDLE_INVALID) { |
| 137 handle_table_.erase(h0); |
| 138 return MOJO_RESULT_RESOURCE_EXHAUSTED; |
| 139 } |
| 140 } |
| 141 |
| 142 scoped_refptr<MessagePipe> message_pipe(new MessagePipe()); |
| 143 dispatcher_0->Init(message_pipe, 0); |
| 144 dispatcher_1->Init(message_pipe, 1); |
| 145 |
| 146 *handle_0 = h0; |
| 147 *handle_1 = h1; |
| 148 return MOJO_RESULT_OK; |
| 149 } |
| 150 |
| 151 MojoResult CoreImpl::WriteMessage( |
| 152 MojoHandle handle, |
| 153 const void* bytes, uint32_t num_bytes, |
| 154 const MojoHandle* handles, uint32_t num_handles, |
| 155 MojoWriteMessageFlags flags) { |
| 156 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(handle)); |
| 157 if (!dispatcher.get()) |
| 158 return MOJO_RESULT_INVALID_ARGUMENT; |
| 159 |
| 160 return dispatcher->WriteMessage(bytes, num_bytes, |
| 161 handles, num_handles, |
| 162 flags); |
| 163 } |
| 164 |
| 165 MojoResult CoreImpl::ReadMessage( |
| 166 MojoHandle handle, |
| 167 void* bytes, uint32_t* num_bytes, |
| 168 MojoHandle* handles, uint32_t* num_handles, |
| 169 MojoReadMessageFlags flags) { |
| 170 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(handle)); |
| 171 if (!dispatcher.get()) |
| 172 return MOJO_RESULT_INVALID_ARGUMENT; |
| 173 |
| 174 return dispatcher->ReadMessage(bytes, num_bytes, |
| 175 handles, num_handles, |
| 176 flags); |
| 177 } |
| 178 |
| 179 CoreImpl::CoreImpl() |
| 180 : next_handle_(MOJO_HANDLE_INVALID + 1) { |
| 181 } |
| 182 |
| 183 CoreImpl::~CoreImpl() { |
| 184 // This should usually not be reached (the singleton lives forever), except |
| 185 // in tests. |
| 186 } |
| 187 |
| 188 scoped_refptr<Dispatcher> CoreImpl::GetDispatcher(MojoHandle handle) { |
| 189 if (handle == MOJO_HANDLE_INVALID) |
| 190 return NULL; |
| 191 |
| 192 base::AutoLock locker(handle_table_lock_); |
| 193 HandleTableMap::iterator it = handle_table_.find(handle); |
| 194 if (it == handle_table_.end()) |
| 195 return NULL; |
| 196 |
| 197 return it->second; |
| 198 } |
| 199 |
| 200 MojoHandle CoreImpl::AddDispatcherNoLock(scoped_refptr<Dispatcher> dispatcher) { |
| 201 DCHECK(dispatcher.get()); |
| 202 handle_table_lock_.AssertAcquired(); |
| 203 DCHECK_NE(next_handle_, MOJO_HANDLE_INVALID); |
| 204 |
| 205 if (handle_table_.size() >= kMaxHandleTableSize) |
| 206 return MOJO_HANDLE_INVALID; |
| 207 |
| 208 // TODO(vtl): Maybe we want to do something different/smarter. (Or maybe try |
| 209 // assigning randomly?) |
| 210 while (handle_table_.find(next_handle_) != handle_table_.end()) { |
| 211 next_handle_++; |
| 212 if (next_handle_ == MOJO_HANDLE_INVALID) |
| 213 next_handle_++; |
| 214 } |
| 215 |
| 216 MojoHandle new_handle = next_handle_; |
| 217 handle_table_[new_handle] = dispatcher; |
| 218 |
| 219 next_handle_++; |
| 220 if (next_handle_ == MOJO_HANDLE_INVALID) |
| 221 next_handle_++; |
| 222 |
| 223 return new_handle; |
| 224 } |
| 225 |
| 226 // Note: We allow |handles| to repeat the same handle multiple times, since |
| 227 // different flags may be specified. |
| 228 // TODO(vtl): This incurs a performance cost in |RemoveWaiter()|. Analyze this |
| 229 // more carefully and address it if necessary. |
| 230 MojoResult CoreImpl::WaitManyInternal(const MojoHandle* handles, |
| 231 const MojoWaitFlags* flags, |
| 232 uint32_t num_handles, |
| 233 MojoDeadline deadline) { |
| 234 DCHECK_GT(num_handles, 0u); |
| 235 |
| 236 std::vector<scoped_refptr<Dispatcher> > dispatchers; |
| 237 dispatchers.reserve(num_handles); |
| 238 for (uint32_t i = 0; i < num_handles; i++) { |
| 239 scoped_refptr<Dispatcher> d = GetDispatcher(handles[i]); |
| 240 if (!d.get()) |
| 241 return MOJO_RESULT_INVALID_ARGUMENT; |
| 242 dispatchers.push_back(d); |
| 243 } |
| 244 |
| 245 // TODO(vtl): Should make the waiter live (permanently) in TLS. |
| 246 Waiter waiter; |
| 247 waiter.Init(); |
| 248 |
| 249 uint32_t i; |
| 250 MojoResult rv = MOJO_RESULT_OK; |
| 251 for (i = 0; i < num_handles; i++) { |
| 252 rv = dispatchers[i]->AddWaiter(&waiter, |
| 253 flags[i], |
| 254 static_cast<MojoResult>(i)); |
| 255 if (rv != MOJO_RESULT_OK) |
| 256 break; |
| 257 } |
| 258 uint32_t num_added = i; |
| 259 |
| 260 if (rv == MOJO_RESULT_ALREADY_EXISTS) |
| 261 rv = static_cast<MojoResult>(i); // The i-th one is already "triggered". |
| 262 else if (rv == MOJO_RESULT_OK) |
| 263 rv = waiter.Wait(deadline); |
| 264 |
| 265 // Make sure no other dispatchers try to wake |waiter| for the current |
| 266 // |Wait()|/|WaitMany()| call. (Only after doing this can |waiter| be |
| 267 // destroyed, but this would still be required if the waiter were in TLS.) |
| 268 for (i = 0; i < num_added; i++) |
| 269 dispatchers[i]->RemoveWaiter(&waiter); |
| 270 |
| 271 return rv; |
| 272 } |
| 273 |
| 274 } // namespace system |
| 275 } // namespace mojo |
OLD | NEW |