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

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

Issue 23621056: Initial in-process implementation of some Mojo primitives. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: wip18.1 Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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::mojo_system_singleton_ = NULL;
71
72 // static
73 void CoreImpl::Init() {
74 CHECK(!mojo_system_singleton_);
75 mojo_system_singleton_ = new CoreImpl();
76 }
77
78 MojoResult CoreImpl::Close(MojoHandle handle) {
79 if (handle == MOJO_HANDLE_INVALID)
80 return MOJO_RESULT_INVALID_ARGUMENT;
darin (slow to review) 2013/09/25 06:06:07 nit: consider a more specific error code of MOJO_R
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_OUT_OF_RANGE;
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)
darin (slow to review) 2013/09/25 06:06:07 it seems like there are some good test cases to wr
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 MojoResult CoreImpl::WaitManyInternal(const MojoHandle* handles,
227 const MojoWaitFlags* flags,
228 uint32_t num_handles,
229 MojoDeadline deadline) {
230 DCHECK_GT(num_handles, 0u);
231
232 std::vector<scoped_refptr<Dispatcher> > dispatchers;
233 dispatchers.reserve(num_handles);
234 for (uint32_t i = 0; i < num_handles; i++) {
235 scoped_refptr<Dispatcher> d = GetDispatcher(handles[i]);
236 if (!d.get())
237 return MOJO_RESULT_INVALID_ARGUMENT;
238 dispatchers.push_back(d);
239 }
240
241 // TODO(vtl): Should make the waiter live (permanently) in TLS.
242 Waiter waiter;
243 waiter.Init();
244
245 uint32_t i;
246 MojoResult rv = MOJO_RESULT_OK;
247 for (i = 0; i < num_handles; i++) {
248 rv = dispatchers[i]->AddWaiter(&waiter,
249 flags[i],
250 static_cast<MojoResult>(i));
251 if (rv != MOJO_RESULT_OK)
252 break;
253 }
254 uint32_t num_added = i;
255
256 if (rv == 1)
257 rv = static_cast<MojoResult>(i);
258 else if (rv == MOJO_RESULT_OK)
259 rv = waiter.Wait(deadline);
260
261 for (i = 0; i < num_added; i++)
262 dispatchers[i]->RemoveWaiter(&waiter);
263
264 return rv;
265 }
266
267 } // namespace system
268 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698